タグ:備忘録 ( 278 ) タグの人気記事

Delphi XE Pro - UnixTime を計算して経過時間を表示
Delphi XE Pro - Unixtime を 年月日 時分秒に変換

uses に DateUtils が必須です。
procedure TForm1.UnixtimeButton2Click(Sender: TObject);
var
UnixtimeStamp, StartTime, ElapsedTime : UInt64;

day, Hour, Minute, Second: Integer;
AdayOver : Integer; // 24 時間以上用

daystr : string;
TimeString : string;
begin
UnixtimeStamp := 1372995141;
TimeString := FormatDateTime('yyyy/mm/dd hh:mm:ss',UnixToDateTime(UnixtimeStamp));

ShowMessage(TimeString);


// 放送開始からの経過時間
StartTime := 1372485140;

ElapsedTime := UnixtimeStamp - StartTime; // 経過時間(秒数で格納)
ShowMessage(IntToStr(ElapsedTime) + '秒');

Hour := ElapsedTime div 60 div 60 ;

if Hour > 24 then
begin
day := Hour div 24;
AdayOver := Hour mod 24;
daystr := IntToStr(day) + '日目 ' + Format('%.2d',[AdayOver])+ '時間';
end
else
begin
daystr := IntToStr(Hour)+ '時間';
end;

Minute := ElapsedTime div 60 - Hour * 60 ;

Second := ElapsedTime - (Hour * 60 * 60 + Minute * 60) ;

TimeString := daystr + Format('%.2d',[Minute]) + '分' + Format('%.2d',[Second] ) + '秒';

ShowMessage(TimeString);

user_id_Memo.Text := TimeString;
end;


510001秒 が 
5日目 21時間40分01秒
と表示されます。
[PR]

by arigayas | 2013-06-30 00:29 | Delphi Programming | Trackback | Comments(5)
Delphi XE Pro - Unixtime を 年月日 時分秒に変換
uses に DateUtils が必須です。

procedure TForm1.UnixtimeButton2Click(Sender: TObject);
var
UnixtimeStamp : Int64;
// Temptime : TDateTime;
TimeString : string;
begin
UnixtimeStamp := 1372485141;
// Temptime := UnixToDateTime(UnixtimeStamp); Unixtime を TDateTime 型に変換してる。
TimeString := FormatDateTime('yyyy/mm/dd hh:mm:ss',UnixToDateTime(UnixtimeStamp));

ShowMessage(TimeString);
end;


以下のように表示される
2013/06/29 05:52:21

[PR]

by arigayas | 2013-06-29 15:00 | Delphi Programming | Trackback(1) | Comments(0)
Delphi XE Pro - TurboPower Abbrevia を使ってみるテスト
Delphi XE Pro - 今年の1月から作成していたソフト、XPI_Maker が完成した。

XPI_Maker に致命的なバグがあったので ZIP 形式の圧縮ファイルにする時のコンポーネントを
TurboPower Abbrevia 5.0 にしてみようと四苦八苦して心が折れたヽ(´ヮ`)/
コンポーネントのインストール方法をイマイチ理解していないの為かうまくインストールできないので強引にソースコードを追加したし(苦笑)

何も指定せずにフォルダの圧縮をするようにフォルダを投げると
出力される圧縮ファイルは絶対パスで圧縮されたファイルが作られる(´;ω;`)

英語サイトをググたりソースコードを追いかけて、恐らく「AbArcTyp.pas」の191~192行目にある
TAbStoreOption =
  (soStripDrive, soStripPath, soRemoveDots, soRecurse, soFreshen, soReplace);
の組み合わせを上手くすれば相対パスで圧縮されたファイルが作られると思うけど限界になったので休憩する。


休憩を終えて追記1回目:
使い方としては、
ほげほげ.StoreOptions := [soStripPath, soFreshen, soReplace];
などと指定する。
無指定だと、絶対パスを含むフォルダ構成で圧縮ファイルを作成するオプションのようだ。
soStripPath はフォルダ構成を無くして圧縮ファイルを作成するオプションのようだ。

