AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Tutorials Delphi How to BOLD(t) your problem
Tutorial durchsuchen
Ansicht
Themen-Optionen

How to BOLD(t) your problem

Ein Tutorial von sakura · begonnen am 5. Sep 2003 · letzter Beitrag vom 16. Nov 2003
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von sakura
sakura
Registriert seit: 10. Jun 2002
Hi DPler,

in den letzten Tagen war ich offensichtlich nicht da. Nun bin ich zurück. Neben viel Schlaf zur schnelleren Genesung habe ich auch einige Zeit dem "Architect" meiner Delphi Version gewidmet. (D7A - Delphi 7 Architect)



Ich muss zugeben, lange Zeit dachte ich mir, daß es doch mehr geben muss, als diese paar "lächerlichen" Bold-Komponenten, die in der Architect Version enthalten sind. Immerhin kostet diese müde 650 Euro mehr als die Enterprise. Aber... mehr ist nicht dabei. Na ja, die Zeit hatte es mir nicht gestattet mich ausführlicher mit "Bold for Delphi" (kurz Bold) zu beschäftigen. Die letzten Tage habe mir gezeigt, daß dieses wohl ein Fehler war. Mir fehlt wohl auch in der nächsten Zeit dieselbige, um mich näher mit zu beschäftigen, da die nächsten Termine nicht warten, aber ich bin schon mal heiß

Dieser Artikel ist ausschließlich für Eigentümer der Delphi 7 Architect Version, bzw. für Besitzer von Bold for Delphi. Der Rest mag es lesen, wenn Ihr wollt, allerdings wird das Testen der Beispiele nicht möglich sein, sorry

Was ist dieses Bold nun

