Deutsches AutoHotkey Homepage AutoHotkey Community
Wir helfen uns gegenseitig aus der Patsche
 
 FAQFAQ   SuchenSuchen   MitgliederlisteMitgliederliste   RegistrierenRegistrieren 
 ProfilProfil   Einloggen, um private Nachrichten zu lesenEinloggen, um private Nachrichten zu lesen   LoginLogin 

[Funktion] DelSpaces(str)
Gehe zu Seite Zurück  1, 2, 3  Weiter
 
Neues Thema eröffnen   Neue Antwort erstellen    AutoHotkey Community Foren-Übersicht -> Skripte & Funktionen
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen  
Autor Nachricht
haichen



Anmeldedatum: 10.06.2007
Beiträge: 92

BeitragVerfasst am: Fr Feb 29, 2008 1:21 am    Titel: Antworten mit Zitat

Selbst wenn Chuckys code so funktionieren würde (sorry!) dann ist er noch doppelt so langsam wie der bisherige Testsieger von DerRaphael (und meine kleine Abwandlung).

Meine erste Version im englischen Forum (noch etwas konfus) ist allerdings um den Faktor 20 langsamer.

Ich hab hiernoch eine Abwandlung nach Laszlo, nur mit StringReplace.
Aber auch ein erstes und letztes Leerzeichen um den String wird entfernt:
Code:

delsp1(s){
 StringReplace, s, s,%a_tab%,%a_space%, All
 StringReplace s, s, %A_Space%                   %A_Space%, %A_Space%, All ; 21
 StringReplace s, s, %A_Space%    %A_Space%, %A_Space%, All ; 6
 StringReplace s, s, %A_Space% %A_Space%, %A_Space%, All ; 3 -> 1
 StringReplace s, s, %A_Space%%A_Space%, %A_Space%, All  ; 2 -> 1
 StringReplace s, s, %A_Space%%A_Space%, %A_Space%, All  ; 2 -> 1
 s =%a_space%%a_space%%s%%a_space%%a_space%
 StringReplace, s, s,%a_space%%a_space%%a_space%,,all
 StringReplace, s, s,%a_space%%a_space%,,all
return %s%
}


Und der Klopper ist dennoch schneller als die Regular Expressions.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
denick



Anmeldedatum: 15.09.2006
Beiträge: 1199
Wohnort: Berlin

BeitragVerfasst am: Sa März 01, 2008 12:50 pm    Titel: Antworten mit Zitat

Moin,

das hat mir natürlich keine Ruhe gelassen. Wink

Nach vielem Probieren lassen sich für das gegebene Problem mehrere Feststellungen treffen:

1. Die relative Performance des RegEx sinkt mit der Komplexität des Suchausdrucks.
2. Die relative Performance des RegEx sinkt mit der Länge des Suchstrings.
3. Der RegEx wird relevant stärker vom umgebenden System beeinflusst (CPU, RAM, andere Tasks).
4. Der RegEx profitiert in diesem Fall durchaus von der Option S(tudy).

In diesem Beispiel werden ja nicht komplette Dateiinhalte sondern nur einfache Zeichenfolgen verarbeitet. Die Strings in DerRaphael's Benchmark sind deshalb meiner Meinung nach untypisch lang (obwohl die u.a. Funktion auch dort gewinnen kann). Nach Tests auf zwei recht unterschiedlichen Rechnern hat dann letztlich folgende Funktion gewonnen:

Code:
DelSp2(Str)
{
   StringReplace, Str, Str, %A_Tab%, %A_Space%, All
   Str := RegExReplace(Str, "S)\s+", " ")
   If (SubStr(Str, 1, 1) = " ")
      Str := SubStr(Str, 2)
   If (SubStr(Str, 0) = " ")
      Str := SubStr(Str, 1, -1)
   Return Str
}


Ohne S(tudy) schlägt sie sich auch nicht wirklich schlecht, verliert aber mit wachsender Stringlänge.

Und hier ist der passende Benchmark (trau keinem, den Du nicht selbst geschrieben hast):

Code:
#NoEnv
; SetBatchLines, -1