追記2回目:
ドキュメントというかヘルプファイルを見つけた(苦笑)TurboPower Abbrevia 3.04 | SourceForge.net
soStripDrive
Drive letter information is removed from the stored file name.
(Note: This option is ignored in Linux.)

soStripPath
All path information is removed from the stored file name.

soRemoveDots
All relative path information is removed from the stored file name. For example,
if you call AddFiles with a FileMask of "..\TEST.TXT" ("../TEST.TXT" in Linux),
the parent of the current BaseDirectory is searched for a file named "TEST.TXT".
If the file is found, it is stored as "TEST.TXT".

soRecurse
Subdirectories of the search path are included in the search for files to add or freshen.

soFreshen
When adding an existing item to the archive, the item is freshened.

soReplace
When adding an existing item to the archive, the item is replaced.


2013年5月31日12時10分 追記3回目:
もしかして「TurboPower Abbrevia 」って相対パスでの圧縮ファイルにするのに対応していないのか?と思い始めてる。


2013年5月31日15時07分 追記4回目;
情報の後出しは良くないんですけど、deko さんのサイト[ 続・ZIP で圧縮 / 解凍したい (Delphi 2010 以降) ]を見てこのコンポーネントを使おうと思いました。
これを諦めて 7-zip.dll を使おうかと思い始めてます・・・。

2013年5月31日17時04分 追記5回目:
Twitter で おにさんに助言[ Twitter / onimaro2010 ... ]をいただいて「TurboPower Abbrevia 」を使って相対パスでの圧縮ファイルを作成するのに成功しました。
しかし、このコンポーネントは圧縮ファイルのファイル名の拡張子をチェックして圧縮ファイルにする処理を開始するから Firefox 等のアドオンで使われている xpi ファイルを指定すると「そんなファイルタイプを知らん!」と圧縮ファイルを作成してくれないので困った(´・ω・`)
SaveFileName := ChangeFileExt(SaveFileName, 'xpi');
とするだけじゃアプリケーションのメモリ内だけでファイル名の拡張子が変わるだけだけですし(´・ω・`)


2013年6月1日5時43分 追記6回目:
普通に「delphi ファイル名 変更」でググってファイル名の拡張子変更を解決したw
RenameFile(SaveFileName,ChangeFileExt(SaveFileName, 'xpi'));

