![]() |
Zugriff auf Objekt in Klasse
Im Umgang mit Klassen (eigene Definitionen) bin ich noch nicht wirklich geübt.
Jetzt bin ich aber doch einigermassen erstaunt darüber, dass der Compiler folgendes frisst: Ich definiere eine eigene Klasse:
Code:
und greife dann darauf zu, ohne vorher eine Instanz gebildet zu haben.
TEmailCoreObject = CLASS(TObject)
IMAPClient: TIdIMAP4; ...
Code:
Warum geht das ?
IMAPClient.Host := 'imaps.gmail.com';
IMAPClient.Port := 993; Macht das Sinn ? Mit einer Typendeklaration RECORD ... geht das nicht, ich muss zuerst eine Variable mit diesem Typ definieren. Habe ich etwas nicht kapiert ? |
AW: Zugriff auf Objekt in Klasse
Der Fall liegt vermutlich etwas komplizierter. Studiert im Moment noch
nicht zuviel daran herum. Ich werde ein Präzisierung nachliefern. |
AW: Zugriff auf Objekt in Klasse
Moin...8-)
Zitat:
Delphi-Quellcode:
...Felder einer Klasse werden immer mit F gekennzeichnet. Da liegt u.a. an einer Property...wenn man es braucht. :zwinker:
TEmailCoreObject = CLASS(TObject)
IMAPClient: TIdIMAP4; StyleGuide: ![]() Bitte denke auch ggf. an die Sichtbarkeiten...wenn benötigt. ![]() Besser:
Delphi-Quellcode:
TEmailCoreObject = class
private protected FIMAPClient: TIdIMAP4; // protected...weil das auch in der abgeleiteten Klasse nach Core verfügbar sein soll, oder? public constuctor Create; destructor Destroy; override; property IMAPClient: TIdIMAP4 read FIMAPClient write FIMAPClient; // ggf. als property nach "Außen" end; ... constructor TEmailCoreObject.Create; begin FIMAPClient := TIdIMAP4.Create; end; destructor TEmailCoreObject.Destroy; begin FIMAPClient.Free; inherited; end; |
AW: Zugriff auf Objekt in Klasse
@Haentschman
danke, werde das genauer ansehen. Ich hab's jetzt nochmals genauer angeschaut: Eine Instanz von IMAPClient oder neu jetzt FIMAPClient wurde erzeugt und das überrascht mich jetzt, ohne vorher eine Instanz von TEmailCoreObject gebildet zu haben. Es existiert also nur:
Code:
und eine uninitialisierte Instanz von TEmailCoreObject in einem übergeordneten Modul
TEmailCoreObject = CLASS(TObject)
... PUBLIC FIMAPClient: TIdIMAP4; END; (ohne je ein Create durchgeführt zu haben). Und es läuft trotzdem. Nebenbei: Sehe ich das richtig, dass FIMAPClient ohne Schlüsselwort mit PUBLIC gleichzusetzen ist? Mindestens so scheint es bei mir zu funktionieren. |
AW: Zugriff auf Objekt in Klasse
Der Name ist vollkommen egal.
Und egal ob Record oder Class, die Instanz von TIdIMAP4 mußt du immer erstllen. Es wird da garnichts automatisch gemacht. Beim Class muß natürlich auch noch die Instanz von TEmailCoreObject erstellt werden. Einziger Unterschied, das Feld (FIMAPClient) wird in der Klasse automatisch mit NIL initialisiert. Ob das auch bei dem Record passiert, hängt davon ab, wo diese Variable liegt. (lokale Variablen in Prozeruden/Methoden sind nie initialisiert) |
AW: Zugriff auf Objekt in Klasse
Moin...:P
Zitat:
Zitat:
|
AW: Zugriff auf Objekt in Klasse
Zitat:
und auch NEIN. Normalerweise ist bei Objekten und auch Records der Default das "public". ABER alles ab TComponent TPersistent, da ist es "published", da {$M+} ! ![]() Darum sind die Komponenten-Variablen in TForms am Anfang eben auch published, damit der DFM-Reader diese Varialen und die EventMethoden finden kann. |
AW: Zugriff auf Objekt in Klasse
Zitat:
Nur VCL/FMX Klassen brauchen dieses Verhalten, da alle in dieser "nicht" Sektion deklarierte Felder die auf der Form liegenden Komponenten sind, deren eigentliche Erzeugung/Initialisierung über den Form Streaming Mechanismus erfolgt. Aber du solltest dir's besser gleich abgewöhnen. |
AW: Zugriff auf Objekt in Klasse
Ich bin da weiterhin am Üben.
Die Klassendefinition habe ich geändert, so dass nun TEmailCoreObject ein Nachkomme von TidIMAP4 ist.
Code:
Nun einige Fragen:
TYPE
TEmailCoreObject = CLASS(TidIMAP4) PRIVATE (* Private-Deklarationen *) OpenSSLHandler: TIdSSLIOHandlerSocketOpenSSL; PUBLIC (* Public-Deklarationen *) PROCEDURE OpenEmail(VAR IMAPClientExtd: TEmailCoreObject); PROCEDURE CloseEmail(VAR IMAPClientExtd: TEmailCoreObject); END; - Wenn ich eine Instanz von TEmailCoreObject erzeuge, ist dann das CREATE nur für diese Instanz notwendig oder zusätzlich auch für TidIMAP4 ? - Die Klasse TEmailCoreObject kommt auch als Parameter in den Methoden vor, z.B. in OpenEmail(..). Ist das ein unzulässiger Schwanzbeisser oder geht das ? - Wie kann ich ganz einfach feststellen, ob ein Objekt richtig erzeugt wurde ? (am liebsten mit Debugger) |
AW: Zugriff auf Objekt in Klasse
Hallo,
schreib ins Create ein inherited Create, dann gilt das Create für beide. Schwanzbeisser, ja Warum das Objekt als Parameter an das gleiche Objekt/Klasse übergeben? Initialisiertes Objekt erkennen? Setze es auf NIL sonst erkennst du es nicht. |
AW: Zugriff auf Objekt in Klasse
@hoika
Schwanzbeisser: - Ich möchte möglichst alles in das Modul verpacken, auch das Create! - Der einzige Zugriff soll (vorderhand) über OpenEmail und CloseEmail erfolgen, später dann noch Setup, Read und Write. Ich benötige aber gleichzeitig mehrere EmailProvider, daher mehrere IMAPClients. Vielleicht hast du weiteren Tipp /Lösungsweg ? |
AW: Zugriff auf Objekt in Klasse
Noch etwas:
Vorderhand, während Entwicklung, möchte ich auch ausserhalb des Email-Moduls vollen Zugriff auf TidIMAP4 um alle Funktionen des IMAP4 Drivers verwenden zu können. |
AW: Zugriff auf Objekt in Klasse
Hallo,
Zugriff auf IMAP4 hast du ja durch die Ableitung. Und mehere Konten = mehrere eigene Klassen, pro Konto eine. Aber: Bevor du mit deinen ganzen eigenen Dachen anfängst, würde ich erst mal alles mit dem originalen Indy TIdImap4 zusammenbauen und dann deine eigene Klasse erzeugen. |
AW: Zugriff auf Objekt in Klasse
Moin...:P
Es ist zwar löblich das Üben in einen sinnvollen Kontext zu packen. :thumb: Das hilft dir nicht weiter. Du brauchst Grundlagen! Zitat:
Was das bedeutet: siehe ![]() Noch Lesestoff: ![]() :wink: |
AW: Zugriff auf Objekt in Klasse
@hoika
das Arbeiten mit dem Indy TIdIMAP4 funktioniert grundsätzlich. Nur will ich ein einfacheres und anwenderfreundlicheres Interface dazu. Gewisse Details dürfen versteckt bleiben. In den bisherigen Anwendungen zeigte sich was für mich wichtig ist, darum möchte ich nicht immer den ganzen Ballast mitschleppen. @hoika, haentschman Ich programmiere seit einem halben Jahrhundert (was an und für sich noch nichts heissen will). Es ist einfach so, dass OOP mich noch nicht so richtig überzeugt hat. Trotzdem will ich den Einstieg jetzt mal definitiv durchziehen. Auch, damit ich mir selbst ein Bild von den Vor- und Nachteilen machen kann. Bis anhin sehe ich vorallem die Nachteile. Bis jetzt habe ich eher den Eindruck von viel Ballast und - was ich hasse: unsichere und unzuverlässige Software. Wohlverstanden immer mit dem gleichen Aufwand. Auch bezüglich der besseren Lesbarkeit bin ich noch nicht überzeugt. Aber warten wir ab, vielleicht komme ich noch auf den Geschmack. Etwas verwundert bin ich auch, dass mir der Einstieg nicht eins, zwei, drei gelingt. Hat das mit dem Alter, Eingefahrenheit oder damit zu tun, dass doch nicht alles so logisch und konsistent ist ? Kann auch sein, dass ich noch nicht die für mich richtige Literatur gefunden habe. Nun ich mache weiter und werde weitere Fragen stellen. Bis dahin herzlichen Dank |
AW: Zugriff auf Objekt in Klasse
Hallo,
wenn du die Grundlagen noch sicherer drauf hast, ist's kein wirklicher ballast mehr. Deine Klasse erbt ja eigentlich alles von der entsprechenden Indy-Klasse, du solltest halt nur wie schon beschrieben einen Constructor spendieren und in dem inherited aufrufen, damit der geerbte Constructor der Indy-Klasse auch aufgerufen wird. Dannb rauchst du vermutlich bei deinen Methoden keine Objektinstanzen mehr als Parameter, das macht dann alles die eigene Klasse. Allerdings: durch das Erben sind bei deiner Klasse halt auch alle Dinge, welche die Indy-Klasse als public anbietet weiterhin public. Wenn dir das nicht passt kannst du alternativ eine Klasse schreiben die nicht erbt, sondern intern eine Instanz der betreffenden Indy-Klasse nutzt die im COnstructor erzeugt wird und im Destructor freigegeben wird. Dann schreibst du nur für die DInge, die bei dir öffentlich sein soll entsprechende Wrapper-Methoden. Grüße TurboMagic |
AW: Zugriff auf Objekt in Klasse
Wenn er kaseln will würde ich das auch eher vorschlagen (
![]() |
AW: Zugriff auf Objekt in Klasse
Nun ich gehe jetzt tiefer in die Materie, es bringt ja nichts, wenn ich es nur
halb verstehe. Bin an Übungen mit dem Doberenz Delphi 7 Buch. Das Tutorial des Delphi-Treffs kann ich nicht mehr runterladen. Weiss jemand wo das noch möglich ist ? Zugleich muss ich vorwärts kommen. Daher nun zu weiteren Schwierigkeiten. Für das aktuelle Problem bin ich nahe am Ziel. In der folgenden Version läuft's nämlich:
Code:
Es wurde mir klar, dass die 'Übergabe' einer Instanz eigentlich einer Parameterübergabe
(* Deklaration und Aufruf *)
VAR IMAPClientEx: TEmailCoreObject; ... BEGIN IMAPClientEx := TEmailCoreObject.Create(NIL); IMAPClientEx.OpenEmail; .. .. END; (* Klassendefinition und Implementation (in eigenem Modul) *) TYPE TEmailCoreObject = CLASS(TidIMAP4) PRIVATE (* Private-Deklarationen *) .. PUBLIC (* Public-Deklarationen *) PROCEDURE OpenEmail; PROCEDURE CloseEmail; END; entspricht. Daher können auch die Parameter in OpenEmail usw.entfallen. (wie von TurboMagic gesagt) Was mir an dieser Realisierung noch nicht passt, ist, dass das Create im Aufrufteil stattfindet. Das muss in das Modul mit der Klassendefinition rein. Wie dieses Create-Zeile aussieht ist mir noch nicht klar. Der Compiler frisst zwar folgendes, aber die Referenz der Instanz verschwindet natürlich im Nirvana.
Code:
Vielleicht hat das jetzt mit dem anscheinend notwendigen (oder mindestens empfehlenswerten) CONSTRUCTOR
(* Deklaration und Aufruf *)
VAR IMAPClientEx: TEmailCoreObject; ... BEGIN IMAPClientEx.OpenEmail; .. .. END; (* Klassendefinition und Implementation (in eigenem Modul) *) TYPE TEmailCoreObject = CLASS(TidIMAP4) PRIVATE (* Private-Deklarationen *) .. PUBLIC (* Public-Deklarationen *) PROCEDURE OpenEmail; PROCEDURE CloseEmail; END; PROCEDURE OpenEmail; BEGIN TEmailCoreObject.Create(NIL); (* geht nicht, funktionierende Alternative ? *) .. .. END; zu tun? Auch das SELF könnte ein Kandidat zur Lösung des Problems sein. Grüsse |
AW: Zugriff auf Objekt in Klasse
Die Tutorials gehen doch? Zumindest kann ich problemlos z. B. das folgende aufrufen:
![]()
Delphi-Quellcode:
(* Deklaration und Aufruf *)
// jeder soll formatieren wie er kann und mag, aber dieses UPPERCASE der Schlüsselwörter ist irgendwie ganz schwer // TurboPascal aus den Achtzigern. Da wird der Bildschirm vor dem inneren Auge schwarz und die Schrift giftgrün // und auf auf 80 Zeichen pro Zeile begrenzt ;-) VAR IMAPClientEx: TEmailCoreObject; ... BEGIN IMAPClientEx := TEmailCoreObject.Create(nil); IMAPClientEx.OpenEmail; .. .. // wenn fertig, freigeben: IMAPClientEx.Free; END; (* Klassendefinition und Implementation (in eigenem Modul) *) TYPE TEmailCoreObject = CLASS(TidIMAP4) PRIVATE (* Private-Deklarationen *) .. PUBLIC (* Public-Deklarationen *) PROCEDURE OpenEmail; PROCEDURE CloseEmail; END; PROCEDURE TEmailCoreObject.OpenEmail; // < - - - - Hier die Änderung beachten BEGIN // hier jetzt die eigentliche Logik implementieren. .. .. END; |
AW: Zugriff auf Objekt in Klasse
@TiGü und andere
Entschuldigung, das habe ich unvollständig kopiert bzw. abgeschrieben. Das ist schon mit der Klasse vorne dran. |
AW: Zugriff auf Objekt in Klasse
@TiGü
Du schon recht, das einzelne Tutorial lässt sich schon runterladen. Was nicht geht ist der Download des Delphi-Starter. |
AW: Zugriff auf Objekt in Klasse
Du meinst dieses PDF-Buch?
Naja, da verpasst man jetzt auch nichts. |
AW: Zugriff auf Objekt in Klasse
An meinem letzten Problem stehe ich immer noch an, trotz lesen in
mehreren Büchern. Im Hauptmodul soll's so aussehen, kein Create:
Code:
VAR
IMAPClientEx: TEmailCoreObject; ... BEGIN IMAPClientEx.OpenEmail; .. .. END; Das Untermodul (EmailCore) soll so aussehen:
Code:
Kann da jemand konkret weiterhelfen ? Danke
UNIT EmailCore;
TYPE TEmailCoreObject = CLASS(TidIMAP4) PRIVATE (* Private-Deklarationen *) .. PUBLIC (* Public-Deklarationen *) // hier CONSTRUCTOR notwendig ?? Wie genau ? <--- PROCEDURE OpenEmail; .. END; PROCEDURE TEmailCoreObject.OpenEmail; BEGIN // Was muss hier eingefuegt werden, damit der Speicher für TEmailCoreObject // reserviert wird ? <--- .. .. END; |
AW: Zugriff auf Objekt in Klasse
warum sträubst Du dich so gegen ein Create?
Delphi-Quellcode:
Wenn Du kein Create haben möchstes musst Du Klassen-Methoden erstellen.
VAR
IMAPClientEx: TEmailCoreObject; ... BEGIN IMAPClientEx := TEmailCoreObject.Create; try IMAPClientEx.OpenEmail; .. .. finally IMAPClientEx.Free; end; END; Dann könnte es so gehen. Grüße Klaus |
AW: Zugriff auf Objekt in Klasse
Weil das nur ein technisches Problem (endlicher Speicher) ist und nichts mit der eigentlichen
Aufgabe zu tun hat. Es verhunzt die eigentliche Absicht. Die Essenz des Programmes versinkt in solchen technischen Details. Das Programm ist schlussendlich schlechter lesbar, es sind mehr Fehler möglich. Natürlich mag das für einen Einzelfall nicht grafierend sein aber in der Summe.. Eine normale Variable muss man ja auch nicht zuerst kreiieren. Ich mag diesen Ballast nicht, so ähnlich ist es ja auch mit der Fehlerverarbeitung. Auch die ist so dominant, obwohl es eigentlich nur um die Ausnahmen geht. Ich bin da ein Purist und würde sogar soweit gehen, dass dies ein Teil unserer heutigen Softwarekrise ist. Um es zu verdeutlichen ein Beispiel - der Zugriff auf eine Festplatte: - Oeffnen (mit moeglichst wenigen Parametern, oder allenfalls Setup) - Lesen oder Schreiben - Schliessen Das ist die Hauptstruktur, nichts weiter. Und die muss möglichst sichtbar bleiben. Details dann in tieferen Schichten und auch dort dasselbe. Ich hoffe du verstehst mich nicht falsch. Ich finde es wird gerade in der Software-Industrie oft viel zu kompliziert gedacht. Ich könnte jetzt ein weiteres Mal Einstein zitieren... Grüsse FediDelPr |
AW: Zugriff auf Objekt in Klasse
Ah danke noch, dann schau ich mal bei den Klassen-Methoden
|
AW: Zugriff auf Objekt in Klasse
Gesetzt den Fall ich verzichte auf das Create im aufrufenden Modul,
Code:
kann ich eine Methode trotzdem erreichen oder nicht ? Ist also der Einsprung trotzdem
VAR
IMAPClientEx: TEmailCoreObject; ... BEGIN // IMAPClientEx := TEmailCoreObject.Create(nil); --> kein Create IMAPClientEx.OpenEmail; .. garantiert oder geht der Aufruf quasi ins Leere (weil nicht definiert) ? Beim Debugging war das erfolgreich. Zufall ? |
AW: Zugriff auf Objekt in Klasse
Moin...:P
Zitat:
Zur dynamischen Verwendung einer Klasse/Objekt gehört immer ein Create/Free. Bei dieser Konstellation hast du die Wahl wann das Objekt im Speicher aufgenommen wird (Create) und wieder entfernt wird (Free). Zitat:
Zitat:
Zitat:
Zitat:
Wie schon mehrfach gesagt:
Delphi-Quellcode:
Stell den gesamten Code mal ein.
type
TEmailCoreObject = class(TidIMAP4) private public constructor Create(Owner: TComponent); destructor Destroy; override; procedure OpenEmail; end; implementation constructor TEmailCoreObject.Create(Owner: TComponent) begin inherited Create(Owner) // immer erste Zeile -> Erzeugen Vorfahr TidIMAP4 // end; destructor TEmailCoreObject.Destroy; begin // inherited; // immer letzte Zeile end; . . . procedure TfoMain.Blubb; var IMAPClientEx: TEmailCoreObject; begin IMAPClientEx := TEmailCoreObject.Create(nil); try IMAPClientEx.OpenEmail; finally IMAPClientEx.Free; end; end; |
AW: Zugriff auf Objekt in Klasse
Hallo,
ich glaube der TE verwechselt Debuggen mit Compilieren. Wenn Du ohne Create arbeiten willst, Musst du die Klasse über den Delphi-Designer auf das DataModul packen. Davon raten dir hier alle ab. Jetzt musst du halt entscheiden. |
AW: Zugriff auf Objekt in Klasse
Zitat:
Nochmal zu Klassenmethoden: ![]() Zitat:
Frage: Wie oft wird das Objekt benutzt? Je nach Verwendung kann man das Objekt direkt vor OpenMail erzeugen und direkt wieder freigeben oder z.b. im constructor der Form oder der Logik Klasse erzeugen und am Ende (jeweiliger destuctor) wieder freigeben. Damit hat man das Objekt über die Lebensdauer der Form z.B. im Zugriff ohne ständig Create/Free. :zwinker: |
AW: Zugriff auf Objekt in Klasse
Für deinen Fall kannst du auch einen singleton implementieren (oder eine globale variable mit initialization und finalization nutzen), aber auch ich rate dir davon ab...
|
AW: Zugriff auf Objekt in Klasse
Zitat:
- Unsichere / unzuverlässige Software lässt sich in erster Linie mit einem Instrument bekämpfen: Tests. Am besten automatisierte, zuverlässige (deterministische) häufige, umfangreiche Tests. OOP hat damit nur sehr am Rande etwas zu tun. OOP bietet mMn vor allem eine Gruppierung von Methoden mit einem Zusammenhang an. Wo man "früher" einen struct erstellt hat und dann 7 Funktionen hatte, die den als Parameter bekommen, kann man heute eine Klasse erstellen und die Methoden mit den Daten zusammen in einer Datei ablegen. Zitat:
Wenn du keine dynamische Speicherallozierung machst, dann musst du für jede Sache beim Compilieren festlegen, wieviele verschiedene Sachen es geben darf. Also Chrome würde bspw. mit maximal 20 Tabs laufen weil das Array hat auf 20 Elemente gesetzt ist. In echt möchte aber der eine Type 50 schlanke Tabs laufen lassen, der zweite nur einen Tab aber der rechnet irre viel und der dritte kauft sich extra 64GB RAM um 500 Tabs parallel anzuzeigen. Daher gibt es dynamisches Speichermanagement, damit jeder das machen kann, was er will ;-) Und dazu gehört dann auch immer Speicher allozieren und freigeben. Vergleiche einmal Pseudocode:
Code:
var myParams = malloc(TmyParams);
myParams.Recipient = "a@b.com" SendEmail(myParams); Free(myParams);
Code:
Ist quasi dasselbe, nur anders aufgeschrieben. Das Problem, was hier gelöst wird: Es wird Speicher für Variablen reserviert, die länger leben als ein Funktionsaufruf. Denn letztlich kennt der C und der Delphi Compiler die zwei Optionen: Variable lebt genau so lange wie die Funktion (Stack) oder Variable lebt länger => Heap & Programmierer muss sich darum kümmern, den Speicher wieder aufzuräumen.
var myParams = TmyParams.Create();
myParams.Recipient = "a@b.com" myParams.SendEmail(); myParams.Free; Wenn dir das Speichermanagement zuviel wird, würde ich dir eine andere Sprache empfehlen. Eine mit automatischem Speichermanagement. Dann musst du immer noch allozieren, aber nicht mehr freigeben. Die Auswahl ist riesig und wird immer größer. (Mir wäre keine neue Sprache bekannt, die dem Entwickler das aufbürdet) Eine Auswahl: - Rust - Javascript / Typescript - C# - Kotlin - Python - Oxygene? Der Code wird lesbarer weil du dich um das freigeben nicht mehr kümmern musst. |
AW: Zugriff auf Objekt in Klasse
Automatisches Speichermanagement klingt zwar in der Theorie schön, hat in der Praxis aber durchaus auch seine Tücken.
Ein gutes Beispüiel dafür war die Delphi 2006 IDE... Denn: der Speicher wird nicht deterministisch sondern meist irgendwann (Ausnahme: ARC) freigegeben. Bis dahin hat sich etvl. viel "Müll" angesammelt oder die Freigabe passiert zu einem Zeitpunkt wo der Garbage Collector meint es wäre oppertun, es aber in Wirklichkeit doch nicht ist... |
AW: Zugriff auf Objekt in Klasse
Zugriff auf nicht erzeugte Objektreferenzen wird eher zeitnah knallen!
Einfach nicht so gegen das Create sträuben! Du kannst halt auch nicht in der Bibliothek ein Buch ausleihen ohne den Ausleihvorgang irgendwie zu registrieren... Und was Exceptionbehandlung anbelangt: die ist eigentlich weniger aufdringlich als die klassische Fehlerbehandlungsmethode. Warum? Weil man früher direkt nach jedem Aufruf der schief gehen konnte eine Statusvariable (in Turbo Pascal IOresult, in SAP's ABAP Sy-Subrc) direkt abfragen musste und dann dort den Fehler gleich behandeln musste weil er sonst nach dem nächsten Aufruf einer Routine die diese Fehlerbehandlung nutzt überschrieben ist. Bei Exceptions kann man mitunter auch eine zentrale Behandlung irgendwo implementieren und alle Exceptions laufen dort auf, egal woher die kommen. Man kann auch Fehler durch unterschiedliche Exception Klassen unterscheiden und nur die behandeln, die man für relevant hält. Diese Klassen können dann auch zusätzliche Daten die Infos zur Fehlerursache enthalten bekommen usw. ALles Dinge, die der klassische Ansatz nicht bietet. Der lenkt vielstärker von der eigentlichen Aufgabe ab als so ein Create Aufruf... |
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:14 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz