Autor Beitrag
Silas
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 478

Windows XP Home
Delphi 2005, RAD Studio 2007, MASM32, FASM, SharpDevelop 3.0
BeitragVerfasst: Fr 31.08.07 16:21 
FastIniFiles (TFIniFile)

Die Klasse TFIniFile hat im Grunde die selbe Funktion wie TIniFile, nur wird die INI-Datei komplett in einen Speicherbaum geladen und von dort aus gelesen/bearbeitet. Die Handhabung ist der von TRegistry relativ ähnlich.


Vorteile:
  • Es können auch größere Dateien ohne extrem hohen Zeitverbrauch verwendet werden (bis zu 100 mal schneller als TMemIniFile!)
  • Es lässt sich feststellen, ob die geöffnete Datei fehlerfrei war
  • Es gibt die Möglichkeit, die Datei in einem anderen Ordner / mit einem anderen Dateinamen zu speichern
  • FastIniFiles besitzt mehr Möglichkeiten, Daten zu speichern (z.B. Binärdaten)

Beispiel:
Ein Code, der in der Datei "test.ini" aus der Sektion "testSect" die Eigenschaft "testValue" ausliest, könnte folgendermaßen aussehen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
with TFIniFile.Create('test.ini'do begin
  if SectionExists('testSect'then begin 
    EnterSection; // 'testSect' wurde beim letzten Zugriff gefunden und muss nicht mehr angegeben werden
    if ValueExists('testValue'then WriteLn('testValue: ' + ReadString) // siehe oben
    else WriteLn('Konnte Eigenschaft nicht auslesen');
  end else WriteLn('Konnte Sektion nicht finden');
  Free;
end;


Speedtest: (Im Vergleich zu TMemIniFile)
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
TMemIniFile vs. TFIniFile Speedtest
===================================

Ergebnisse:

  TMemIniFile
    Create & Free
      Große Datei: 7,328 ms
      Mittlere Datei: 2,235 ms
      Kleine Datei: 0,203 ms
    Datei auslesen (Mit Prüfung)
      Große Datei: 339,187 ms
      Mittlere Datei: 63,312 ms
      Kleine Datei: 0,797 ms
  
  TFIniFile
    Create & Free
      Große Datei: 10,766 ms
      Mittlere Datei: 3,093 ms
      Kleine Datei: 0,235 ms
    Datei auslesen (Mit Prüfung)
      Große Datei: 3,75 ms
      Mittlere Datei: 0,922 ms
      Kleine Datei: 0,16 ms

Große Datei = 100 Sektionen a 50 Eigenschaften
Mittlere Datei = 50 Sektionen a 30 Eigenschaften
Kleine Datei = 5 Sektionen a 10 Eigenschaften

Alle Tests wurden der Genauigkeit halber 1000 mal durchgeführt.


Lizenz: Die Lizenz liegt der Unit bei.
Einloggen, um Attachments anzusehen!
_________________
Religionskriege sind nur Streitigkeiten darüber, wer den cooleren imaginären Freund hat ;-)


Zuletzt bearbeitet von Silas am Fr 08.05.09 14:42, insgesamt 31-mal bearbeitet
Gausi
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8410
Erhaltene Danke: 431

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.2 CE
BeitragVerfasst: Fr 31.08.07 16:30 
Interessante Idee. Kannst du grob erläutern, wo der Vorteil deiner Klasse gegenüber TMemIniFile ist? Denn da wird das ja ähnlich gehandhabt, oder irre ich mich da?

_________________
Oel ngati kameie.
Silas Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 478

Windows XP Home
Delphi 2005, RAD Studio 2007, MASM32, FASM, SharpDevelop 3.0
BeitragVerfasst: Fr 31.08.07 17:03 
:les: Oh, TMemIniFile hab ich noch gar nicht gekannt. Das macht den größten Vorteil schon einmal zunichte.
Mein zugegebenermaßen nicht so tolles Delphi-Buch sagt mir (mehr oder weniger gut), das das ganze in Stringlisten gespeichert wird (stimmt das?).

Meine Klasse speichert es als Baum, also in etwa so:
  • TFIniFile
    • Sektion1
      • Name
      • Eigenschaften
        • Eigenschaft1
          • Name
          • Wert
        • Eigenschaft2
          • Name
          • Wert
    • Sektion2
      • Name
      • Eigenschaften
        • Eigenschaft1
          • Name
          • Wert
        • Eigenschaft2
          • Name
          • Wert

Wenn das mit den Stringlisten stimmt, wäre ein Baum schon schneller, weil kopierarbeit wegfällt.
Die "ganze Arbeit" wird bei meiner Klasse im Konstruktor ausgeführt, die Read/Write-Methoden müssen nur noch im Baum den jeweiligen Wert suchen.
Außerdem gibt es (wie bei TRegistry) eine aktuelle Sektion, sodass nicht bei jedem Vorgang die Sektion gesucht werden muss (Ich weiß nicht wie das bei TMemIniFile ist, deswegen geh ich hier von TIniFile aus).

_________________
Religionskriege sind nur Streitigkeiten darüber, wer den cooleren imaginären Freund hat ;-)
Horst_H
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1640
Erhaltene Danke: 234

WIN10,PuppyLinux
FreePascal,Lazarus
BeitragVerfasst: Fr 31.08.07 17:42 
Hallo,

eine kleine Frage:
wieso dies hier?
ausblenden Delphi-Quelltext
1:
2:
Float1=123.456 #Float mit .
Float2=123,456 #Float mit ,

Wäre es nicht geschickter in der Ini Datei den Ländercode mitzuspeichern oder das Format von "Format" mit abzuspeichern??

Gruß Horst
Silas Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 478

Windows XP Home
Delphi 2005, RAD Studio 2007, MASM32, FASM, SharpDevelop 3.0
BeitragVerfasst: Fr 31.08.07 18:12 
Na ja, man muss immer davon ausgehen, dass in einer INI-Datei (die ja deutsch oder englisch oder was auch immer sein kann) diese Info nicht gespeichert ist. Dann kann der Parser ja nicht wissen, welches Format das verwendete ist.

_________________
Religionskriege sind nur Streitigkeiten darüber, wer den cooleren imaginären Freund hat ;-)
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8720
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Fr 31.08.07 21:27 
Ein paar Fragen:
- Ist das Kommentar-Zeichen einstellbar?
- Könnte der Parser so erweitert werden, dass man Kommentare zurückspeichern kann? (Wär doch schade, wenn meine php.ini plötzlich ohne Kommentare dastände ;-))
- Kommt deine Klasse mit doppelten Sektionen oder doppelten Einträgen klar (Sagen wir, weil ein Programm denkt, mehrzeilige Angaben durch mehrere Zeilen mit dem Gleichen Namen zu speichern?
- Kann man die Reihenfolge der Einträge beeinflussen beim Speichern?

Kennst Du TBigIniFile?
- Kann deine Klasse TColor-Werte lesen?
- Werden andere Zusatztypen unterstützt? (z.B. Sets oder Enums auslesen, wenn man die Typinfo von Delphi mitliefert)???

Ansonsten ne nette Idee; hab mir die Implementierung aber noch nicht im Detail angeschaut.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
matze
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 4613
Erhaltene Danke: 24

XP home, prof
Delphi 2009 Prof,
BeitragVerfasst: Fr 31.08.07 21:57 
Ja das mit dem Kommentarzeichen ist wichtig. Das muss irgendwie markiert werden.
Denn wenn ich folgenden String abspeichern möchte: Das ist das Haus #4 würde ja nur Das ist das Haus rauskommen. Du müsstest das irgendwie "escapen".

Man müsste auch direkt mal einen Speedtest durchführen: FastIniFiles vs MemIniFile

_________________
In the beginning was the word.
And the word was content-type: text/plain.
Silas Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 478

Windows XP Home
Delphi 2005, RAD Studio 2007, MASM32, FASM, SharpDevelop 3.0
BeitragVerfasst: So 02.09.07 12:28 
user profile iconBenBE hat folgendes geschrieben:
Ist das Kommentar-Zeichen einstellbar?
Ab jetzt schon. :) (Der Konstruktor hat einen zweiten Parameter bekommen)
user profile iconBenBE hat folgendes geschrieben:
Könnte der Parser so erweitert werden, dass man Kommentare zurückspeichern kann?
Schwierig. Das ist ein Nachteil der Baumstruktur. Wenn du die Datei nicht bearbeitest, bleibt sie ja unverändert. Es gäbe die Möglichkeit, für jede Eigenschaft die Kommentare davor bzw. danach abzuspeichern, aber ob dass so effizient ist... Ich werd's mal versuchen, aber wenn jemand eine bessere Idee hat, freu' ich mich natürlich.