AutoTrim, Off
TxT := "`t`t  The `t`t   Quick Brown       Fox Jumps`tBrown   Over          the"
    .  "     Lazy            Dog`t"
Str := Txt
Erg := ""
; freq enthält qpc einheiten per sek
DllCall("QueryPerformanceFrequency", "int64*", Frequenz)
MsgBox, 0
      , Funktionsnachweis:
      , % "DelSp1: >" . DelSp1(Str) . "<`n`nDelSp2: >" . DelSp2(Str) . "<"

SetFormat, Float, 0.8

OL := 20       ; Äußere Schleife
IL := 10       ; Innere Schleife

Loop, %OL%
{
   VarSetCapacity(Out, StrLen(Str))
   Critical
   DllCall("QueryPerformanceCounter", "Int64*", Start)
   Loop, %IL%
   {
      Out := DelSp1(Str)
   }
   DllCall("QueryPerformanceCounter", "Int64*", Ende)
   Critical, Off
   T1 := (Ende - Start) / Frequenz / IL
   Critical
   DllCall("QueryPerformanceCounter", "Int64*", Start)
   Loop, %IL%
   {
      Out := DelSp2(Str)
   }
   DllCall("QueryPerformanceCounter", "Int64*", Ende)
   Critical, Off
   T2 := (Ende - Start) / Frequenz / IL
   Erg .= StrLen(Str) . "|" . T1 . "|" . T2 . "`n"
   Loop, %A_Index%
      Str .= TxT
}

Gui, Margin, 0, 0
Gui, Font, s10, Tahoma
Gui, Add, Text, , Äußere Schleife`t: %OL%`nInnere Schleife`t: %IL%
Gui, Add, ListView
   , Readonly NoSort NoSortHdr Grid R%OL% w400
   , Stringlänge  |Zeit DelSp1 | Zeit DelSp2 |DelSp2 `%
