|
Antwort |
Olli
(Gast)
n/a Beiträge |
#21
Zitat von negaH:
2.) wir schauen in die Geschichte der Computerei, und stellen fest das sich eben fast NIE das durchgesetzt hat was das Beste darstellte. Es setzte sich immer das durch was im allgmeinen Interesse rundum praktisch war. Also das was sich auch gut vermarkten lässt, was Profit bringen wird und denoch technisch einigermaßen gelungen war. Also nicht das was hypothetisch supergut war aber zb. keinerlei Lobby dahinter hatte.
Beispiel: In der Firma, auf die ich anspiele, werden 2 Systeme eingesetzt um die Oberfläche für Kontrollstationen in Fabriken zu designen. Nun ist es so, daß ich mich krampfhaft an dem Design der einen (in der Firma beliebteren) Software orientieren mußte und deshalb in zahlreiche Schwierigkeiten kam. Stattdessen wäre es möglich gewesen eine Bibliothek aus für beide Systeme einheitlichen ActiveX-Controls zu erstellen, die dann für ein einheitliches Aussehen und "corporate identity" gesorgt hätten. Das ist ist aber unbeliebt, weil man es nicht direkt an den Kunden weitergeben kann (bzw. dann bei einer Ausschreibung schlechter dasteht).
Zitat von negaH:
Exception ansich sind ein sehr wichtiges Mittel der Programmierung geworden. Sie stellen sozusagen einen parallel zum eigentliche Programablauf feststehenden Programmablaufplan dar. Und exakt in dieser Parallelität sehe ich auch gleichzeitig die Schwäche der Exceptions. Denn im Denkvermögen der meisten Programmierer stellt sich ein Program am einfachsten als simple und rein sequientielle Steuerung dar.
Zitat von negaH:
1.) wenn Exception dann aber auch immer try finally benutzen um resourcen zu schützen, das verringert die Anzahl unerwünschter Nachfolgefehler falls eine Exception/Event asynchron den Programfluß unterbricht.
Zitat von negaH:
2.) Wissen, die Programmierer habe zu lernen wie asynchrone Programme per Exceptions/Events zu arbeiten haben
Zitat von negaH:
3.) Beschränkungen, durch willkürlich Beschränkungen auf gemeinsam benutzte und Firmeninterene Vorgaben im Arbeitsstil.
Zitat von negaH:
4.) das Eintreffen/Auslösen solche asynchrone Exceptions/Events möglichst reduzieren.
Zitat von negaH:
Nichts ist schlimmer wenn eine solche Funktion tief im Inneren eines Programmes ständig Exceptions auslösst.
Zitat von negaH:
Nun führen wir aber in diese Funktion in deren Implementation eine Exception ein. Wird diese ausgelösst so zerstört sie das Black-Box-Prinzip denn WIR SEHEN diese Exception NICHT in der Schnittstelle !!??
Zitat von negaH:
Exception sind also einerseits ein produktives Mittel aber andererseits ein möglicherweise kontrapoduktives Design da sie aus Sicht der Schnittstelle nicht sichtbar sind.
Zitat von negaH:
[...] oder aber der Programmiere beginnt wild umsich zu try except'en und zerstört somit im Grunde den Nutzen der Exceptions.
Der letzte fängt die Exception
Zitat von negaH:
Das sind die Folgen eines schlechten Designes, und die Ursache liegt darin begründet das wir in der Schnittstelle unserer Funktionen/Merthoden etc. pp. eben nicht SEHEN welche Exception zu erwarten sind.
Um es auf einen Punkt zu bringen Für mich gehören try-except-Blöcke in die OOP-Welt und try-finally-Blöcke in die PP-Welt. Daß sie bei Delphi vermischt auftreten, haben wir der Tatsache zu verdanken, daß sie Objekte in Delphi nicht wie Stackvariablen verhalten (man sie also explizit freigeben muß, was oft in try-finally-Blöcken geschieht). Nichts dagegen, daß dies überhaupt möglich ist (auch in C++ kann ich über Objektzeiger gehen), aber in Delphi gibt es eben nur diese eine Möglichkeit. Ich gehe aber davon aus, daß Delphi.NET dafür eine Antwort hat. Robert_G? Anwesend? Sag mal was Korrektur: Natürlich geht es auch in Delphi (nämlich mit Interfaces), aber eben nur über Umwege. Und wenn jetzt irgendjemand kommt und das unsägliche object vorschlägt, dann bin ich aber raus aus der Diskussion. Das existiert bekanntlich nur für die Kompatibilität mit älteren Quelltexten. EDIT2: jbg's Einwand eingearbeitet. |
Zitat |
Registriert seit: 12. Jun 2002 3.483 Beiträge Delphi 10.1 Berlin Professional |
#22
Zitat von Olli:
Und wenn jetzt irgendjemand kommt und das unsägliche TObject vorschlägt, dann bin ich aber raus aus der Diskussion. Das existiert bekanntlich nur für die Kompatibilität mit älteren Quelltexten.
Natürlich bietet Delphi.NET da eine Möglichkeit: Das .Free einfach weglassen (sofern die Klasse kein Dispose() braucht). Um auf das angeben von Exceptions im Interface zu kommen. Java hat dies in die Syntax eingebaut: "void bla() throws MyException". Das macht meines erachtens aber nur solange Sinn, wie man die Exceptions direkt vor Ort behandelt. Denn wenn man die nun durchzuschleifen probiert, hat man das Problem, dass man bei allen Methoden das throws anpassen muss, was bei größeren Projekten (mit einer kleinen Änderung im Kern: neue Exception) dann zu einer Sisyphusarbeit ausartet.
Andreas aka AHUser aka jbg
Mein Blog - kombiniert mit all meinen Delphi Tools |
Zitat |
Registriert seit: 25. Jun 2003 Ort: Thüringen 2.950 Beiträge |
#23
Hi Olli,
es ist schwer eine solche Grundsatzdiskussion über das Netz zu führen. Lieber würde ich sowas in einer persönlichen Diskussion klären. Denn im Grunde vertreten wir ähnliche Ansichten, der Unterschied zwischen uns besteht nur darin aus welchem Winkel wir die Problematik betrachten und was für Schlüsse wir letzendlich daraus ziehen.
Zitat:
Aber es reicht doch an sich für den Programmierer die Erkenntnis, daß er eine Exception nicht am Ort des Auftretens behandeln muß ....
In beiden Fällen bedeutet ein solcher "Vorgang" eben Zeit, somit Geld und Nerven. Das verkompliziert sich noch wenn man nun Funktionen benutzt die wiederum Funktionen benutzen die im Grunde alle eine Exception auslösen können. Ergo: Der Programmierer müsste auf Grund der fehlenden Information wo und wann Exceptions ausgelösst werden entweder die "auf Nummer sicher gehen Methode" anwenden und alle Exceptions permanent abfangen, oder aber die "Ignorieren Methode" und verzichtet auf die aktive Einflußnahme des Programmablaufes beim Eintreffen einer Exception. BEIDES ist aber kontraproduktiv, denn ein programmiertes Feature macht nur dann effektiv Sinn wenn es mir Arbeit abnimmt und einsparrt, und nicht zus. Zeit kostet weil es im Grunde in der Schnittstelle undokumentiert ist. Und schwups sind wir bei der Dokumentation. Ein sauberer Source sollte komplett ohne Doku auskommen können, denn warum sollte Goethe ein Buch schreiben um eine Dokumentation zum Lesen eines seiner anderen Bücher zu haben. Das ist doch idtiotisch, und im übertragenen Sinne ist es noch idiotischer auf einen Source bezogen. Denn in dieser Form der Sprache haben WIR die Regeln festgelegt und diese Regeln arbeiten immer nach dem Prinzip einer öffentlichen Schnittstellendeklaration und einer Black Box Implementation. Leider verstoßen aber immer mehr OOP Ansätze exakt gegen dieses Konzept. Exceptions sind nicht in der Methoden/Funktions Deklaration kenntlich gemacht, sie werden innerhalb der Black Box ausgelösst. Aus diesem Grunde geht der Vorteil der Schnittstelle und dem Black Box Prinzip kaputt denn der Entwickler muß nun doch wissen ob innerhalb der Black Box eine Exception auftreten kann. Ergo: der Source muß dies separat dokumentieren, er wird also auf Grund seiner Schnittstellen Deklaration nicht mehr selbsterklärbar sein, und schwups wieder ein alter Vorteil verloren. Ich möchte hier nicht gegen Exceptions argumentieren, sondern eher das dahinterliegende Konzept im Gesamtkonzept der Programmiermethoden analysieren. Und deshalb meinte ich eingangs das Exception tatsächlich in jedlicher Weise eine Ausnahme darstellen. Der Grad ihrer Nützlichkeit ist also sehr schmal für uns Programmierer. Gruß Hagen |
Zitat |
Registriert seit: 9. Jun 2005 Ort: Unna 1.172 Beiträge Delphi 10.2 Tokyo Professional |
#24
Jetzt gebe ich auch noch mal meinen Senf dazu (obwohl ich den immer noch nicht mag...)
1. Bedeutung des Begriffs Exception Für mich widerspricht es dem eigentlichen Sinn wenn man Exceptions dazu benutzt, einfache Fehlerbedingungen zu signalisieren. Für mich ist eine Exception im wörtlichen Sinne eine Ausnahmebedingung: eine Programmzustand, in dem nicht mehr mit der normalen Ausführung fortgefahren werden kann. Nicht genug Speicher, unzureichende Systemresourcen, die CD mit der EXE-Datei des Programms wurde aus dem Laufwerk genommen oder ähnliches, und sicher auch Programmierfehler wie fehlerhafte Indizes. Ganz bestimmt aber nicht so etwas wie ein einfacher Fehlerzustand. Der kann zwar stellenweise asynchron auftreten, also ohne direkten Bezug zur aktuell aufgerufenen Prozedur, aber ich denke das ist kein Grund aus einem Ereignis (-> Event) eine Exception (-> Ausnahmebedingung) zu machen. 2. Was der "normale" Programmierer daraus macht In meinen Augen macht ein Block wie
Delphi-Quellcode:
überhaupt keinen Sinn - da kann ich die Exception auch gleich bis zum obersten Level durchschlagen lassen, dort wird nämlich auch einfach eine Meldung ausgegeben. Diese Form sieht man aber am häufigsten. Noch schlimmer ist, dass die meisten Programmierer dann den Fehler machen, einfach im Code fortzufahren als ob nichts geschehen wäre, der try-except Block in diesem Fall also gerade eine Dummheit ist.
try
TueIrgendWas; except on E: Exception do MessageDlg(E.Message, mtError, [mbOk], 0); end; 3. Was ich daraus mache Persönlich benutze ich Exception-Handling fast ausschließlich für try-finally Blöcke zum Ressourcenschutz. Nur an bestimmten Stellen verwende ich try-except und zwar dort, wo ich mit einem möglichen Fehlschlagen rechne. Z.B. wenn ich ein TFileStream ohne vorherige Abfrage mit FileExists öffne, was ja sowieso wenig Sinn macht, denn es kann ja sein dass es die Datei gibt aber ich sie trotzdem nicht öffnen darf. 4. Der Nutzen Praktisch finde ich durchaus, dass SEH den Sourcecode übersichtlicher macht. Ich finde z.B. die erste Variante wesentlich besser zu lesen als die zweite:
Delphi-Quellcode:
Ich kann mich noch gut an die ersten Code-Beispiele von Microsoft zur Windows-API / GDI-Programmierung erinnern, wo hinter jedem Prozeduraufruf (GetDC, CreateBrush, SelectObject, DeleteObject, ReleaseDC) immer wieder der ganze Salmon hing, also jedesmal eine separate Fehlerbehandlung mit abschließendem return. Ich denke da ist SEH die bessere Alternative.
procedure Variante1;
begin TueDies; TueDas; if StimmtDas then TueIrgendWas else TueWasAnderes; // Kein Rückgabewert notwendig, Exception // schlägt durch in die aufrufende Routine end; function Variante2: boolean; begin if TueDies <> 0 then Result = false //<-- 1 signalisiert Fehler else if TueDas in [0, 7, 24] then Result = false //<-- 0 = nicht gefunden, 7 = zu groß, 24 = zu alt else case StimmtDas of 5, 13: Result = false; //<-- Fehlercodes 1: Result := TueIrgendWas = 1; 0: Result := TueWasAnderes = 0; end; end; <Vorbehalt="Muss ich noch mal genau drüber nachdenken"> 5. Exceptions zur Fehlerbehandlung Um eine Exception für die normale Fehlerbehandlung zu "missbrauchen" fehlt ein ganz wichtiges Feature, nämlich das Fortfahren an der Fehlerstelle. Im Grunde so etwas wie das "Resume Next" in Visual Basic. Dann könnte man nämlich in Fällen wie beim "EConnectionClosedGracefully" den Fehler dankend zu Kenntnis nehmen und an der alten Stelle fortfahren. </Vorbehalt> Hinweis: Nachträglich noch etwas editiert, um es strukturierter aussehen zu lassen
Volker
|
Zitat |
Olli
(Gast)
n/a Beiträge |
#25
Zitat von jbg:
Du meinst wohl object. TObject ist bei Delphi eine class.
Zitat von jbg:
Um auf das angeben von Exceptions im Interface zu kommen. Java hat dies in die Syntax eingebaut: "void bla() throws MyException".
Zitat von jbg:
as macht meines erachtens aber nur solange Sinn, wie man die Exceptions direkt vor Ort behandelt. Denn wenn man die nun durchzuschleifen probiert, hat man das Problem, dass man bei allen Methoden das throws anpassen muss
Zitat von jbg:
was bei größeren Projekten (mit einer kleinen Änderung im Kern: neue Exception) dann zu einer Sisyphusarbeit ausartet.
Nochmal mein Beispiel. Ich habe eine Molekülklasse geschrieben, die intern sog. Tripods ("Dreibeine") benutzt um 2 Atome und 3 Bindungen darzustellen. Nach außen ist das nicht sichtbar. Im Sinne der Effizienz ist es nun so, daß man von außen auf beliebige Bindungen oder Atome zugreifen kann (auch nichtexistente!). Intern ist es wie gesagt ein 2D-Array dieser Tripods. Ist der Zugriff nicht erfolgreich ("out of range") behandele ich die Exception lokal und erweitere das Array und ggf. erstelle ich das vorher nicht vorhandene Tripod-Objekt. Hier werden Exceptions sehr sinnvoll eingesetzt und sind nach außen nicht sichtbar.
Zitat von negaH:
es ist schwer eine solche Grundsatzdiskussion über das Netz zu führen. Lieber würde ich sowas in einer persönlichen Diskussion klären. Denn im Grunde vertreten wir ähnliche Ansichten, der Unterschied zwischen uns besteht nur darin aus welchem Winkel wir die Problematik betrachten und was für Schlüsse wir letzendlich daraus ziehen.
Zitat von negaH:
BEIDES ist aber kontraproduktiv, denn ein programmiertes Feature macht nur dann effektiv Sinn wenn es mir Arbeit abnimmt und einsparrt, und nicht zus. Zeit kostet weil es im Grunde in der Schnittstelle undokumentiert ist.
Zitat von negaH:
Und schwups sind wir bei der Dokumentation. Ein sauberer Source sollte komplett ohne Doku auskommen können
Zitat von negaH:
Denn in dieser Form der Sprache haben WIR die Regeln festgelegt und diese Regeln arbeiten immer nach dem Prinzip einer öffentlichen Schnittstellendeklaration und einer Black Box Implementation.
Allein die Wahl eines Methodennamens muß ja nicht sonderlich clever sein. Wenn die Dokumentation existiert ist's aber kein Problem.
Zitat von negaH:
Aus diesem Grunde geht der Vorteil der Schnittstelle und dem Black Box Prinzip kaputt denn der Entwickler muß nun doch wissen ob innerhalb der Black Box eine Exception auftreten kann. Ergo: der Source muß dies separat dokumentieren, er wird also auf Grund seiner Schnittstellen Deklaration nicht mehr selbsterklärbar sein, und schwups wieder ein alter Vorteil verloren.
Zitat von negaH:
Ich möchte hier nicht gegen Exceptions argumentieren, sondern eher das dahinterliegende Konzept im Gesamtkonzept der Programmiermethoden analysieren. Und deshalb meinte ich eingangs das Exception tatsächlich in jedlicher Weise eine Ausnahme darstellen. Der Grad ihrer Nützlichkeit ist also sehr schmal für uns Programmierer.
|
Zitat |
Olli
(Gast)
n/a Beiträge |
#26
Keine rote Box. Sorry, will dich natürlich nicht ignorieren
Ich stimme in den Punkten 1-4 vollständig mit dir überein.
Zitat von Flocke:
Ich kann mich noch gut an die ersten Code-Beispiele von Microsoft zur Windows-API / GDI-Programmierung erinnern, wo hinter jedem Prozeduraufruf (GetDC, CreateBrush, SelectObject, DeleteObject, ReleaseDC) immer wieder der ganze Salmon hing, also jedesmal eine separate Fehlerbehandlung mit abschließendem return. Ich denke da ist SEH die bessere Alternative.
Zitat von Flocke:
Um eine Exception für die normale Fehlerbehandlung zu "missbrauchen" fehlt ein ganz wichtiges Feature, nämlich das Fortfahren an der Fehlerstelle. Im Grunde so etwas wie das "Resume Next" in Visual Basic. Dann könnte man nämlich in Fällen wie beim "EConnectionClosedGracefully" den Fehler dankend zu Kenntnis nehmen und an der alten Stelle fortfahren.
Aber wenn wir schon bei Windows' SEH sind. Das bietet das. Nur die meisten Compiler machen nicht komplett Gebrauch von allen Features (bzw. reichen nicht alle zum Benutzer/Programmierer durch). Genaugenommen kannst du an einer beliebigen Stelle deines Codes mit beliebiger Registerbelegung fortfahren. Wenn die Exception aber vorher durchschlug, wurde der Stack schon aufgeräumt, will heißen ein Fortfahren ist nicht ohne weiteres möglich. Der Stack müßte gesichert und wiederhergerstellt werden um das zu ermöglichen. |
Zitat |
Registriert seit: 25. Jun 2003 Ort: Thüringen 2.950 Beiträge |
#27
Hi Olli
Zitat:
Zitat:
Denn in dieser Form der Sprache haben WIR die Regeln festgelegt und diese Regeln arbeiten immer nach dem Prinzip einer öffentlichen Schnittstellendeklaration und einer Black Box Implementation.
Allein die Wahl eines Methodennamens muß ja nicht sonderlich clever sein. Wenn die Dokumentation existiert ist's aber kein Problem.
Zitat:
Zitat:
Aus diesem Grunde geht der Vorteil der Schnittstelle und dem Black Box Prinzip kaputt denn der Entwickler muß nun doch wissen ob innerhalb der Black Box eine Exception auftreten kann. Ergo: der Source muß dies separat dokumentieren, er wird also auf Grund seiner Schnittstellen Deklaration nicht mehr selbsterklärbar sein, und schwups wieder ein alter Vorteil verloren.
Nein. Es sollte garkeine Dokumentation geben, das wäre am besten !! Die Programmier-Sprache sollte auf jegliches Element das eine Information zu einer Information liefert verzichten. Denn es kann niemals eine Information zu einer Information geben, das ist unlogisch. Die eigentliche Information verkommt zu einer redundanten und schon bekannten Nachricht. Eine zusätzliche Dokumentation eines Sources wäre vergleichbar mit einer Information zu einer Nachricht. Eine Nachricht enthält aber keine für uns neue und nützliche Information. Somit wird der eigentlich geschrieben Source zu einer belanglosen Nachricht und IN der Dokumentation steckt eigentlich exakt das drinnen an Information die in den Source gehören würde. Der Programmierer hat geschlampt. Die IDEALE Programmier-Sprache ist eine Sprache die ein Problem für die Machine und den Menschen absolut ohne zus. Informationen in Form von Dokumentationen erklärbar und verständlich macht. Schau mal, auch wir brauchen in unserer natürlichen Sprache keine zusätzliche Sprache um das was wir ausdrücken wollen nochmals in dieser zus. Sprache, genannt Dokumentation, deutlich auszudrücken. Wir benötigen nur eine Sprache und mehr nicht. Wir sollten und werden eines Tages in einer Programmiersprache programmieren die exakt diesen Forderungen entspricht und sehr sehr ähnlich zu unserer natürlichen Sprache funktioniert. Aber am wesentlichsten an dieser Sprache wird es sein das es keine Nachrichten gibt, sprich sie wird in jeder Quelltextzeile absolute Information enthalten, ohne Redundanz und ohne Nachrichten. Man kann sich nun streiten ob eine Dokumentation zu einem Source + dem Source ein komplettes Program darstellt, sprich zwei untrennbare Bestandteile des Programmes sind. Ich behaupte mal nicht, denn nur der eigentliche Source stellt den Ablaufplan des Programmes dar. Die ideale Sprache würde also reinen Source enthalten und denoch wäre dieser Source gleichmaßen ideal verständlich für uns Menschen und gleichermaßen ideal übertragbar auf eine Machine. Gruß Hagen |
Zitat |
Olli
(Gast)
n/a Beiträge |
#28
Zitat von negaH:
Nein. Es sollte garkeine Dokumentation geben, das wäre am besten !!
Zitat von negaH:
Die Programmier-Sprache sollte auf jegliches Element das eine Information zu einer Information liefert verzichten. Denn es kann niemals eine Information zu einer Information geben, das ist unlogisch.
Zitat von negaH:
Die eigentliche Information verkommt zu einer redundanten und schon bekannten Nachricht.
Zitat von negaH:
Man kann sich nun streiten ob eine Dokumentation zu einem Source + dem Source ein komplettes Program darstellt, sprich zwei untrennbare Bestandteile des Programmes sind. Ich behaupte mal nicht, denn nur der eigentliche Source stellt den Ablaufplan des Programmes dar. Die ideale Sprache würde also reinen Source enthalten und denoch wäre dieser Source gleichmaßen ideal verständlich für uns Menschen und gleichermaßen ideal übertragbar auf eine Machine.
|
Zitat |
Registriert seit: 1. Apr 2005 Ort: Bad Tölz 4.149 Beiträge Delphi 2006 Professional |
#29
Ich finde Exceptions sind eine gute waffe gegen Funktionen mit booleschem Rückgabewert
Wenn in der JVCL bei den Indies aber "Verbindung erfolgreich geschlossen" eine Ausnahme darstellt, würde ich mir überlegen, warum ich diese komponenten benutze( ) - am Ende sind wir bei Java, wo ja gelegentlich "Fatal Error: No Error" gemeldet werden soll... Eigentlich wollte ich ja auf die redundanz zu sprechen kommen: Redundanz ist gut, wenn es um komplexe zusammenhänge geht, bei denen hintergrundinfo hilft. redundanz ist schlecht, wenn es um bandbreite geht Natürlich wäre ein Programmierstil, der keine Dokumentation mehr verlangt, ideal. Aber würde das nicht in deskriptiven Sprachen(ergo Overhead=Redundanz), oder zumindest in Funktuionsdeklarationen wie function A_und_B_werden_und_addiert_ausgegeben(A,b:integer):integer enden? ohne redundanz geht es nicht - ob jetzt mit oder ohne Kommentaren, Dokumentation oder anschaulichen Funktionsnamen. Denn ist nicht schon add(a,b:integer):integer ein enormer overhead? viel effektiver wäre doch f 372(x,y:2):2, oder? aber wie bereits gesagt: je komplexer das thema/die methode, desto mehr redundanz braucht der mensch. Auch wenn der Code noch so schön eingerückt ist, solange man nicht Neo heisst, wird man kaum aus dem reinen Lesen des Quellcodes das Programm vor sich Ablaufen sehen. Zumindest bei genügender Komplexität des Problems. ich fasse zusammen: Soviel Redundanz wie nötig, so wenig Dokumentation wie möglich. Aber bitte nicht auf koreanisch EDIT: sachlichen fehler korrigiert. Sorry an die JVCL
Lukas Erlacher
Suche Grafiktablett. Spenden/Gebrauchtangebote willkommen. Gotteskrieger gesucht! For it is the chief characteristic of the religion of science that it works. - Isaac Asimov, Foundation I, Buch 1 |
Zitat |
Ansicht |
Linear-Darstellung |
Zur Hybrid-Darstellung wechseln |
Zur Baum-Darstellung wechseln |
ForumregelnEs 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
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
LinkBack URL |
About LinkBacks |