user profile iconBenBE hat folgendes geschrieben:
Kommt deine Klasse mit doppelten Sektionen oder doppelten Einträgen klar (Sagen wir, weil ein Programm denkt, mehrzeilige Angaben durch mehrere Zeilen mit dem Gleichen Namen zu speichern?
Auch noch nicht. Aber ich könnte es so ändern, dass er in diesem Fall eine Stringliste verwendet, oder dass es ein Zeilen-Fortsetzungs-Zeichen (wie in manchen Sprachen der Backslash) gibt (Das zweite wäre natürlich einfacher).

user profile iconBenBE hat folgendes geschrieben:
Kann man die Reihenfolge der Einträge beeinflussen beim Speichern?
Nein, das ist wieder ein Problem mit der Baumstruktur. Die neuesten Einträge landen immer unten in der Sektion bzw. in der Datei.

user profile iconBenBE hat folgendes geschrieben:
Kennst Du TBigIniFile?
Nein :wink: (Hab auf die Schnelle jetzt auch nichts gefunden)

user profile iconBenBE hat folgendes geschrieben:
Kann deine Klasse TColor-Werte lesen?
Ist das nicht ein Integer?

user profile iconBenBE hat folgendes geschrieben:
Werden andere Zusatztypen unterstützt?
Bis jetzt nur String, Integer, Boolean und Extended. Werd' aber noch eine ReadBinary und WriteBinary-Methode einbauen.


user profile iconmatze hat folgendes geschrieben:
Man müsste auch direkt mal einen Speedtest durchführen: FastIniFiles vs MemIniFile

Voilà: Siehe erster Post
Schaut euch das Ergebnis an. :beer:

_________________
Religionskriege sind nur Streitigkeiten darüber, wer den cooleren imaginären Freund hat ;-)


Zuletzt bearbeitet von Silas am So 17.02.08 16:55, insgesamt 1-mal bearbeitet
Silas Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 478

Windows XP Home
Delphi 2005, RAD Studio 2007, MASM32, FASM, SharpDevelop 3.0
BeitragVerfasst: Sa 05.01.08 15:16 
So, nach einem knappen halben Jahr: Ein neues Release! (Version 2.0)
[+] Read/WriteBinary - Funktionen: Schreiben/Lesen beliebige Werte (z.B. Records, GUIDs) als hexadezimalen string in die/aus der Datei.
[+] Escapede Strings: Schreiben/Lesen nach C-Art escapede Strings ((un)escaped werden die Whitespaces, sodass beispielsweise mehrzeilige und/oder mit Tabs/Leerzeichen formatierte Werte gespeichert werden können
[+] Eine Clear-Prozedur: Löscht den Inhalt der gesamten Datei
[+] Dazu gehörend eine ClearSection-Prozedur: löscht den Inhalt einer Sektion
[+] Zugriffsbeschleunigung: Wenn z.B. die existenz einer Sektion mit SectionExists abgefragt wurde, muss bei EnterSection der Name nicht erneut angegeben werden, da die Klasse nun die Daten (also den Index im Array) des letzten Zugriffs speichert.
[+] Int64: Read/WriteInteger speichert/liest nun Int64-Werte
[*] Die ReadInteger/Bool/Float-Funktionen lösen bei einem Konvertierungsfehler nun keine Exception mehr aus, sondern geben einen Standardwert zurück (0, false, 0.0)
[*] Ein paar unwichtige Optimierungen
[*] Die Exception-Typen EIniSectionNotFound und EIniValueNotFound wurden zu EIniEntryNotFound zusammengefasst.

Ich werde, sobald wie möglich, eine Funktion zum speichern der Kommentare schreiben. Die Formatierungen wie führende Leerzeichen und Leerzeilen (ohne Kommentarzeichen) würde ich dann aber außer Acht lassen.

_________________
Religionskriege sind nur Streitigkeiten darüber, wer den cooleren imaginären Freund hat ;-)


Zuletzt bearbeitet von Silas am Sa 29.03.08 15:44, insgesamt 1-mal bearbeitet
Silas Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 478

Windows XP Home
Delphi 2005, RAD Studio 2007, MASM32, FASM, SharpDevelop 3.0
BeitragVerfasst: Mo 04.02.08 12:22 
Nochmal ein Neues Release (Version 2.1):
[+] RenameSection/RenameValue-Funktionen: Benennen Eigenschaften und Funktionen um
[+] WriteString/ReadString escaped wenn auch Kommentarzeichen (zu \c)
[*] Bugfix: Ein Bug, der das Einlesen von gleichnamigen Eigenschaften in verschiedenen Sektionen verhindert hat, wurde behoben
[*] Ein paar unwichtige (Architektur-)Veränderungen

Download im ersten Posting.

Ich schreib gerade an der Kommentar-Funktion, erweist sich allerdings als schwierig.

_________________
Religionskriege sind nur Streitigkeiten darüber, wer den cooleren imaginären Freund hat ;-)


Zuletzt bearbeitet von Silas am Sa 29.03.08 15:44, insgesamt 1-mal bearbeitet
Gahero
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 193

Win Vista HP 64bit
Delphi 2007 Pro
BeitragVerfasst: Di 05.02.08 15:35 
Geile Sache.
Bin gerade am überlegen, ob ich mein Projekt, was demnächst mal wieder eine Frischzellenkur braucht auf Fastinifiles umzustellen. Gibts noch andere Vorteile außer bessere Geschwindigkeiten bei größeren Datenmengen und speichern von anderen Datentypen?
Silas Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 478

Windows XP Home
Delphi 2005, RAD Studio 2007, MASM32, FASM, SharpDevelop 3.0
BeitragVerfasst: Di 05.02.08 16:22 
user profile iconGahero hat folgendes geschrieben:
Geile Sache.
Bin gerade am überlegen, ob ich mein Projekt, was demnächst mal wieder eine Frischzellenkur braucht auf Fastinifiles umzustellen.

Danke. Freut mich sehr.

user profile iconGahero hat folgendes geschrieben:
Gibts noch andere Vorteile außer bessere Geschwindigkeiten bei größeren Datenmengen und speichern von anderen Datentypen?

  • Mehr Bearbeitungsmöglichkeit(en): Eine Rename- und eine Clear-funktion (ich weiß nicht, ob es letztere auch in TIniFile gibt, kann sein)
  • Du musst weniger tippen :) (Wegen der Funktion des automatischen letzten Zugriffs)
  • FastIniFiles wird weiterentwickelt!

_________________
Religionskriege sind nur Streitigkeiten darüber, wer den cooleren imaginären Freund hat ;-)
Heiko
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3169
Erhaltene Danke: 11



BeitragVerfasst: Di 05.02.08 18:14 
Hallo Silas,

es gibt eine Stelle, dir mir bei OpenSource-Units immer gleich einfällt, wo eine Fehlerstelle ist ;).

Versuch mal eine ini zu öffnen, wo der Pfad folgendermaßen ist ;):

ausblenden Quelltext
1:
C:\Нас Не Дагонят\test.ini					


Wie du dort sehen wirst, scheitert deine Unit daran. UniCode-Support wäre also nicht schlecht (ich hab hier in der Sparte ne Unit dafür liegen, falls du die verwenden möchtest. Alternativ kannste ja auch einen constructor für TFile anbieten, so dass er die Daten auch von MemoryStreams annehmen kann).
Silas Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 478

Windows XP Home
Delphi 2005, RAD Studio 2007, MASM32, FASM, SharpDevelop 3.0
BeitragVerfasst: Di 12.02.08 20:05 
Danke für die Antwort! Die Idee mit den Streams ist interessant, aber der Destruktor muss das Ganze ja wieder speichern können... Soll ich dann einfach dem Destruktor einen Parameter geben, oder wie hast du das gemeint?

_________________
Religionskriege sind nur Streitigkeiten darüber, wer den cooleren imaginären Freund hat ;-)
Heiko
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3169
Erhaltene Danke: 11



BeitragVerfasst: Di 12.02.08 20:22 
Wenn man im constructor einen Stream übergibt, erhält man ja eigentlich nur eine Referenz, mit der du arbeitren kannst. Diese behällst du dir als private-Var in der Klasse. Sobald der destructor aufgerufen wird, verwendest du die einfach weiter. Das birgt zwar ein paar mögliche Fehlerstellen (ein anderer gibt hat die Klasse bereits freigegeben), aber es gibt eben immer Schwachpunkte ;). Du kannst natürlich dem destructor auch eine Variable geben. Nimm einfach das, was dir am besten gefällt.
Silas Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 478

Windows XP Home
Delphi 2005, RAD Studio 2007, MASM32, FASM, SharpDevelop 3.0
BeitragVerfasst: Di 12.02.08 20:45 
Das war das Problem, das ich gemeint habe. Ich denke, ich werde jetzt erst einmal den Unicode-Support aus deiner Unit (mit internem Stream natürlich) und dann vielleicht einen Read-Only-Modus für Streams schreiben. Lassen sich z.B. Resource-Streams überhaupt schreiben?

_________________
Religionskriege sind nur Streitigkeiten darüber, wer den cooleren imaginären Freund hat ;-)
Heiko
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3169
Erhaltene Danke: 11