Loop, Parse, Erg, `n
{
   If (A_Index > OL) {
      Break
   }
   StringSplit, F, A_LoopField, |
   LV_Add("", F1, F2, F3, Round(F3 * 100 // F2))
}
LV_ModifyCol(1, "Center")

Gui, Show, , Durchschnittszeiten
Return

GuiClose:
GuiEscape:
ExitApp

DelSp1(Str)
{
   StringReplace, Str, Str, %A_Tab%, %A_Space%, All
   Loop,
      If (InStr(Str, "  "))
         StringReplace, Str, Str, %A_Space%%A_Space% ,%A_Space%, All
      Else
         Break
   If (SubStr(Str, 1, 1) = " ")
      Str := SubStr(Str, 2)
   If (SubStr(Str, 0) = " ")
      Str := SubStr(Str, 1, -1)
   Return Str
}

DelSp2(Str)
{
   StringReplace, Str, Str, %A_Tab%, %A_Space%, All
   Str := RegExReplace(Str, "S)\s+", " ")
   If (SubStr(Str, 1, 1) = " ")
      Str := SubStr(Str, 2)
   If (SubStr(Str, 0) = " ")
      Str := SubStr(Str, 1, -1)
   Return Str
}

_________________
Hilfe zur Hilfe

(de)nick
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
DerRaphael



Anmeldedatum: 09.01.2008
Beiträge: 1037
Wohnort: Zuhause

BeitragVerfasst am: Sa März 01, 2008 2:24 pm    Titel: Antworten mit Zitat

chapeau, denick Very Happy


_________________
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
haichen



Anmeldedatum: 10.06.2007
Beiträge: 92

BeitragVerfasst am: Sa März 01, 2008 7:20 pm    Titel: Antworten mit Zitat

Ja komisch das man sich an so etwas festbeißen kann. Aber geht mir auch so.

Ich hab mal in deinem Benchmark den outerloop mit
Process, priority, ,Realtime laufen lassen. Die Ergebnisse scheinen dann reproduzierbarer zu sein.
Very Happy
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Chucky



Anmeldedatum: 07.01.2006
Beiträge: 646
Wohnort: Powerland

BeitragVerfasst am: Sa März 01, 2008 10:37 pm    Titel: Antworten mit Zitat

Die Geschwindigkeit läßt sich noch ordentlich erhöhen, wenn man Maschinencode-Funktionen nutzt.

Diese Methode läuft natürlich außer Konkurrenz, denn sie benutzt nicht die üblichen AutoHotkey-Funktionen, wie DelSp1() und DelSp2().
Trotzdem ist sie erwähnenswert, da sie trotz ihrer hohen Geschwindigkeit komplett im Script integriert ist.

Grundlage ist die MCode-Funktion des genialen Laszlo aus dem amerikanischen Forum.
Man kann sich damit temporäre Maschinencode-Funktionen erzeugen, die naturgemäß wesentlich schneller sind als zu interpretierender Code.

Der Maschinencode läßt sich z. B. mit ziemlich jedem Compiler generieren, der DLLs erzeugen kann, z. B mit dem freien GNU-C-Compiler Dev-Cpp, den ich benutze.
Ich habe also eine DelSpaces-Funktion geschrieben (jetzt auch mit Tab->Space-Wandlung Smile) und in eine DLL kompiliert. Die DLL disassembliert man, um an den Hex-Code der Funktion zu kommen. Den Code aus dem Listing befreit man von Speicheradressen, Mnemonics, Spaces usw. und reduziert ihn damit auf den hexadezimalen Maschinencode.

MCode schreibt den Maschinencode, der in hexadezimaler Form im Script vorliegt, in eine Variable. AutoHotkey kann danach Smile diese Variable als Funktion benutzen, indem es sie mit DllCall() aufruft. Die Funktion verhält sich dann genauso wie eine mit DllCall("LoadLibrary", ins RAM geladene Funktion einer DLL.

@denick
Schönes, übersichtliches Benchmark-Script, das werde ich wohl häufiger benutzen!
Eine Frage, wieso hast Du 'SetBatchLines, -1' auskommentiert? Und: 'Process, priority, , High' macht den Test noch unabhängiger von anderen Prozessen.

Ich habe es mal zur Gegenüberstellung um eine dritte DelSp-Funktion erweitert und das Geschwindigkeitsverhältnis zu DelSp2() in die letzte Spalte geschrieben.

Noch zwei Anmerkungen:
  1. Meine Funktion DelSp3() bearbeitet den ihr übergebenen String, daher muß er vor dem Funktionsaufruf an die Out-Variable übergeben werden statt nachher, damit die Originalvariable nicht zerstört wird. Deshalb der etwas seltsam anmutende Aufruf 'Out := Str, DllCall(&DelSp3, "str", Out)'. (Die Gründe dafür später, wenn's interessiert.)
  2. Der Test mißt die reine Arbeitszeit der Funktion, nicht aber die Zeit, die MCode braucht, um die Funktion zu erstellen. MCode braucht natürlich nur einmal vor dem ersten Aufruf gestartet zu werden; AutoHotkey braucht allein zum Starten ein Vielfaches dieser Zeit. Für den Fall, daß man es trotzdem nachmessen will, muß an den Stellen mit XXXXX ent- bzw. auskommentiert werden.


Code:
#NoEnv

; Maschinencode aus einer DLL
DSCode =
(Join
5589E583EC0C8B45088945FC8B45088945F8C645F6018B45FC0FB6008845F7807DF700751B807DF600740D8B
45F83B450876058D45F8FF088B45F8C60000EB40807DF7207408807DF7097402EB17807DF60075258B45F8C6
00208D45F8FF00C645F601EB148B45F889C20FB645F788028D45F8FF00C645F6008D45FCFF00EB968B4508C9C3
)

; Erzeugung einer Funktion aus dem Maschinencode
MCode(DelSp3, DSCode) ; XXXXX auskommentieren für Benchmark incl. Funktionserzeugung

; Laszlos MCode
MCode(ByRef code, hex) { ; allocate memory and write Machine Code there
   VarSetCapacity(code,StrLen(hex)//2)
   Loop % StrLen(hex)//2
      NumPut("0x" . SubStr(hex,2*A_Index-1,2), code, A_Index-1, "Char")
}

; SetBatchLines, -1

AutoTrim, Off
TxT := "`t`t  The `t`t   Quick Brown       Fox Jumps`tBrown   Over          the"
    .  "     Lazy            Dog`t"
Str := Txt
Erg := ""
; freq enthält qpc einheiten per sek
DllCall("QueryPerformanceFrequency", "int64*", Frequenz)

Out := Str, DllCall(&DelSp3, "str", Out)
MsgBox, 0
      , Funktionsnachweis:
      , % "DelSp1: >" . DelSp1(Str) . "<`n`nDelSp2: >" . DelSp2(Str) . "<`n`nDelSp3: >" . Out . "<"

SetFormat, Float, 0.8

OL := 20       ; Äußere Schleife
IL := 10       ; Innere Schleife

Loop, %OL%
{
   VarSetCapacity(Out, StrLen(Str))
   Critical
   DllCall("QueryPerformanceCounter", "Int64*", Start)
   Loop, %IL%
   {
      Out := DelSp1(Str)
   }
   DllCall("QueryPerformanceCounter", "Int64*", Ende)
   Critical, Off
   T1 := (Ende - Start) / Frequenz / IL
   Critical
   DllCall("QueryPerformanceCounter", "Int64*", Start)
   Loop, %IL%
   {
      Out := DelSp2(Str)
   }
   DllCall("QueryPerformanceCounter", "Int64*", Ende)
   Critical, Off
   T2 := (Ende - Start) / Frequenz / IL
   Critical
   DllCall("QueryPerformanceCounter", "Int64*", Start)
   Loop, %IL%
   {
      ; XXXXX Die nächsten beiden Zeilen entkommentieren für Benchmark incl. Funktionserzeugung
      ; If Not DelSp3
      ;   MCode(DelSp3, DSCode)
      Out := Str, DllCall(&DelSp3, "str", Out)
   }
   DllCall("QueryPerformanceCounter", "Int64*", Ende)
   Critical, Off
   T3 := (Ende - Start) / Frequenz / IL
   Erg .= StrLen(Str) . "|" . T1 . "|" . T2 . "|" . T3 . "`n"
   Loop, %A_Index%
      Str .= TxT
}

Gui, Margin, 0, 0
Gui, Font, s10, Tahoma
Gui, Add, Text, , Äußere Schleife`t: %OL%`nInnere Schleife`t: %IL%
Gui, Add, ListView
   , Readonly NoSort NoSortHdr Grid R%OL% w500
   , Stringlänge  |Zeit DelSp1 | Zeit DelSp2 | Zeit DelSp3 |DelSp3/DelSp2 `%
Loop, Parse, Erg, `n
{
   If (A_Index > OL) {
      Break
   }
   StringSplit, F, A_LoopField, |
   LV_Add("", F1, F2, F3, F4, Round(F4 * 100 // F3))
}
LV_ModifyCol(1, "Center")

Gui, Show, , Durchschnittszeiten
Return

GuiClose:
GuiEscape:
ExitApp

DelSp1(Str)
{
   StringReplace, Str, Str, %A_Tab%, %A_Space%, All
   Loop,
      If (InStr(Str, "  "))
         StringReplace, Str, Str, %A_Space%%A_Space% ,%A_Space%, All
      Else
         Break
   If (SubStr(Str, 1, 1) = " ")
      Str := SubStr(Str, 2)
   If (SubStr(Str, 0) = " ")
      Str := SubStr(Str, 1, -1)
   Return Str
}

DelSp2(Str)
{
   StringReplace, Str, Str, %A_Tab%, %A_Space%, All
   Str := RegExReplace(Str, "S)\s+", " ")
   If (SubStr(Str, 1, 1) = " ")
      Str := SubStr(Str, 2)
   If (SubStr(Str, 0) = " ")
      Str := SubStr(Str, 1, -1)
   Return Str
}


__________________________________________
Created with BBCodeWriter 7.0 - the one and only Very Happy
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
haichen



Anmeldedatum: 10.06.2007
Beiträge: 92

BeitragVerfasst am: Sa März 01, 2008 11:41 pm    Titel: Antworten mit Zitat

In kürze will ich nur sagen :! Unglaublich !

Über den seltsamen Aufruf mußt Du uns (mich) tatsächlich später noch aufklären.

Zu ; SetBatchLines, -1 steht im Helpfile :
In v1.0.47+, turning on Critical also puts SetBatchLines -1 into effect for the current thread.

Danke für dieses "Ding"!

Very Happy
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
denick



Anmeldedatum: 15.09.2006
Beiträge: 1199
Wohnort: Berlin

BeitragVerfasst am: So März 02, 2008 8:33 am    Titel: Antworten mit Zitat

Moin Chucky,

"! Unglaublich !" halte ich mal für stark untertrieben.

Zitat:
Der Maschinencode läßt sich z. B. mit ziemlich jedem Compiler generieren, der DLLs erzeugen kann, z. B mit dem freien GNU-C-Compiler Dev-Cpp, den ich benutze.
Ich habe also eine DelSpaces-Funktion geschrieben (jetzt auch mit Tab->Space-Wandlung Smile) und in eine DLL kompiliert. Die DLL disassembliert man, um an den Hex-Code der Funktion zu kommen. Den Code aus dem Listing befreit man von Speicheradressen, Mnemonics, Spaces usw. und reduziert ihn damit auf den hexadezimalen Maschinencode.
Wenn's weiter nichts ist? Shocked

Zitat:
Eine Frage, wieso hast Du 'SetBatchLines, -1' auskommentiert? Und: 'Process, priority, , High' macht den Test noch unabhängiger von anderen Prozessen.
Zu SetBatchLines hat ja haichen schon geantwortet. Process, Priority habe ich noch nie benutzt und deshalb auch nicht einmal daran gedacht. Ich werde es mir aber merken.

An die Künstler unter uns: Rollt die Transparente wieder ein! Wink
_________________
Hilfe zur Hilfe

(de)nick
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Milchmann



Anmeldedatum: 10.12.2007
Beiträge: 66

BeitragVerfasst am: Mo März 03, 2008 10:03 am    Titel: Antworten mit Zitat

Hallo, wie kann ich bei der genannte Version über
mehrere Zeilen die Leerzeichen und die TABs entfernen. Es geht um mehrere durch Enter getrennte Zeilen. Bei mir klappt es nicht mit der Variablen.
Danke Bert
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
BoBo¨
Gast





BeitragVerfasst am: Mo März 03, 2008 10:54 am    Titel: Antworten mit Zitat

Wie hälst du denn den Mehrzeiler vor? In einer Variablen (zB Clipboard)?
Oder Zeilen in einer Datei??

Code:
Loop, Read, Mein.txt
   DelSp(A_LoopReadLine)
 .
 .
 .



Code:
Loop, Parse, ClipBoard, `n`r`
{
   DelSp(A_LoopField)
   ParsedContent .= A_LoopField "`n"
   }
MsgBox % ParsedContent
 .
 .
Nach oben
haichen



Anmeldedatum: 10.06.2007
Beiträge: 92

BeitragVerfasst am: Mo März 03, 2008 11:52 am    Titel: Antworten mit Zitat

Welche Version benutzt Du denn?
Die Binärcode Version entfernt bei mir keine Zeilentrenner.
DSCode = .... MCode(DelSp3, DSCode) müssen vor dem Aufruf von Out := Str, DllCall .. stehen.

Falls Du eine der Versionen mit RegexpReplace benutzt, mußt Du \s gegen \h
tauschen, damit \n oder \r nicht entfernt werden.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Milchmann



Anmeldedatum: 10.12.2007
Beiträge: 66

BeitragVerfasst am: Mo März 03, 2008 1:56 pm    Titel: Antworten mit Zitat

Hallo, ich möchte aus dem Clipboard mehrere Zeilen auslesen lassen und diese dann die Leerzeichen etc. entfernen. Da funktioniert aber dein Skript:
delspaces(str) nicht.
Wie muss das Skript richtig aufgebaut sein, damit es funktioniert?

PS: Wie kann ich einer Variablen einen mehrzeiligen Text zuweisen

Danke Bert
Wie muss ich
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
haichen



Anmeldedatum: 10.06.2007
Beiträge: 92

BeitragVerfasst am: Mo März 03, 2008 2:47 pm    Titel: Antworten mit Zitat

Dann zeig doch mal was Du hast. Falls es Teil eines größeren Skripts ist, am besten nur den Teil mit dem ClipBoard und dem DeleteSpaces.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
haichen



Anmeldedatum: 10.06.2007
Beiträge: 92

BeitragVerfasst am: Mo März 03, 2008 3:36 pm    Titel: Antworten mit Zitat

Geht alles wie 'ne eins.
Hier nur zwei Beispiele:
Code:
#d:: msgbox, % delspaces5(clipboard)

delspaces5(str){
str :=RegExReplace(Str,"\h{2,}", " ")
str :=RegExReplace(Str,"(^\h)|(\h$)","")
return %str%
}

Code:
MCode(DelSp3)
#d:: msgbox, % delspaces8(clipboard)

delspaces8(str){
   global DelSp3
   Out := Str, DllCall(&DelSp3, "str", Out)
   return out
}

MCode(ByRef code) { ; allocate memory and write Machine Code there
hex =
(Join
5589E583EC0C8B45088945FC8B45088945F8C645F6018B45FC0FB6008845F7807DF700751B807DF600740D8B
45F83B450876058D45F8FF088B45F8C60000EB40807DF7207408807DF7097402EB17807DF60075258B45F8C6
00208D45F8FF00C645F601EB148B45F889C20FB645F788028D45F8FF00C645F6008D45FCFF00EB968B4508C9C3

   VarSetCapacity(code,StrLen(hex)//2)
   Loop % StrLen(hex)//2
      NumPut("0x" . SubStr(hex,2*A_Index-1,2), code, A_Index-1, "Char")
}
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Gast






BeitragVerfasst am: Mo März 03, 2008 8:34 pm    Titel: Antworten mit Zitat

Hallo Haichen,

Du hast mit Deinen Funktionen recht,
diese laufen:
Code:

Loop, Parse, ClipBoard, `n`r`
{
   DelSp(A_LoopField)
   ParsedContent .= A_LoopField "`n"
   }
MsgBox % ParsedContent

Dort kommt call to non exist Funktion Wieso Rolling Eyes

Mein Clipboard enthält evtl. diese Daten:
[code]
NeuJahr=01.01.Jahr
Karfreitag=Ostersonntag-2
Ostermontag=Ostersonntag+1
ChristiHimmelfahrt=Ostersonntag+39
Pfingstsonntag=Ostersonntag+49
Pfingstmontag=Ostersonntag+50
TagDerArbeit=01.05.Jahr
TagDerDeutschenEinheit=03.10.Jahr
Reformationstag=31.10.Jahr
Buß- und Bettag
HeiligAbend=24.12.Jahr
ErsterWeihnachtstag=25.12.Jahr
ZweiterWeihnachtstag=26.12.Jahr
Silvester=31.12.Jahr
)
;Rosenmontag=Ostersonntag-48
;Faschingsdienstag=Ostersonntag-47
;Aschermittwoch=Ostersonntag-46
;Gründonnerstag=Ostersonntag-3
; HlDreiKönige=06.01.Jahr
; FrankfurterWäldchestag=Ostersonntag+51
; Karsamstag=Ostersonntag-1
; Fronleichnam=Ostersonntag+60
; AugsburgerFriedensfest=08.08.Jahr
; MariäHimmerfahrt=15.08.Jahr
; Alleheiligen=01.11.Jahr
; MariäEmpfängnis=08.12.Jahr [/code


Danke Bert]
Nach oben
BoBo¨
Gast





BeitragVerfasst am: Mo März 03, 2008 8:46 pm    Titel: Antworten mit Zitat

Zitat:
Dort kommt call to non exist Funktion Wieso
Weil da wo die drei Punkte angeführt sind, die Funktion stehen sollte.
Nach oben
Beiträge der letzten Zeit anzeigen:   
Neues Thema eröffnen   Neue Antwort erstellen    AutoHotkey Community Foren-Übersicht -> Skripte & Funktionen Alle Zeiten sind GMT
Gehe zu Seite Zurück  1, 2, 3  Weiter
Seite 2 von 3

 
Gehe zu:  
Du kannst Beiträge in dieses Forum schreiben.
Du kannst auf Beiträge in diesem Forum antworten.


Powered by phpBB © 2001, 2005 phpBB Group
Deutsche Übersetzung von phpBB.de