Whois - Felix John COLIBRI. | - abstract : a Web utility enabling batch Whois requests
- key words : TCP IP, Whois, reverse DNS, socket programming, Whois Server
- software used : Windows XP, Delphi 6
- hardware used : Pentium 1.400Mhz, 256 M memory, 140 G hard disc
- scope : Delphi 1 to 8 for Windows, Kylix
- level : Delphi developer
- plan :
1 - Introduction
Each morning we process our Web Server logs, to check whether some mistakes were found (dead links, wrong zip names etc). We also accumulate some statistics, look at the way visitors jump from page to page, and perform a
quick URL analysis: who are the people visiting our site. The IIS logs include the IP of the visitors, and this allows to get the domain name of the visitor (reverse DNS) and IP owner (Whois).
Before getting into the detail of the Whois project, let us stress that this enquiry is in no way a "big brother" kind of eavesdropping. Many individual visitors use ISP's (Internet Service Providers) who own bundles of IP's,
and the reverse DNS as well as the Whois request only yields the ISP and not the true final visitor. And if users connect by using a corporate Server with a dedicated IP, we only get back the corporation, and not the individual who is
visiting us. Nevertheless, knowing that persons from Chevron or Texas Instruments came by rather than NBC or Macy's is still interesting.
2 - Principle of Whois Resquests
When you buy a domain, you have to register this purchase with some companies. There is a record of this purchase in a database, and this record can be read by doing a Whois TCP/IP request.
There are many companies who register the domains. Each of them maintains a Whois Server, which can be interrogated by a Whois request. I'm not sure how many of those companies are around, by for our site, we found
that 5 Whois Servers covered all the IPs we had to handle. They are: - whois.arin.net for North America
- whois.apnic.net for the Asia Pacific area
- whois.lacnic.net for Latin America
- whois.ripe.net for Europe
- whois.afrinic.net for Africa
In order to get the information concerning a visitor: - we establish a connection with the Whois Server
- we sent the visitor IP
- the Server sends back a text page with
- either the information about this IP
- or some kind of message trying to tell us what other Whois Server should be used
Let us take a first example: - a visitor from 192.193.221.153 looked at our site
- using the whois.arin.net Server, we asked who was 192.193.221.153
- the answer came back:
OrgName: Citicorp Global Information Network
OrgID: CGIN
Address: 388 Greenwich
City: New York
StateProv: NY
PostalCode: 10013
Country: US
NetRange: 192.193.0.0 - 192.193.255.255
CIDR: 192.193.0.0/16
NetName: CITICORP-C
NetHandle: NET-192-193-0-0-1
Parent: NET-192-0-0-0-0
NetType: Direct Assignment
NameServer: NS1.NSROOT1.COM
NameServer: NS2.NSROOT2.COM
Comment:
RegDate: 1992-07-06
Updated: 2003-08-14
TechHandle: KM9-ARIN
TechName: McKenna, Ken
TechPhone: +1-718-248-3866
TechEmail: hostmaster@cto.citicorp.com
OrgAbuseHandle: CCC9-ARIN
OrgAbuseName: CTAC Command Center
OrgAbusePhone: +1-212-723-4480
OrgAbuseEmail: ctaccmdcenter@citigroup.com
OrgTechHandle: PATRI6-ARIN
OrgTechName: Morris, Patrick A.
OrgTechPhone: +1-212-816-1780
OrgTechEmail: patrick.a.morris@citigroup.com
# ARIN WHOIS database, last updated 2005-05-23 19:10
# Enter ? for additional hints on searching ARIN's WHOIS database.
|
2.1 - The Whois Server information The answer of each Whois Server is not normalized. Each Server has its own
answer format. In addition, there is no way to tell which Whois Server should be interrogated: there is no central table which establish this IP - Whois Server correspondance.
It seems that the best we can do is to select a Whois Server at random, read the answer, and if this answer tells us to look at some other Whois Server, to try our luck there.
We therefore must look at some answers, and try to establish some patterns in order to tell whether the correct Whois Server was reached, and if not, how to find in the answer the next candidate.
So let us quickly present the format of our 5 main Whois Servers:
2.2 - ARIN (Northern Americas and southern Africa) Here is an example with 146.27.122.17:
OrgName: Chevron Corporation
OrgID: CHEVRO
Address: 6001 Bollinger Canyon Road
City: San Ramon
StateProv: CA
PostalCode: 94583-2324
Country: US
NetRange: 146.22.0.0 - 146.46.255.255
CIDR: 146.22.0.0/15, 146.24.0.0/13, 146.32.0.0/13,
146.40.0.0/14, 146.44.0.0/15, 146.46.0.0/16
NetName: CHEVRON
NetHandle: NET-146-22-0-0-1
Parent: NET-146-0-0-0-0
NetType: Direct Assignment
NameServer: BOCFG3.CHEVRONTEXACO.COM
NameServer: BOCFG4.CHEVRONTEXACO.COM
NameServer: CHVPKFG1.CHEVRONTEXACO.COM
NameServer: CHVPKFG2.CHEVRONTEXACO.COM
Comment:
RegDate: 1991-01-18
Updated: 2003-04-07
TechHandle: BB1786-ARIN
TechName: Beach, Bob
TechPhone: +1-925-842-3626
TechEmail: hostmaster@chevrontexaco.com
OrgTechHandle: BB1786-ARIN
OrgTechName: Beach, Bob
OrgTechPhone: +1-925-842-3626
OrgTechEmail: hostmaster@chevrontexaco.com
# ARIN WHOIS database, last updated 2005-05-23 19:10
# Enter ? for additional hints on searching ARIN's WHOIS database.
| (we have inserted a newline in the CIDR line)
2.3 - APNIC (Asia Pacific) Here is the result for 211.123.199.142:
% [whois.apnic.net node-1]
% Whois data copyright terms http://www.apnic.net/db/dbcopyright.html
inetnum: 211.120.0.0 - 211.135.255.255
netname: JPNIC-NET-JP
descr: Japan Network Information Center
country: JP
admin-c: JNIC1-AP
tech-c: JNIC1-AP
rev-srv: ns0.nic.ad.jp
rev-srv: ns.wide.ad.jp
rev-srv: ns0.iij.ad.jp
rev-srv: dns0.spin.ad.jp
rev-srv: ns-jp.sinet.ad.jp
rev-srv: ns-jp.ntt.net
remarks: JPNIC Allocation Block
remarks: Authoritative information regarding assignments and
remarks: allocations made from within this block can also be
remarks: queried at whois.nic.ad.jp. To obtain an English
remarks: output query whois -h whois.nic.ad.jp x.x.x.x/e
mnt-by: APNIC-HM
mnt-lower: MAINT-JPNIC
changed: hostmaster@apnic.net 20000427
status: ALLOCATED PORTABLE
source: APNIC
role: Japan Network Information Center
address: Kokusai-Kougyou-Kanda Bldg 6F, 2-3-4 Uchi-Kanda
address: Chiyoda-ku, Tokyo 101-0047, Japan
country: JP
phone: +81-3-5297-2311
fax-no: +81-3-5297-2312
e-mail: hostmaster@nic.ad.jp
admin-c: SS13-AP
tech-c: SY7-AP
nic-hdl: JNIC1-AP
mnt-by: MAINT-JPNIC
changed: hm-changed@apnic.net 20041222
changed: hm-changed@apnic.net 20050324
source: APNIC
inetnum: 211.123.199.128 - 211.123.199.191
netname: FUJIFILM-NW
descr: FUJI PHOTO FILM CO.,LTD.
country: JP
admin-c: NH1104JP
tech-c: NH1104JP
remarks: This information has been partially mirrored by APNIC from
remarks: JPNIC. To obtain more specific information, please use the
remarks: JPNIC WHOIS Gateway at
remarks: http://www.nic.ad.jp/en/db/whois/en-gateway.html or
remarks: whois.nic.ad.jp for WHOIS client. (The WHOIS client
remarks: defaults to Japanese output, use the /e switch for for
remarks: English output)
changed: apnic-ftp@nic.ad.jp 20001117
source: JPNIC
|
2.4 - LACNIC (Latin America and the Carribean) The information for 170.66.1.123 is:
% Copyright LACNIC lacnic.net
% The data below is provided for information purposes
% and to assist persons in obtaining information about or
% related to AS and IP numbers registrations
% By submitting a whois query, you agree to use this data
% only for lawful purposes.
% 2005-05-24 05:57:28 (BRT -03:00)
inetnum: 170.66/16
status: assigned
owner: Banco do Brasil S.A.
ownerid: BR-BBSA-LACNIC
responsible: Edi Domingues
address: STN 716 bloco C Brazil, 000,
address: 70770-100 - Brasília - DF
country: BR
phone: +55 61 3106303 []
owner-c: EDD
tech-c: EDD
inetrev: 170.66/16
nserver: DNS1.BANCOBRASIL.COM.BR
nsstat: 20050519 AA
nslastaa: 20050519
nserver: DNS2.BANCOBRASIL.COM.BR
nsstat: 20050519 AA
nslastaa: 20050519
created: 19940224
changed: 20030915
nic-hdl: EDD
person: EDI DOMINGUES
e-mail: edi@BB.COM.BR
address: STN 716 BLOCO C, 00,
address: 70770100 - Brailia - df
country: BR
phone: +55 61 3106303 []
created: 20030110
changed: 20030110
% whois.lacnic.net accepts only direct match queries.
% Types of queries are: POCs, ownerid, CIDR blocks, IP
% and AS numbers.
|
2.5 - RIPE (Europe) Here is 81.255.154.129:
% This is the RIPE Whois query server #1.
% The objects are in RPSL format.
%
% Note: the default output of the RIPE Whois server
% is changed. Your tools may need to be adjusted. See
% http://www.ripe.net/db/news/abuse-proposal-20050331.html
% for more details.
%
% Rights restricted by copyright.
% See http://www.ripe.net/db/copyright.html
% Information related to '81.255.154.0 - 81.255.154.255'
inetnum: 81.255.154.0 - 81.255.154.255
netname: FR-L-OREAL-CO-GLOBAL-SWITCH
descr: L OREAL CO GLOBAL SWITCH
country: FR
admin-c: PB630-RIPE
tech-c: PVI3-RIPE
status: ASSIGNED PA
mnt-by: RAIN-TRANSPAC
source: RIPE # Filtered
person: Pascal BUGNOT
address: L OREAL CO GLOBAL SWITCH
address: 3 rue du 8 Mai 1945
address: 92586 CLICHY
phone: +33147567272
fax-no: +33147568181
e-mail: fbugnot@dgaf.loreal.com
nic-hdl: PB630-RIPE
mnt-by: RAIN-TRANSPAC
source: RIPE # Filtered
person: Pascal Vitte
address: L'Oreal - DGAF/DOM/TI
address: 62 rue d'Alsace
address: 92583 Clichy CEDEX
address: France
phone: +33 1 47 56 46 33
fax-no: +33 1 47 56 05 57
e-mail: pvitte@dgaf.loreal.com
nic-hdl: PVI3-RIPE
mnt-by: RAIN-TRANSPAC
source: RIPE # Filtered
% Information related to '81.255.154.0/24AS31629'
route: 81.255.154.0/24
descr: L'OREAL - RAIN Customer
descr: L'OREAL
origin: AS31629
mnt-by: RAIN-TRANSPAC
source: RIPE # Filtered
|
2.6 - AFRINIC (Africa)
% This is the AfriNIC Whois server.BR>
inetnum: 193.95.53.0 - 193.95.53.255
netname: G-NET53
descr: SSS GlobalNet ISP, P.O.P net 53
country: TN
admin-c: PA1317-AFRINIC
tech-c: ER149-AFRINIC
status: ASSIGNED PA
mnt-by: ATI-MNT
mnt-lower: ATI-MNT
changed: saadaoui@ati.tn 20010401
changed: tn.ati@ati.tn 20020214
changed: tn.ati@ati.tn 20020923
changed: hostmaster@afrinic.net 20050205
remarks: data has been transferred from RIPE Whois Database 20050221
source: AFRINIC
person: PDG ATI
address: ATI
address: 13 rue Jugurtha Mutuelle-ville
address: 1002 Tunis - Tunisia
phone: +216 71 846 100
fax-no: +216 71 846 600
e-mail: pdg@ati.tn
nic-hdl: PA1317-AFRINIC
mnt-by: ATI-MNT
changed: tn.ati@ati.tn 20020212
changed: lir@ati.tn 20040119
changed: hostmaster@afrinic.net 20050205
remarks: data has been transferred from RIPE Whois Database 20050221
source: AFRINIC
person: Equipe Reseaux
address: ATI
address: 13 rue Jugurtha Mutuelle-ville
address: 1002 Tunis - Tunisia
phone: +216 71 846 100
fax-no: +216 71 846 600
e-mail: equipe-reseaux@ati.tn
nic-hdl: er149-AFRINIC
mnt-by: ATI-MNT
changed: tn.ati@ati.tn 20020212
changed: lir@ati.tn 20040119
changed: hostmaster@afrinic.net 20050205
remarks: data has been transferred from RIPE Whois Database 20050221
source: AFRINIC
| 2.7 - Recovering from wrong Server requests If we interrogate the wrong Server, the answer usually tells us where we should look at instead.
Let's assume that we want to investigate 13. 16.137.10 (Xerox Palo Alto Research Center). APNIC is quite clear:
% [whois.apnic.net node-2]
% Whois data copyright terms http://www.apnic.net/db/dbcopyright.html
inetnum: 13.0.0.0 - 13.255.255.255
netname: IANA-NETBLOCK-13
descr: This network range is not allocated to APNIC.
descr:
descr: If your whois search has returned this message, then you have
descr: searched the APNIC whois database for an address that is
descr: allocated by another Regional Internet Registry (RIR).
descr:
descr: Please search the other RIRs at whois.arin.net or whois.ripe.net
descr: for more information about that range.
country: AU
admin-c: IANA1-AP
tech-c: IANA1-AP
remarks: For general info on spam complaints email spam@apnic.net.
remarks: For general info on hacking & abuse complaints email
abuse@apnic.net.
mnt-by: MAINT-APNIC-AP
mnt-lower: MAINT-APNIC-AP
changed: hm-changed@apnic.net 20020530
changed: hm-changed@apnic.net 20040926
status: ALLOCATED PORTABLE
source: APNIC
role: Internet Assigned Numbers Authority
address: see http://www.iana.org.
e-mail: nobody@apnic.net
admin-c: IANA1-AP
tech-c: IANA1-AP
nic-hdl: IANA1-AP
remarks: For more information on IANA services
remarks: go to IANA web site at http://www.iana.org.
mnt-by: MAINT-APNIC-AP
changed: nobody@apnic.net 20020530
source: APNIC
| RIPE or AFRINIC have similar answers. But LATNIC is less detailed (but ARIN is still somewhere in the text):
% Copyright LACNIC lacnic.net
% The data below is provided for information purposes
% and to assist persons in obtaining information about or
% related to AS and IP numbers registrations
% By submitting a whois query, you agree to use this data
% only for lawful purposes.
% 2005-05-24 06:13:54 (BRT -03:00)
% Not assigned to LACNIC 13.16.137.10
% Please use the whois server at whois.arin.net
% whois.lacnic.net accepts only direct match queries.
% Types of queries are: POCs, ownerid, CIDR blocks, IP
% and AS numbers.
| 2.8 - Partial answers For some URLs, ARIN sends a short answer. For instance with 199-72-58-100:
USLEC Corp. TXFER-INT-USLEC-BLK-1 (NET-199-72-0-0-1)
199.72.0.0 - 199.72.255.255
USLEC Corp. TXFER-INT-USLEC-BLK-1 (NET-199-72-0-0-1)
199.72.0.0 - 199.72.255.255
Witt Biomedical WITT-BIOMEDICAL (NET-199-72-58-96-1)
199.72.58.96 - 199.72.58.111
# ARIN WHOIS database, last updated 2005-05-22 19:10
# Enter ? for additional hints on searching ARIN's WHOIS database.
| A second request with NET-199-72-58-96-1 then yields:
CustName: Witt Biomedical
Address: 305 North Drive
City: Melbourne
StateProv: FL
PostalCode: 32934
Country: US
RegDate: 2003-05-29
Updated: 2003-05-29
NetRange: 199.72.58.96 - 199.72.58.111
CIDR: 199.72.58.96/28
NetName: WITT-BIOMEDICAL
NetHandle: NET-199-72-58-96-1
Parent: NET-199-72-0-0-1
NetType: Reassigned
Comment:
RegDate: 2003-05-29
Updated: 2003-05-29
OrgAbuseHandle: ABUSE34-ARIN
OrgAbuseName: Abuse
OrgAbusePhone: +1-704-319-1248
OrgAbuseEmail: abuse@uslec.com
OrgNOCHandle: NOC136-ARIN
OrgNOCName: Network Operations Center
OrgNOCPhone: +1-800-978-7532
OrgNOCEmail: noc@uslec.com
OrgTechHandle: RUSSE-ARIN
OrgTechName: Russell, Fred
OrgTechPhone: +1-704-319-1333
OrgTechEmail: frussell@uslec.com
# ARIN WHOIS database, last updated 2005-05-23 19:10
# Enter ? for additional hints on searching ARIN's WHOIS database.
| 3 - The Delphi Source code 3.1 - Organization We are going to use - a visitor list, with the IP, the domain, if any, and the name of the file
name containing the information received from the Whois Server
- a Whois Server list containing their domain name and their IP.
- a whois searcher which will interrogate each Whois Server until a correct information text is found
3.2 - The visitor list This is a list enabling to load the IP list, and save the result of our
enquires.
3.3 - The Whois Server list The list is the usual tStringList encapsulation. The domain of each Whois Server is knowns (whois.arin.net) but not their IP
(??). So we first perform a lookup to fill the IP addresses. This could be done using a blocking HostLookup, but since our c_client_socket can perform asynchronous lookups, we will use this possibility. The client socket used for
the lookup is placed in the c_whois_server_list, which enables to delegate the OnAfterLookup event in order to start the next lookup after the end of the current one. In order to reiterate the information requests, we can mark each
c_whois_server to avoid circular errors (it did not happen, but who knows). In addition, some servers can be unavailable (maintenance or whatever) so we also manage an availability boolean for each c_whois_server.
Here is the c_whois_server definition:
c_whois_server= // one "whois_server" Class(c_basic_object)
// -- m_name: the domain ("whois.arin.net")
m_ip: String; // 69.25.34.144
m_key: String; // us
m_unavailable: Boolean;
m_used: Boolean;
Constructor create_whois_server(p_name: String);
function f_display_whois_server: String;
end; // c_whois_server |
and the c_whois_server_list:
c_whois_server_list= // "whois_server" list
Class(c_basic_object)
m_c_whois_server_list: tStringList;
// -- running search index
m_find_ip_index: Integer; m_on_after_create_whois_socket,
m_on_after_lookup_whois_socket,
m_on_after_changed_whois_server: t_on_after_whois_event;
m_c_current_whois_server: c_whois_server;
Constructor create_whois_server_list(p_name: String);
// -- manage the list
function f_whois_server_count: Integer;
function f_c_whois_server(p_whois_server_index: Integer): c_whois_server;
function f_index_of(p_whois_server_name: String): Integer;
function f_c_find_by_whois_server_by_name(p_whois_server_name: String): c_whois_server;
procedure add_whois_server(p_whois_server_name: String; p_c_whois_server: c_whois_server);
function f_c_add_whois_server(p_whois_server_name: String): c_whois_server;
function f_c_add_unique_whois_server(p_whois_server_name: String): c_whois_server;
procedure display_whois_server_list;
// -- ip lookup
procedure lookup_whois_server(p_whois_server_name: String);
procedure handle_after_socket_error(p_c_base_socket: c_base_socket);
procedure handle_after_socket_host_lookup(p_c_client_socket: c_client_socket);
procedure search_next_server_ip;
procedure find_server_ips;
// -- swith servers
function f_c_find_whois_server_by_key(p_key: String): c_whois_server;
procedure set_current_whois_server(p_key: String);
procedure current_whois_server_timed_out;
function f_get_next_server: Boolean;
procedure reset_whois_servers;
// -- load server urls
procedure load_whois_servers(p_full_file_name: String);
procedure load_keys(p_full_file_name: String);
Destructor Destroy; Override;
end; // c_whois_server_list | and - the list contains the usual methods for list management (like
add_whois_server)
- we also placed in this class the IP lookup functions, since this is the class where we will fetch the next domain name when we finished the lookup of the previous one
- once all IPs have been found, we will start fetching the information for each domain. For any domain, we start with a (random) m_c_current_whois_server, and if the returned information tells us to look
elsewhere, we change the current Whois Server. This Whois Server switching is controlled by the last group of methods
3.4 - The search class
The c_whois_searcher performs the request, and changes the Whois Server based on the answer. Here is the definition:
c_whois_searcher= class(c_basic_object)
m_c_whois_server_list_ref: c_whois_server_list;
m_search_ip: String;
m_c_result_string_list: tStringList;
m_result_path, m_result_file_name: String;
m_on_start_whois_search: t_on_whois_search_event;
m_on_after_whois_search_connect: t_on_whois_search_event;
m_on_after_whois_search_reception: t_on_whois_search_event;
m_on_after_whois_search_server_closed: t_on_whois_search_event;
Constructor create_whois_searcher(p_name: String;
p_c_traffic_log_ref: c_log;
p_c_whois_server_list_ref: c_whois_server_list);
function f_whois_server_key: String;
procedure search(p_search_ip: String);
procedure handle_whois_searcher_socket_error(p_c_whois_socket: c_whois_client_socket);
procedure handle_after_whois_searcher_connect(p_c_whois_socket: c_whois_client_socket);
procedure handle_after_whois_searcher_reception(p_c_whois_socket: c_whois_client_socket);
procedure handle_after_whois_searcher_server_closed(p_c_whois_socket: c_whois_client_socket);
Destructor Destroy; Override;
end; // c_whois_searcher | Here is the switching mechanism:
procedure test_server_switch;
procedure search_another(p_save_name, p_log, p_new_key: String);
begin
m_c_whois_server_list_ref.set_current_whois_server(p_new_key);
// -- check that the recognized server has not timed out
if m_c_whois_server_list_ref.m_c_current_whois_server.m_unavailable
then begin
// -- start with another server
if not m_c_whois_server_list_ref.f_get_next_server
then begin
display('*** *** no_other_available_server');
end;
// -- not this is a recursive call
if Assigned(m_on_after_whois_search_server_closed)
then m_on_after_whois_search_server_closed(Self);
end
else // recurse with this new server
search(m_search_ip);
end; // search_another begin // test_server_switch
if (f_whois_server_key= 'us')
and (Pos('Allocated to RIPE', m_c_result_string_list.Text)> 0)
then search_another('_to_europe.txt', 'us -> europe', 'europe') else
if (Pos('see http://www.iana.org', m_c_result_string_list.Text)> 0)
or (Pos('Not assigned to LACNIC', m_c_result_string_list.Text)> 0)
then search_another('_to_us.txt', 'europe -> us', 'us') else
if (f_whois_server_key= 'us')
and (Pos('LACNIC-ARIN', m_c_result_string_list.Text)> 0)
then search_another('_to_latin.txt', 'us -> latin', 'latin') else
if (f_whois_server_key= 'us')
and (Pos('Allocated to APNIC', m_c_result_string_list.Text)> 0)
then search_another('_to_asia.txt', 'us -> asia', 'asia') else
if (Pos('see http://www.afrinic.net', m_c_result_string_list.Text)> 0)
then search_another('_to_africa.txt', ' -> africa', 'africa') else
begin save_result('', '.txt');
if Assigned(m_on_after_whois_search_server_closed)
then m_on_after_whois_search_server_closed(Self);
end; end; // test_server_switch |
3.5 - The main Form Here is a snapshot of the main Form:
Here is a mini HowTo:
- place the liste of IP's into an ASCII file, which is saved in the _search_dns path
- run the application
- click "lookup_" to find the Whois Server's IP addresses
- select the "ip_dns_" tag, click your filename in the tFileListBox
Then - the informations will be saved in individual files in the _data\_result\ path
- if you click on an IP in the "redisplay_info_" the information about this IP will be redisplayed
4 - Download the Sources Here are the source code files:
- whois.zip: the application allowing the Whois requests (49 K)
Those .ZIP files contain: - the main program (.DPR, .DOF, .RES), the main form (.PAS, .DFM), and any other auxiliary form
- any .TXT for parameters
- all units (.PAS) for units
Those .ZIP - are self-contained: you will not need any other product (unless expressly mentioned).
- can be used from any folder (the pathes are RELATIVE)
- will not modify your PC in any way beyond the path where you placed the .ZIP (no registry changes, no path creation etc).
To use the .ZIP: - create or select any folder of your choice
- unzip the downloaded file
- using Delphi, compile and execute
To remove the .ZIP simply delete the folder.
As usual:
- please tell us at fcolibri@felix-colibri.com if you found some errors, mistakes, bugs, broken links or had some problem downloading the file. Resulting corrections will
be helpful for other readers
- we welcome any comment, criticism, enhancement, other sources or reference suggestion. Just send an e-mail to fcolibri@felix-colibri.com.
- or more simply, enter your (anonymous or with your e-mail if you want an answer) comments below and clic the "send" button
- and if you liked this article, talk about this site to your fellow developpers, add a link to your links page ou mention our articles in your blog or newsgroup posts when relevant. That's the way we operate:
the more traffic and Google references we get, the more articles we will write.
5 - The author Felix John COLIBRI works at the Pascal
Institute. Starting with Pascal in 1979, he then became involved with Object Oriented Programming, Delphi, Sql, Tcp/Ip, Html, UML. Currently, he is mainly
active in the area of custom software development (new projects, maintenance, audits, BDE migration, Delphi
Xe_n migrations, refactoring), Delphi Consulting and Delph
training. His web site features tutorials, technical papers about programming with full downloadable source code, and the description and calendar of forthcoming Delphi, FireBird, Tcp/IP, Web Services, OOP / UML, Design Patterns, Unit Testing training sessions. |