BeitragVerfasst: Di 12.02.08 21:16 
user profile iconSilas hat folgendes geschrieben:
Ich denke, ich werde jetzt erst einmal den Unicode-Support aus deiner Unit (mit internem Stream natürlich)

Ich werde die Woche dafür sicherlich ein Update rausbringen, womit das umstellen auf TStream nur noch ein minimaler Compilierschalter ist (habs gerade auf die schnelle probiert, aber Borland nutzt an der einen Stelle Int64, wo ich nur Cardinal nutze, wes wegen ich an ein paar Stellen mehr den Compilierweichen einbauen muss).

user profile iconSilas hat folgendes geschrieben:
und dann vielleicht einen Read-Only-Modus für Streams schreiben.

Wäre eine Möglichkeit. An der Stelle vlt. einen alterativen Destruktor anbeiten, der das auch dann schreiben kann.

user profile iconSilas hat folgendes geschrieben:
Lassen sich z.B. Resource-Streams überhaupt schreiben?

Du meinst bezüglich meiner Unit? Wenn du die auf TStreams basieren lässt wahrscheinlich. Ich habs bisher nicht gebraucht, von daher auch nicht getestet ;).
Silas Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 478

Windows XP Home
Delphi 2005, RAD Studio 2007, MASM32, FASM, SharpDevelop 3.0
BeitragVerfasst: Di 12.02.08 22:56 
user profile iconHeiko hat folgendes geschrieben:
Ich werde die Woche dafür sicherlich ein Update rausbringen, womit das umstellen auf TStream nur noch ein minimaler Compilierschalter ist.

Ich hätte gedacht das wär schon so? Oder war es gar nicht die, die du gemeint hast?

user profile iconHeiko hat folgendes geschrieben:
user profile iconSilas hat folgendes geschrieben:
Lassen sich z.B. Resource-Streams überhaupt schreiben?

Du meinst bezüglich meiner Unit? Wenn du die auf TStreams basieren lässt wahrscheinlich. Ich habs bisher nicht gebraucht, von daher auch nicht getestet ;).

Nein, ich meine TResourceStream, mit dem man auf Ressourcen zugreifen kann. Ich denke nicht, dass man auf so einen Stream (wirklich) schreiben kann, oder? Schließlich ist die Resource ja in der EXE verankert...

Das mit dem alternativen Destruktor werd ich wahrscheinlich so machen :) .

_________________
Religionskriege sind nur Streitigkeiten darüber, wer den cooleren imaginären Freund hat ;-)
Heiko
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3169
Erhaltene Danke: 11



BeitragVerfasst: Mi 13.02.08 08:12 
user profile iconSilas hat folgendes geschrieben:
Oder war es gar nicht die, die du gemeint hast?

Doch die meine ich ;). Wenn ich dich richtig verstanden habe, willst du ja als Grundobjekt nicht TObject haben, sondern TStream. Um beide Variante zu erlauben, kommt demnächst ein Compilierschalter rein, da ich TStrea,m bisher außebn vorgelassen habe.

user profile iconSilas hat folgendes geschrieben:
Nein, ich meine TResourceStream, mit dem man auf Ressourcen zugreifen kann.

Achso, den muss ich mir mal angucken. Ich hab schon eigentlich geguckt, ob in Classes ein weiterer Stream ist, aber den habe ich wohl übersehen ;).
Silas Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 478

Windows XP Home
Delphi 2005, RAD Studio 2007, MASM32, FASM, SharpDevelop 3.0
BeitragVerfasst: Mi 13.02.08 17:23 
user profile iconHeiko hat folgendes geschrieben:
user profile iconSilas hat folgendes geschrieben:
Oder war es gar nicht die, die du gemeint hast?

Doch die meine ich ;). Wenn ich dich richtig verstanden habe, willst du ja als Grundobjekt nicht TObject haben, sondern TStream. Um beide Variante zu erlauben, kommt demnächst ein Compilierschalter rein, da ich TStrea,m bisher außebn vorgelassen habe.

Nein, nein, ich will schon TObject als Elternklasse lassen, nur den Konstruktor umschreiben, dass er mit Streams arbeitet, und anschließend diesen wieder für Dateien überladen, dass der Parser selbst also nur noch mit Streams arbeitet. Denk ich, wäre sinnvoller, weil ja ein Parser (als Klasse) nicht viel mit Streams am Hut hat und ich sonst die ganzen Read / Write Methoden überladen muss, bloß mit was? :wink:

_________________
Religionskriege sind nur Streitigkeiten darüber, wer den cooleren imaginären Freund hat ;-)