upしている過去バージョンは使い物にならないから全部削除だな(´・ω・`)
[PR]

by arigayas | 2013-05-30 15:22 | Delphi Programming | Trackback | Comments(0)
Delphi XE Pro - 今年の1月から作成していたソフト、XPI_Maker が完成した。
2013年1月30日から作り始めたソフトXPI_Maker が昨日完成した。

作り始めたきっかけは、Mozilla Firefox のアドオンソフトで
2ちゃんねるを見る chaika の開発版を手軽に手元で作るためのソフトをGUIで作ってみたくなったからです。
chaika の開発者のF氏が忙しくなったのか新機能追加が全くなかったのだけど、
N氏が開発を引き継ぐことになってから猛烈に新機能追加されるようになったので最新バージョンが欲しくなったんです。
しかし、ただ最新バージョンを取得するだけならバッチファイル[ 7zip と Subversion を使って chaika チェックアウトして xpi を作るバッチファイル : arigayas の 雑記帳 ]を作れば充分なのです。

なぜ、バッチファイルじゃなく GUI で作ったのかというと chaika の不具合報告するのに
自分が今、どのリビジョンを使っているのか忘れてしまっても大丈夫なように
アドオンのインストール情報が書かれている install.rdf のバージョン情報を書き換えてしまおうと考えたからです。
バッチファイルでダウンロードした特定のファイルを編集するのは、たぶんかなり面倒臭いと思ったのもあります。
あとダウンロードして生成されるファイル名にもアドオン名とRevision番号があればわかりやすいと思ったのもあります。


ソフトの用件は
  1. ソフトが作成するファイル名には、アドオン名とRevision番号があること
  2. 圧縮ファイルを作成に自前で圧縮ファイルを作成すること
  3. 保存フォルダを選べること
  4. 特定のRevision を指定し取得して作成できること
  5. Subversion がインストール済みであること
  6. ボタンは なるべく少なくする
  7. 設定は記録されること

こんな感じで作り始めました。作り始めた初日には1ヶ月ぐらいで作り終わるかな?と思ってたけど、
プログラミング初心者の進捗は遅い&行き詰まったら心が折れやすいのもあって、
初日に思った4倍の時間が掛かってしまったw (一応、言い訳:プログラミングしてない日数は半分以上あります。)

b0003577_9232919.png


今後実装したい機能があって複数のアドオンに対応したいです。
現状だと複数のアドオンを設定するには、アドオン毎にフォルダを作成しないと設定ファイルを保存できない設計です。

使用例
b0003577_11523599.png


気が向いたら追記するかもしないし、全くしないかも知れない。

関連記事
[PR]

by arigayas | 2013-05-27 11:30 | Delphi Programming | Trackback(1) | Comments(0)
Delphi XE Pro - XML ファイルの値を変えてファイルに書き込む。
Delphi XE Pro - XMLファイルの値取得がわからない 【"略"を変更】

例えば以下のようなXMLファイルがあったとする。
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description>
<em:description>ソフト説明</em:description>
<em:name>テスト</em:name>
<em:version>0.0.1</em:version>
</Description>
</RDF>

これのノードの<em:version>0.0.1</em:version>の値を書き変えたい場合にどうするのかすぐにわからなかったのでメモ。
procedure TForm2.Button3ArrangeClick(Sender: TObject);
const
NamespaceURI: string = 'http://www.mozilla.org/2004/em-rdf#'; // 検索するノードの名前空間(xmlns:emの値)
NodeName: string ='name';
NodeVer : string ='version';
var
FileName : string;
XMLDocument1: IXMLDocument1;
XMLNode, XMLNodeVerData: IXMLNode;
MemoString, ReleaseVerData: string;

begin
Memo1.Text:='';
Memo2.Text:='';

if OpenDialog1.Execute then
begin
FileName := OpenDialog1.FileName;
Form2.Caption := FileName;

XMLDocument1 := LoadXMLDocument1(FileName);

for MemoString in XMLDocument1.XML Do // 読み込んだファイルを
Memo2.Lines.Add(MemoString); // 表示する

XMLNode := XMLDocument1.DocumentElement.ChildNodes[0].ChildNodes.FindNode(NodeName, NamespaceURI);
if XMLNode = nil then
begin
XMLNode := XMLDocument1.documentElement.ChildNodes.First.AttributeNodes['em:' + NodeName];
if not (XMLNode = nil) then
Memo1.Lines.Add(XMLNode.NodeValue)
else
begin
Memo1.Lines.Add('--Not Found--');
end;
end
else
begin
// version 探索
XMLNodeVerData := XMLDocument1.DocumentElement.ChildNodes[0].ChildNodes.FindNode(NodeVer, NamespaceURI);
ReleaseVerData := VarToStr(XMLNodeVerData.NodeValue);
ReleaseVerData := '0.1.0_Rev002';
XMLNodeVerData.NodeValue := ReleaseVerData;
// XMLDocument1.SaveToXML(ReleaseVerData); // 必要?
try // ファイルが他のソフトで開かれている場合のためにtryでの実行は必須
XMLDocument1.SaveToFile(FileName); // 更新実行
except on E: Exception do
MessageDlg('install.rdf に対するエラー:'+#13#10+ // 例外メッセージを表示
E.Message, mtError, [mbOK],0);
end;

Memo1.Lines.Add(XMLNode.NodeValue);
end;
end;
end;

SaveToXML と SaveToFile の違いがよくわからない(´・ω・`)

註1:
 本当は「Document1.」や「XMLDocument1.」の「1」は不要なのですが
 エキサイトブログのセキュリティの関係で投稿不可になるので「1」を付けて記事を投稿しました。
註2:
 公開用に編集するのが面倒なので使っているソースコードをそのままupしました。
[PR]

by arigayas | 2013-05-25 19:54 | Delphi Programming | Trackback | Comments(0)
サクラエディタ 2.0.8.0 で追加された フォントサイズ変更 マクロ機能
サクラエディタのマクロ - ダブルクリックした単語を自動検索


参照先→Sakura Editor / PatchUnicode / #398 フォントサイズの拡大or縮小
何かキーを押しながらマウスホイールの操作で表示しているテキストのフォントサイズを変更することは2013年5月現在、対応してない。
その代わりにショートカットキーでフォントサイズの変更するちょっと便利なマクロが追加されたので紹介する。

フォントサイズ拡大マクロ
SetFontSize(0, 1);
とだけ書いて fontsize_p1.mac というファイル名で保存する。

フォントサイズ縮小マクロ
SetFontSize(0, -1);
とだけ書いて fontsize_m1.mac というファイル名で保存する。

sakura.exe のあるフォルダの直下にmacroというフォルダをつくってそれぞれを保存する。
ただしWindows Vista 以降ではProgram Files には簡単に保存できなくなったので
%appdata%\sakura\macro
というフォルダに保存するのもアリかと。


フォントサイズ拡大マクロAlt+PgUp というショートカットキーに割り当てる例を説明する。
  1. 2つのファイルをフォルダに保存したら
  2. 設定 > 共通設定 > {マクロ} タブ を開く
  3. 「マクロ一覧」の[参照]ボタンを押してfontsize_p1.mac のあるフォルダを選択
  4. 「名前」に”フォントサイズ拡大”と記入
  5. 「File」にfontsize_p1.mac を選択して[設定]ボタンを押す
  6. キー割り当て}タブを開く
  7. 「種別」で"外部マクロ"を選択
  8. 「機能」の列に表示された”フォントサイズ拡大”を選択
  9. 「機能」の列 と 「キー」の列 の間にある”ALt”のチェックボックスにクリックしてチェックを入れる
  10. 「キー」の列の表示されてる”Alt+PgUp(RollUp)”を選択
  11. [割付]ボタンを押して[OK]ボタンを押して完了


ちなみにフォントサイズ縮小は Alt+PgDn を割り当てました。
[PR]

by arigayas | 2013-05-19 22:49 | Soft | Trackback | Comments(0)
[解決しました] Delphi XE Pro - 2つのボタンを procedureを使って一時的に無効にしたい。
2つのボタンを procedureを使って一時的に無効にしたいと思って作ってみたけど無効にならなくて何故だ?と思ったので記事にしてみた。
フォームにButtonを2つ置く。
b0003577_1231565.png

以下のようなコードを書いて、それぞれ1つ目のButtonOnOff(Sender);にブレイクポイントを置いて実行してみた。
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure ButtonOnOff(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
ButtonOnOff(Sender);
Form1.Caption := '1111111';
ButtonOnOff(Sender);
end;


procedure TForm1.Button2Click(Sender: TObject);
begin
ButtonOnOff(Sender);
Form1.Caption := '2222222';
ButtonOnOff(Sender);
end;

procedure TForm1.ButtonOnOff(Sender: TObject);
begin
if Button1.Enabled = True then
begin
Button1.Enabled := False;
Button2.Enabled := False;
end
else
begin
Button1.Enabled := True;
Button2.Enabled := True;
end;
end;

end.
しかし、Form1.Caption := の所に戻ってくると押したボタンだけが無効になっている。
そんで2回目の ButtonOnOff(Sender); で不可解な動きになるので
理由がわかる方はコメントかトラックバックをお願いします(≧_≦)

追記:「Button2.Enabled := False;」の次に ShowMessage(''); を書くと2つのボタンがちゃんと無効になる。

2013年5月17日追記 2013年5月23日にも追記
[PR]

by arigayas | 2013-05-16 12:43 | Delphi Programming | Trackback | Comments(0)
Delphi XE Pro - RadioGroup コンポーネントの仕様を把握していなかった。
YouTube に書いた説明文とほぼ同じです。

RadioGroup コンポーネントの仕様を把握していなかった為につまづいたので記録しました。

RadioGroup の選択項目をクリックすることによって 「Edit」 や「ボタン」を
有効(ボタンON)/無効(ボタンOFF)にするコードを書いたつもりでした。

しかし、RadioGroup の項目の横に「Edit」や「ボタン」を置いて
その間とかをクリックすると無効状態でも有効になってしまって
ボタンが動いてしまうバグ(**)というか仕様に遭遇したので
RadioGroup を使わない方式で作り直すことにした。[**]

(**):筆者が想定していた動きと違うという意味でバグかな。
[**]:このブログを書いた時点ではUIを変えることを決めただけです。
    おそらく GroupBox と RadioButton を使うことにします。



ちなみに動画のために作ったソフトとソースコードは削除済み。
動画作成に使ったソフト→AG-デスクトップレコーダー ダウンロードページ
[PR]

by arigayas | 2013-05-14 12:55 | Delphi Programming | Trackback | Comments(0)
Delphi XE Pro - ステータスバーの表示を数秒後に消すには?[3秒後にしました]
ステータスバーの表示を数秒後に消すには?
と任意の秒数後に表示を消したい的な質問して回答をいただました。

しかし処理した内容(途中経過)の表示に使おうとして実行したら例外が出るようになってしまって
どうしたらいいのかわからないので手に負えないのでソースから削除しました(´;ω;`)

でTwitterでDEKOさんの回答の参照先の筆者さんのLynaさんから以下のような助言をもらった。
「OnTimer内でTimer1.Enabled:=False;とした上で目的の処理を続けて書くと良いと思います。」
ので書き直してみた。

フォームに Timer を貼ってプロパティの Interval には 3秒 という意味の3000と入れてます。
b0003577_21221434.png
procedure TForm1.Timer1Timer(Sender: TObject);
begin
if not (StatusBar1.SimpleText ='') then
begin
Timer1.Enabled := false;
StatusBar1.SimpleText :='';
end;
end;
として試しにFormCreateする時に
StatusBar1.SimpleText :='テスト中'; 
と入れると起動後3秒後にステータスバーから「テスト中」という文字列は消えました。
しかしこれだとTimerが止まっているので他のところのボタンとかに
StatusBar1.SimpleText :='2回目のテスト'; 
と入れても消えてくれません。
消えるようにするにはTimerを動かすようにするために
StatusBar1.SimpleText :='2回目のテスト'; 
と書く前に
Timer1.Enabled := True;
を入れないといけません。

しかしいちいちいろんなところで
Timer1.Enabled := True;
StatusBar1.SimpleText :='hogehoge';
を書き込むのは面倒なので以下のようにまとめてみました。
procedure TForm1.StatusBarInfo(i: Integer);
begin
Timer1.Enabled := True;
case i of
0 : StatusBar1.SimpleText :=''; // Clear
1 : StatusBar1.SimpleText :='ファイルパスを確認しました';
2 : StatusBar1.SimpleText :='ファイルをダウンロードが完了しました';
3 : StatusBar1.SimpleText :='';
4 : StatusBar1.SimpleText :='';
5 : StatusBar1.SimpleText :='';
6 : StatusBar1.SimpleText :='';
7 : StatusBar1.SimpleText :='';
8 : StatusBar1.SimpleText :='';
9 : StatusBar1.SimpleText :='99999';
else
begin
ShowMessage('無設定ですよ');

StatusBarInfo(0);
end;
end;

end;

Timerを動かして文字列を書き込んでTForm1.Timer1TimerでTimerを止めた後にステータスバーから文字列を削除されるはず。
で他のところからは「StatusBarInfo(数字)」で呼びたいメッセージ番号を書くという感じにしてみました。
たぶんこのソース、まだ改良点があるんだろうなぁ・・・。

2013年4月30日追記その1: with do文を使ってみた。
procedure TForm1.StatusBarInfo(i: Integer);
begin
Timer1.Enabled := True;
with StatusBar1 do
begin
case i of
0 : SimpleText :=''; // Clear
1 : SimpleText :='ファイルパスを確認しました';
2 : SimpleText :='ファイルをダウンロードが完了しました';
3 : SimpleText :='';
4 : SimpleText :='';
5 : SimpleText :='';
6 : SimpleText :='';
7 : SimpleText :='';
8 : SimpleText :='';
9 : SimpleText :='99999';
10: SimpleText :='';
else
begin
ShowMessage('無設定');

StatusBarInfo(0);
end;
end;
end
end;
上記のようなwith do文を使っている中に
10:StatusBar1.SimpleText :='';
として潜り込ませてみも動いたのはちょっとビックリしたw

2013年4月30日追記その2:
button1をクリックして「StatusBarInfo(1) の文字列」と「StatusBarInfo(2) の文字列」を続けて表示したい場合に
処理;
StatusBarInfo(1);
処理;
処理;
StatusBarInfo(2);
処理;
と書くとStatusBarInfo(1);のタイマーが有効のままStatusBarInfo(2);が呼ばれるので実行時には一瞬変わったかも?と思うぐらいの時間しか「StatusBarInfo(2) の文字列」が表示されません。
ぼけーっと見ていたら「StatusBarInfo(2) の文字列」が表示されずに消えますw
この様にならない為に
処理;
StatusBarInfo(1);
処理;
処理;
Timer1.Enabled := False; // 一旦タイマーを止める意味で無効にする。
StatusBarInfo(2);
処理;
と書くと「StatusBarInfo(1) の文字列」と「StatusBarInfo(2) の文字列」がちゃんと表示される。
// 2013年4月30日追記終わり

以下は勘違いかもですが、
[PR]

by arigayas | 2013-04-27 21:18 | Delphi Programming | Trackback | Comments(0)
Delphi XE Pro - XMLファイルの値取得がわからない 【"略"を変更】
例えば以下のようなXMLファイルがあったとする。
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description>
<em:description>ソフト説明</em:description>
<em:name>テスト</em:name>
<em:version>0.0.1</em:version>
</Description>
</RDF>
追記:2013年4月18日21時13分xmlns:em のURI?を略さずに書くことにしました。


これの<em:name>テスト</em:name>の「テスト」という値(文字列)を取得方法がわからない。
しかも<em:name>の位置は不確定なので決め打ちが出来ないので困りもの。
試しに以下のようなDelphiのコードを書いた。
procedure TForm2.Button1Click(Sender: TObject);
var
DirPath: string;
document1: IXMLDocument;
Description1st: IXMLNode;
node: IXMLNode;
numString: int16;

begin
if OpenDialog1.Execute then
begin
DirPath := OpenDialog1.FileName;

Form2.Caption := DirPath;

document1 := LoadXMLDocument(DirPath);
Memo1.Lines.Add('+++++++++++');

node := document1.DocumentElement;
Memo1.Lines.Add(node.NodeName); // RDF

node := document1.DocumentElement.ChildNodes.First;
Memo1.Lines.Add(node.NodeName); // Description

node := document1.DocumentElement.ChildNodes.First.ChildNodes.First;
Memo1.Lines.Add(node.NodeName); // em:description

numString := document1.DocumentElement.ChildNodes.First.ChildNodes.Count;
Memo1.Lines.Add(IntToStr(numString)); // 4

numString := document1.DocumentElement.ChildNodes.First.ChildNodes.First.ChildNodes.Count;
Memo1.Lines.Add(IntToStr(numString)); // 1

node := document1.DocumentElement.ChildNodes.First.ChildNodes.First.ChildNodes.First;
Memo1.Lines.Add(node.NodeName); // #text
Memo1.Lines.Add(node.Text); // ソフト説明

node := document1.DocumentElement.ChildNodes.First.ChildNodes.First.ChildNodes['name'];
Memo1.Lines.Add(node.NodeName); // em:name
Memo1.Lines.Add(node.Text); // null

node := document1.DocumentElement.ChildNodes[0].ChildNodes.First.ChildNodes['em:name'].ChildNodes.First;
Memo1.Lines.Add(node.NodeName); // #text
Memo1.Lines.Add(node.Text); // null
Memo1.Lines.Add(BoolToStr(node.HasChildNodes)); // 0 って


Memo1.Lines.Add('+++++++++++');
end;

end;

end.

node := document1.DocumentElement.ChildNodes[0].ChildNodes.First.ChildNodes['em:name'].ChildNodes.First.Textがnullになるのは何故?

まぁXMLをわかっていないのがバレバレですけどね(苦笑)

山本隆 さんの回答を元にアレンジしてみました。
[PR]

by arigayas | 2013-04-18 01:19 | Delphi Programming | Trackback(1) | Comments(4)