Bold ist eines "dieser UML-Tools". Was Bold nicht liefert ist ein grafisches UML-Tool. Dafür muss man weiterhin auf etablierte Tools wie z.B. Rational Rose oder ModelMaker zurückgreifen. Für Käufer von D7A ist ModelMaker (kurz MM) schon auf der Delphi 7 CD mit dabei und nutzbar. Allerdings ist die Benutzung von Bold und MM nicht ohne ein weiteres Tool möglich - was natürlich wieder Geld kostet. Erhältlich bei Datator (http://developer.datator.com/products.html). Diese Produkte habe ich allerdings noch nicht getestet und greife hier lediglich auf Empfehlungen dritter zurück

Zurück zum Thema. Wenn Bold ein UML-Tool ist, welches keine grafischen UML-Darstellungen macht, was ist es dann genau. Im Bold UML-Editor kann man die Logiken, welche durch UML definiert werden hierarchisch darstellen. Alles, was in UML normalerweise grafisch dargestellt werden kann, kann man mit Hilfe von Bold in einer Treeview definieren.

nonVCL VCL Bold

Für die Puristen unter uns, welche gerne extrem kleine Programme erstellen, die ungepackt bereits möglichst unter 25 KB Gesamtgröße haben ist Bold wahrlich nichts. Aber diese "Masochisten" wollen ja sowieso alles mit Handles erschlagen

Kommen wir also zu denen, welche sich von den Größen der VCL-Projekte nicht zurückschrecken lassen. Bitte einmal tief durchatmen und eine DSL Leitung besorgen Bold Projekte schlagen ganz schnell mit Echsen von 1,5 MB zu Buche. Gibt es dafür eine gute Rechtfertigung?

Ja

Wer sich schon mal die ganzen Datenbanken-Demos von Delphi näher angeschaut hat, dem dürfte es nicht entgangen sein, daß einige von denen mit nur 0 Zeilen Code auskommen. Was bei den Demos nicht sofort auffällt ist, dass die Datenbankstruktur von Hand erstellt werden muss.

Und nu?

Bold ermöglicht uns das Designen von Anwendungen nach der benötigten Logik. Damit kann auch eine saubere Trennung von Datenspeicherung, Logik und GUI erreicht werden. Schauen wir uns das mal anhand eines konkreten Beispiels an.

......
Ich bin nicht zurück, ich tue nur so
 
Benutzerbild von sakura
sakura

 
Delphi 11 Alexandria
 
#2
  Alt 5. Sep 2003, 19:28
Prepare to roll...

Das folgende Beispiel lehnt sich eng an die bei Bold mitgelieferte Dokumentation von Anthony Richardson an, erweitert Part I jedoch nach meinem Geschmack.

Ziel unserer Bold-Anwendung wird es sein, eine kleine Kontakte-Verwaltung zu erstellen, die als eine gesamte Exe auslieferbar ist. Sie wird nicht wunderschön aussehen, oder viele Optionen bieten, aber uns einen ersten Einstieg in die Möglichkeiten von Bold liefern. Die Kontaktdaten werden in einer XML Datei im Verzeichnis der Anwendung gespeichert.

Hinweis I: Die Speicherung und Widerherstellung der Daten verläuft problemlos. Allerdings ist das erzeugte XML Format nicht 100% XML-konform, sobald Sonderzeichen (z.B. ä, ö, ü) in den Daten vorkommen. Der Import der Daten in andere Anwendungen könnte problematisch werden. Allerdings können auch andere Speicherarten (z.B. Datenbanken) genutzt werden.

Hinweis II: Die Änderungen solltet ihr häufig speichern, ganz fehlerfrei ist die IDE-Umgebung von Bold nicht.

Hinweis III: Es gibt ein aktuelles kostenfreies Update für alle registrierten D7A Anwender. HOLEN!

Wenn wir fertig sind, haben wir genau eine Zeile Code geschrieben, viel geklickt und hoffentlich etwas gelernt.

Das UML Model der Anwendung

Folgende Grafik habe ich mit ModelMaker erstellt. Wie bereits erwähnt wird die grafische Darstellung vom UML nicht direkt durch Bold erstellt. Da ich keine Tools zur Verbindung vom MM mit Bold einsetze, ist diese Grafik unabhängig erstellt, sollte aber passen



In der Grafik sehen wir drei Klassen. Die Klasse Contact ist eine abstrakte Klasse, deswegen auch die Darstellung in kursiv. Abgeleitet von dieser Klasse sind die Klassen Company und Person. Die Pfeile stellen diese Beziehung grafisch dar. Beide Klassen erben sämtliche Eigenschaften, Methoden und Felder der Klasse Contact und erweitern diese Klasse um deren eigenen Informationen. Zwischen der Klasse Company und der Klasse Person besteht eine weitere Beziehung. In Worten würden wir sagen, jede Person speichert zusätzlich die Information, für welche Company sie arbeitet. Zusätzlich sehen wir, daß jede Person für entweder keine oder genau eine Company arbeitet. Jede Company hat 0 bis n Person, die für diese arbeiten. (n ist eine beliebige Anzahl)

......
Daniel W.
  Mit Zitat antworten Zitat
Benutzerbild von sakura
sakura

 
Delphi 11 Alexandria
 
#3
  Alt 5. Sep 2003, 19:28
Ready to roll...

Okay, genug des Vorwortes, wollen wir mal Delphi einen Ruck geben und loslegen Man starte D7A oder eine andere Version von Delphi, wenn man BfD besitzt

Erstellt eine neue Anwendung und speichert diese an einem beliebigen Ort auf Eurer Festplatte. Da wir die Logik von Design trennen wollen, tun wir dieses auch in Delphi, also erstellen wir zusätzlich ein leeres Datenmodul und speichern dieses. Diesem DataModule gebe ich den Namen dtmBoldContainer

In das Datenmodul werden folgende Bold-Komponenten eingefügt:
  • TBoldModel (Palette: Bold Handles); Name bldModel; Diese Komponente speichert unser UML-Modell, welches wir später bearbeiten werden.
  • TBoldSystemTypeInfoHandle (Palette: Bold Handles); Name bldSystemTypeInfoHandle; Diese Komponente speichert die UML-Informationen so, daß zur Laufzeit unserer Anwendung möglichst schnell auf die Informationen zugegriffen werden kann, die nötig sind, damit sich unsere Anwendung an die festgelegte Businesslogik hält.
  • TBoldSystemHandle (Palette: Bold Handles); Name bldSystemHandle; Diese Komponente wird zur Designzeit von Bold benötigt, um die Businesslogik zu präsentieren.
  • TBoldPersistenceHandleFileXML (Palette: Bold Persistence); Name bldPersistenceHandleFileXML; Sollen die Daten unserer Anwendung gesichert werden, benötigen wir ein Möglichkeit diese "persistent" zu machen, diese zu speichern. Diese Komponente ermöglicht die Speicherung der Daten im XML-Format.

Das Datenmodul sollte ähnlich wie folgende Grafik ausschauen.



Jetzt müssen die Komponenten noch mit einander verknüpft werden. Die genaue Verbindung zueinander könnt Ihr der folgenden Grafik entnehmen. Diese Verknüpfungen können im Objekt Inspektor gesetzt werden. Zusätzlich sollte weitere Eigenschaften im Objekt Inspektor gesetzt werden.
  • bldSystemTypeInfoHandle.BoldModel := bldModel;
  • bldSystemTypeInfoHandle.UseGeneratedCode := False;
  • bldSystemHandle.SystemTypeInfoHandle := bldSystemTypeInfoHandle;
  • bldSystemHandle.PersistenceHandle := bldPersistenceHandleFileXML;
  • bldSystemHandle.AutoActivate := True;
  • bldPersistenceHandleFileXML.BoldModel := bldModel;
  • bldPersistenceHandleFileXML.FileName := 'contacts.xml';



......
Daniel W.
  Mit Zitat antworten Zitat
Benutzerbild von sakura
sakura

 
Delphi 11 Alexandria
 
#4
  Alt 5. Sep 2003, 19:29
Let's do the logical design

Projekt mal wieder speichern!

Bis hier sind die Schritte für jedes Bold-Projekt gleich bzw. ähnlich, abhängig zum Beispiel von der Art der Datenspeicherung. Aber nun zum eigentlich Projekt und seiner Logik. Dazu starten wir den Bold UML-Editor. Der versteckt sich hinter dem Doppelklick auf die TBoldModel (bldModel) Komponente.

In der aktuellsten Version von Bold sind die Kontextmenüs flexibler, als in den Vorgängerversionen. Von daher kann man fast an jeder Stelle jeden Menüpunkt erreichen und sollte der gewählte Punkt im aktuellen Kontext "keinen Sinn machen", sucht Bold die nächste sinnvolle Position, um die Abfrage auszuführen.



In der Grafik habe ich bereits die ersten drei Punkte unserer Aufgaben markiert. Wenn Ihr Euch ein wenig im Editor umgeschaut habt, dann geht jetzt auf die Root-Node (1) und wählt damit das aktuelle Projekt-Modell aus. Geben wir dem mal einen "vernünftigen" Namen (2) "BoldContacts". Im Feld Model Root Class (3) geben wir der Basis-Klasse unseres Models auch einen Namen "ContactsModelRoot". Anschließend noch die Node der Basis-Klasse (4) auswählen und im erscheinenden Dialog (rechte Seite) den gleichen Namen (5) angeben, den wir auch bei (3) angegeben haben.



Ähnlich wie in Delphi alle Klassen von TObject abgeleitet werden, müssen in einem Bold-Modell alle Klassen von einer Basisklasse oder deren abgeleiteten Klassen abgeleitet werden. Unterschied ist, daß diese Klasse frei benannt werden kann. Diese Klasse ist letztendlich, wenn das Projekt vollständig kompiliert ist, natürlich auch von TObject abgeleitet.

Unsere Klassen

Unterhalb der Node Logical View erstellen wir jetzt die drei benötigten Klassen für unser Model. Dazu müsst Ihr einfach mit der rechten Maustaste auf die Node Logical View klicken und den Menüpunkt New Class auswählen. In der ersten UML-Grafik haben wir dafür festgelegt, daß wir die folgenden Klassen benötigen.
  • Contact (unsere Basisklasse für Kontaktdaten)
  • Company (zusätzlich erforderliche Informationen für Firmendaten)
  • Person (zusätzlich erforderliche Informationen für Personendaten)

Nachdem wir die Klassen angelegt haben, müssen wir noch die Vererbung definieren. Dazu muss für die Node (Klasse) Contact bei der Eigenschaft Superclass die Klasse ContactsModelRoot ausgewählt werden. Für die Nodes (Klassen) Company und Person muss an gleicher Stelle die Klasse Contact ausgewählt werden. Zusätzlich speichern wir für die Klasse Contact, daß diese abstract ist. Das resultiert darin, daß später kein Kontakt angelegt werden kann, der nicht entweder vom Typ Company oder vom Typ Person ist, was sollte das auch für ein Kontakt sein. Ihr Kühlschrank?



Ein Kontakt sollte auch Daten haben

Das bringt uns jetzt zum nächsten Punkt. Wir haben unsere Klassen und diese Klassen können auch genutzt werden. Allerdings sind diese in deren jetzigen Zustand wohl eher nutzlos, da keine Klasse bis jetzt genauere Daten speichert. Nehmen wir dieses mal in Angriff Fangen wir mit der Klasse Contact, welche die Basis der anderen Kontaktdaten-Klassen ist. Klicken wir dazu mit der rechten Maustaste auf die Node der Klasse Contact und legen die folgenden Eigenschaften/Attribute an:
  • emailAddress
  • faxNumber
  • phoneNumber
  • postalAddress
Der Einfachheit zuliebe belassen wir die Defaultdatentypen und -einstellungen (String, 255 Zeichen). Für die Eigenschaften/Attribute emailAddress, faxNumber, phoneNumber, postalAddress markieren wir noch die Checkbox Allow null, da nicht jeder alle Informationen zu bieten hat.

Der Klasse Company geben wir jetzt noch die folgenden Eigenschaften/Attribute billingAddress, welche auch leer sein darf (Allow null markieren) und companyName.

Der Klasse Person geben wir jetzt noch die folgenden Eigenschaften/Attribute firstName und lastName. Beides sind Pflichtangaben (auch wenn es den Nutzer ärgern sollte )



Aber wer arbeitet wo?

Die Logik ist fast fertig. Wir müssen Bold nur noch "erklären", daß die Klasse Company eine 0:n-Beziehung zur Klasse Person (0:1-Beziehung) hat. Dazu klicken wir mit der rechten Maustaste wieder auf die Node Logical View und wählen den Menüpunkt New Association aus.



Anschließend stellt uns der Bold UML-Editor die neue Association bereit. Diese benennen wir gleich in "Employment" um.



Mit Hilfe dieser Assoziation können wir jetzt die logische Verbindung zwischen der Klasse Company und der Klasse Person herstellen. Dazu benennen wir das erste "Ende der Assoziation" in "worksFor" (Name) um. Bei Multiplicity wählen wir "0..1" aus und abschließend wählen wir für Class die Klasse "Company" aus. Das sollte uns direkt zu dem zweiten Ende der Beziehung (Assoziation) bringen. Dort tragen wir für den Namen "employs" ein, für Multiplicity den Wert "0..*" und für Class die Klasse "Person". Zusätzlich muss in der Verbindung für Klasse Company sichergestellt werden, daß das Häkchen bei der Checkbox Embed entfernt ist. Dadurch veranlassen wir, daß die Beziehung "Person <--> Company" auf seiten der Klasse Person gespeichert wird.



Hinweis: Es kann immer nur ein Ende einer Beziehung diese Speichern. für n:m-Beziehungen muss eine extra Klasse erstellt werden, welche zu jedem der Enden eine 0/1:n-Beziehung hat.

Damit habe wir die Verbindung zwischen Angestellten einer Firma zur Firma definiert, wie eingangs am UML-Modell (Grafik) beschrieben.

Spätestens jetzt sollte alles mal wieder gespeichert werden!

......
Daniel W.
  Mit Zitat antworten Zitat
Benutzerbild von sakura
sakura

 
Delphi 11 Alexandria
 
#5
  Alt 5. Sep 2003, 19:29
Der Nutzer muss auch was davon haben

Die Logik unser Anwendung ist soweit fertig, allerdings hat der Endanwender davon noch keinen sichtbaren Nutzen. Er kann die Daten weder lesen, noch ändern, noch neue hinzufügen. Also machen wir uns an die Oberfläche.

Als wir die Anwendung zu Beginn des Tutorials angelegt haben, war auch gleich ein Formular mit dabei, dieses werden wir jetzt mal etwas bestücken Es wird wahrlich nicht schön aussehen, aber uns erst einmal zeigen, wie es geht. Das Design überlasse ich Euch

Wir benötigen
  • Drei TLabel (Standard): Kontakte allgemein, Firmen, Personen
  • Drei TBoldNavigator (Bold Controls): eine für jede Datenklasse
  • Drei TBoldGrid (Bold Controls): eine für jede Datenklasse
  • Drei TBoldListHandle (Bold Handles): eine für jede Datenklasse

Damit wir jetzt die Verbindung der Bold-Komponenten vom Form zu unserem Modell herstellen können, müssen wir die Datenmodulunit in die uses-Klausel unseres Formulars aufnehmen! Anschließend können wir die benötigten Eigenschaften im Objekt Inspektor einstellen. Dieser Vorgang ist für alle drei Bereiche (Contact, Company und Person) identisch, daher werde ich es nur für den ersten beschreiben.

Die Verbindung des visuellen zur Geschäftslogik

Als erstes wird die Eigenschaft RootHandle der TBoldListHandle-Komponente auf das TBoldSystemHandle (Wert: dtmBoldContainer.bldSystemHandle) unseres Datenmodules gesetzt. (Für alle drei Bereiche identisch!) Jetzt wird die Eigenschaft Expression definiert. Hier wird die Sprache OCL genutzt, welche ich später mal separat erörtern werde. Ein Guide zu OCL wird bei der Installation von Bold mitgeliefert. Der Wert für Expression wird auf "Contact.allInstances" festgelegt. Wenn Ihr wollt, könnt ihr an dieser Stelle auch mal einen Blick in den Expression-Editor wagen

Anschließend wird für den Navigator und das Grid die Eigenschaft BoldHandle auf das entsprechende TBoldListHandle gesetzt. Nun müssen wir noch für das Grid die darzustellenden Spalten definieren. Dazu einfach mit der rechten Maustaste auf das Grid klicken und den Eintrag Create Default Columns anklicken. Fertig!

Am Ende sieht das Formular wie folgt aus (Design-Modus).



......
Daniel W.
  Mit Zitat antworten Zitat
Benutzerbild von sakura
sakura

 
Delphi 11 Alexandria
 
#6
  Alt 5. Sep 2003, 19:31
Unsere Zeile Code

Einen eigenen Abschnitt möchte ich doch glatt der Programmierung widmen Bei allem, was wir bis hierher getan haben, darf natürlich das eigentliche Coding nicht fehlen Im Ereignis OnClose unseres Formulars müssen wir dem Bold-Modell jetzt noch sagen, daß die Änderungen auch in der XML-Datei gesichert werden müssen.

Delphi-Quellcode:
procedure TfrmContactView.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  dtmBoldContainer.bldSystemHandle.System.UpdateDatabase;
end;
Außerdem müssen wir, für die erweiterte "Drag'n-Drop" Funktionalität von Bold die Unit BoldAFPDefault in die uses-Klausel unseres Formulars einfügen. Mit diesen Schritten können wir uns jetzt aufmachen und das Programm starten. Die Echse ist ca. 1,73 MB groß Aber was solls

Folgende Darstellung zeigt die Anwendung zur Laufzeit. Wenn Ihr draufklickt, erhaltet Ihr das Bild im Format 1280x1024



......
Daniel W.
  Mit Zitat antworten Zitat
Benutzerbild von sakura
sakura

 
Delphi 11 Alexandria
 
#7
  Alt 5. Sep 2003, 19:32
Was ist eigentlich geschehen, oder die "Pros" und "Cons"

Wir haben gerade eine kleine XML-Datenbank-Anwendung entworfen, zusammengeklickt und kompiliert. Damit das so einfach geht, übernimmt Bold eine kleine Riesenmenge an Arbeit für uns. Bold verwaltet sämtliche Logikanforderungen für uns, erstellt die Beziehungen und schreibt auf Wunsch sogar die benötigten Pascal-Units (was in diesem Tutorial nicht gezeigt ist).

Der offensichtliche Vorteil für uns als Programmierer ist es, daß wir uns mehr und mehr von den Aufgaben der Programmierung trennen können und uns nur mit dem beschäftigen müssen, was wirklich wichtig ist: der Logik hinter unserer Anwendung. Wir können nur hoffen, das die Entwickler von Bold bei der Umsetzung der Logik in ausführbare Anweisungen nicht so viele Fehler gemacht haben

Weitere Vorteile sind die Geschwindigkeit der Entwicklung und bei Anpassungen im Modell. Glaubt mir, ich habe während der Entstehung des Artikels einige gemacht. Am längsten hat es gedauert, die Screen Shots im Anschluss anzupassen

Bold gibt es nicht nur für Delphi, sondern auch für den C++ Builder. Damit lösen wir uns ein wenig von der Abhängigkeit zu Delphi. Durch weitere Tools können Bold Modelle vollständig in die UML-Anwendungen ModelMaker und Rational Rose (kurz RR) importiert werden. RR ermöglicht uns die Portierung dieser in andere Sprachen komplette Sprachunabhängigkeit, einfach mal nach JAVA portieren und auf dem Mac laufen lassen

Nachteilig kann sich die Abhängigkeit auch auswirken, wenn zum Beispiel Fehler in Bold existieren, muss man mind. auf das nächste Update warten oder diese mühsam umgehen. Natürlich ist es auch ein wenig umständlich, wenn man die Anwendungen online zum Download anbieten will, da die EXE-Dateien doch sehr groß werden.

Wofür man sich entscheidet, hängt letztendlich vom Entwickler ab. Ich hoffe aber, ich konnte einen kleinen Einblick in die Tiefen des "Architect" der Delphi 7 Studio Reihe geben.

Mehr zum Thema wird kommen. Ich habe auch erst ein wenig Luft geschnuppert.

......
Daniel W.
  Mit Zitat antworten Zitat
Benutzerbild von sakura
sakura

 
Delphi 11 Alexandria
 
#8
  Alt 5. Sep 2003, 19:36
Downloads

Anbei findet ihr die folgenden Downloads.
  • Bold Tutorial I.pdf Dieser komplette Beitrag als PDF Datei zum Ausdrucken
  • Sample App (Sources).zip Die Quellcodes zum Project (Voraussetzung Delphi 7 Architect muss installiert, registriert und lizensiert sein!)
  • Sample App (Bins).zip Die Echse des Projects und eine kleine Sample-Daten-Datei.
  • MM62 Models.zip Das Modelmaker UML-Model (ohne jegliche Logiken, Anweisungen, etc.)
Angehängte Dateien
Dateityp: pdf bold_tutorial_i.pdf (714,8 KB, 56x aufgerufen)
Dateityp: zip sample_app__sources_.zip (11,2 KB, 12x aufgerufen)
Dateityp: zip sample_app__bins_.zip (697,9 KB, 13x aufgerufen)
Dateityp: zip mm62_models.zip (3,6 KB, 13x aufgerufen)
Daniel W.
  Mit Zitat antworten Zitat
Daniel B
 
#9
  Alt 5. Sep 2003, 19:58
Wirklich schönes Tutorial!!
Mehr Worte bedarf es glaub ich nicht!
  Mit Zitat antworten Zitat
Hansa

 
Delphi 8 Professional
 
#10
  Alt 5. Sep 2003, 20:09
Hi, eine Frage: wo ist das jetzt bei welcher Delphi - Version dabei ? Nur Architect ? Ich habe das schon länger (vor D7) als Test-Version. Und Sakuras PDF kann ich nicht runterladen. Muß ich jetzt mühsam den Beitrag ausdrucken, um mal in Ruhe zu lesen, was der da geschrieben hat ? @Sakura: nichts für ungut, aber das muß ich in Ruhe lesen wegen der vielen Theorie.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:34 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz