1. Dashboard
  2. Mitglieder
    1. Letzte Aktivitäten
    2. Benutzer online
    3. Team
    4. Mitgliedersuche
  3. Forenregeln
  4. Forum
    1. Unerledigte Themen
  • Anmelden
  • Registrieren
  • Suche
Alles
  • Alles
  • Artikel
  • Seiten
  • Forum
  • Erweiterte Suche
  1. AutoIt.de - Das deutschsprachige Forum.
  2. Mitglieder
  3. misterspeed

Beiträge von misterspeed

  • StdoutRead gibt Fehler zurück.

    • misterspeed
    • 6. August 2012 um 18:17

    Dein Script ist soweit ich das sehe fehlerfrei. Die Meldung stammt auch nicht von Autoit, sondern vom zu überwachenden Prozess. Dieser scheint wohl etwas dagegen zu haben, dass man den stdout einfach mitschneidet. Das selbe Problem für das betreffende Programm wurde auch hier diskutiert:

    http://facepunch.com/showthread.php?t=1181915


    Da die dortigen Lösungsansätze aber meine Fähigkeiten bei weitem übersteigen überlasse ich das mal jemand anderem. ;)

  • Prozess schützen

    • misterspeed
    • 4. August 2012 um 23:18

    Dann viel Spass wenn etwas zweideutigere Werbepopups aufpoppen und der Rechner gesperrt wird. :P
    Oder wenn sich jemand über harmlose Themen informieren möchte bei denen es unumgänglich ist Begriffe wie Sex, Penis oder Vagina zu nennen.

    Ich halte wenig bis garnichts von Zensur. Schon alleine deshalb weil es quasi technisch unmöglich ist sowas brauchbar zu realisieren ohne False Positives.
    Davon ab langt schon eine simple google Bildersuche um pornografische Bilder zu finden.

  • Prozess schützen

    • misterspeed
    • 4. August 2012 um 22:07

    Sowas macht man aber am sinnvollsten per firewall oder router. Software kann man immer austricksen, würd mir da wenig Hoffnung machen. CMD.exe sperren wird dich z.B. nicht vor einem usb stick mit portable FF schützen...

  • Nur 1 Prozess seines Scripts laufen lassen

    • misterspeed
    • 4. August 2012 um 17:20

    Jo deswegen gibts singleton ja vermutlich. :)

    Allerdings dürfte es in der Praxis kaum vorkommen, dass der Prozess innerhalb weniger Milisekunden mehrmals gestartet wird. Viel problematischer an der Lösung ist es aber, dass lediglich der Prozessname geprüft wird, welcher durchaus auch von anderen Programmen verwendet werden könnte. Singleton ist jedenfalls die bessere/zuverlässigere Variante.

  • Nur 1 Prozess seines Scripts laufen lassen

    • misterspeed
    • 4. August 2012 um 14:41
    Zitat von Zattoo

    also es ist nicht so wie ihr meint,
    es is so unzwar is ne exe, wenn die läuft soll se nicht nochmal startbar sein (schon starten aber direkt beendet werden)

    Und nun? Haben doch alle hier verstanden, ersetze einfach die 1 in deiner if Bedingung durch 2 oder nutze alternativ die Funktion singleton(). Beides bewirkt genau das was du willst. Dein Fehler ist es lediglich gewesen, dass sich bereits die erste Instanz beendet, weil sie sich selbst schon als eine zuviel ansieht.

  • Nur 1 Prozess seines Scripts laufen lassen

    • misterspeed
    • 4. August 2012 um 13:32

    Das ganze würde aber auch mit zatoo's Methode funktionieren.


    [autoit]

    If UBound(ProcessList(@ScriptName)) > 1 Then Exit

    [/autoit]


    Der Denkfehler ist hier, dass das Array nicht größer 1 sein darf. Das ist falsch, es darf nicht größer als 2 sein.

    Grund:

    processlist ist 1 Feld groß, wenn kein Prozess mit dem Namen existiert. Da minstesns ein Prozess mit dem Namen existieren darf, nämlich der eigene muss man prüfen ob neben dem eigenen noch weitere existieren, also eine Arraygräße von mehr als 2.

    $array[0][0] = Anzahl der Prozesse <-- 1. Element
    $array[1][0] = Name des 1. Prozesses <-- 2. Element
    $array[2][0] = Name des 2. Prozesses <-- 3. Element

  • Fenster / PopUp schliessen?

    • misterspeed
    • 3. August 2012 um 21:05
    [autoit]


    While 1

    [/autoit][autoit][/autoit][autoit]

    If WinActive("[CLASS:#32770]", "") Then
    WinClose("[CLASS:#32770]","")
    EndIf

    If WinExists("[CLASS:#32770]", "") or WinActive("[CLASS:#32770]", "") Then
    ControlClick("[CLASS:#32770]", "[CLASS:Button; INSTANCE:1]", "")
    EndIf

    ExitLoop ; <------ huch das gehört hier sicher nicht hin...

    [/autoit][autoit][/autoit][autoit]

    WEnd

    [/autoit]


    Kann so ja auch nicht funktionieren... du verlässt deine Schleife ja bereits nach dem 1. Durchlauf mit dem exitloop. Da wohl kaum beide Fenster sofort nach Programmstart aufpoppen wirste das exitloop wohl sinnvollerweise in die if Bedingung zum letzten erscheinenden Fenster packen müssen.

  • Externe au3 Datei via Include wird nicht gezogen

    • misterspeed
    • 2. August 2012 um 17:30

    Ich kann dir auch sagen warum "nix" passiert, oder viel mehr warum etwas passiert, das du sicher nicht beabsichtigst.

    In der admin.au3 machst du Folgendes:

    Du deklarierst die Variable "$GUI_Einstellungen_Daten_SS" ganz am Anfang global, ohne Wertzuweisung, was gleichbedeutend mit der Wertzuweisung 0 ist.
    Das machst du deshalb, weil du die GUI erst in der Funktion erstellst, deine while Schleife aber ausserhalb der Funktion laufen soll... warum auch immer.

    Nun ergibt sich ein Problem. Die While Schleife wird abgearbeitet, die deklarierte Variable, welche du im case abfragst wurde noch nicht mit einer controlid überschrieben, weil die gui noch garnicht erstellt ist. Somit hat die Variable nachwievor den Wert 0. Guigetmsg returned aber immer 0, wenn es kein GUI event gab. Da das zu 99% der Laufzeit der Fall ist sollte man tunlichst vermeiden einer Variable den Wert 0 zuzuweisen, welche mit dem Ergebnis von guigetmsg verglichen wird. Das Ergebnis ist, dass der case erfüllt ist und folgerichtig dein exit ausgeführt wird. Besser sehen kannst du das indem du statt exit ein consolewrite in den case einfügst, dann schaut dein consolelog nämlich so aus:


    Code
    +>17:09:19 AU3Check ended.rc:0
    >Running:(3.3.6.1):C:\Program Files (x86)\AutoIt3\autoit3_x64.exe "C:\Users\****\Desktop\autoit\Neuer Ordner\main.AU3"    
    case erfüllt
    case erfüllt
    case erfüllt
    case erfüllt
    ...


    Aber selbst wenn du das Problem umgehst, z.B. einen negativen Wert bei der Deklaration zuweist wird nicht das passieren was du dir erhoffst, denn wenn du das Hauptscript ausführst wird zuerst alles was global ist, also ausserhalb von Funktionen existiert ausgeführt. Da du die admin.au3 inkludierst bevor der Rest deines Hauptscriptes folge befindet sich die globale while schleife der admin.au3 vor deiner globalen Schleife der main.au3. Dein Script bleibt also in der while Schleife der admin.au3 hängen und kommt erst garnicht zur Ausführung des globalen codes der main.au3. Resultat Endlosschleife.


    Deswegen auch mein Hinweis darauf, dass man in include Dateien auf globale Dinge verzichten sollte, im Höchstfall Variablen oder Konstanten global deklarieren sollte (Benennung muss eindeutig sein, damit es nicht zu Problemen mit Variablen im Hauptscript kommt), aber ganz sicher keinen ausführbaren code und erst recht keine Schleifen.

    Sieh includes nicht als Einbettung von seperaten Programmen, sondern als Funktionssammlungen an.

    Da du hier scheinbar einen PW Schutz in dein Admin Programm einbauen willst wäre es denke ich eher sinnvoller den PW Schutz als include zu gestalten und in die admin.au3 oder deine anderen Programme, welche auf gleichem Wege geschützt werden sollen einzubauen.

  • RegKeys auslesen, anzeigen und bearbeiten

    • misterspeed
    • 1. August 2012 um 23:06

    Würde dir empfehlen das Buch von peethebee mal anzuschaun, denke da werden die wichtigsten Grundlagen ausführlich und anhand von kleinen Beispielen erklärt:

    https://autoit.de/index.php?page=Thread&amp;threadID=11898


    Hier im Forum findest du auch einige Tutorials, unter anderem zum Umgang mit Arrays. GUI Erstellung ist relativ simpel anhand des Koda Form Designers von Scite erlernbar. Hier einfach einige Testguis erstellen, dir die Hilfe Einträge der verwendeten Funktionen und die zugehörigen Beispielscripte ansehen. Das sollte eigentlich recht selbst erklärend sein. Irgendwann wirst du vermutlich dann wie jeder fortgeschrittene Neuling auch einige speziellere Dinge benötigen, dafür ist dann das Forum hier da. Heute hast du ja zum Beispiel schonmal gelernt wie man Eingabefelder ausliest. ;)

    Mir persönlich hat es auch geholfen die Probleme von anderen zu lesen und mir anhand der vorgeschlagenen Lösungen neues Wissen anzueignen, völlig ohne selbst "dumme" Fragen stellen zu müssen. Nennt sich dann Eigeninitiative. Dabei lernt man meist auch mehr, als wegen jeder Kleinigkeit nachzufragen und sich fertige Lösungen die man evtl. noch nicht einmal versteht vorkauen zu lassen. Selbstverständlich sind Fragen hier stets willkommen, aber es macht immer einen besseren Eindruck, wenn man sehen kann, dass sich derjenige bereits damit befasst hat und zumindestens einen Teil selbst beträgt, wie zum Beispiel sein fehlerhaftes Script zu posten oder konkrete Fragen zu eine Funktion zu stellen, die er trotz des Lesens der zugehörige Hilfe nicht verstanden hat.

  • RegKeys auslesen, anzeigen und bearbeiten

    • misterspeed
    • 1. August 2012 um 21:04

    Dabei dann evtl noch beachten, dass man für gewisse Registryzweige wie "Local Machine" Administratorrechte benötigt, also ein #requireadmin an den Scriptanfang sollte. "Current User" geht auch ohne Admin Rechte, aber dir gings ja anscheinend nur darum wie man gui's erstellt und Userinput der GUI weiterverarbeitet. Ergänzend zu Torni's Beispielscript würde ich dir aber dringendst dazu raten die vom User angegeben Strings vor dem Schreiben in die Registry zu überprüfen (z.B. wenn nur Ganzzahlen sinnvoll sind usw.), damit kein Murks in der Registry landet.

  • Daten aus CSV Datei in ein Array Übernehmen

    • misterspeed
    • 1. August 2012 um 18:17
    Zitat von autoBert

    Auf meinem altersschachen Laptop schlägst du Oscar's Variante mit gemessenen 33 Sekunden um Sekunden. Danke für den Beweis, jetzt hat das Thema RegEx für mich wieder an Bedeutung verloren. Ich war doch tatsächlicham überlegen mir das anzutun.


    Freut mich, dass ich nicht der einzige bin, der Reguläre Ausdrücke nicht mag / versteht / keine Lust hat sich intensiver damit auseinanderzusetzen. Dass meine Variante bei dir schneller sein konnte als die RegEx Version überrascht micht jetzt aber schon, bei mir war das nichtmal unter Idealbedingungen der Fall, auch wenn ich nah rankam. Letzten Endes ist meine Methode bei kleineren Datenmengen und weniger Fehlsplits aber auf jedenfall gleichwertig zur RegEx Variante und für mich wenigstens besser nachvollziehbar, als diese kryptischen RegEx Pattern, was die Fehlersuche dann natürlich ungemein erleichtert.

    Etwas beneide ich die RegEx Freaks aber schon. :D

  • Externe au3 Datei via Include wird nicht gezogen

    • misterspeed
    • 1. August 2012 um 17:57

    Nein es ist eben nicht egal wo die includes stehen. Soweit ich weiß werden die Quelltexte der include Dateien dort vom compiler eingefügt wo das #include Statement steht, deswegen gehören includes Grundsätzlich an den Scriptanfang, da es sonst in den meisten Fällen zu Syntax Fehlern kommt, wie man es auch der Fehlermeldung entnehmen kann.

    Wichtig sind außerdem noch folgende Dinge:

    Handelt es sich nicht um ein Standardinclude aus dem Autoit Installationsordner muss die Datei durch eine der unteren Varianten includiert werden:

    [autoit]


    #include "DateiImScriptVerzeichnis.au3"
    #include "C:\test\dateiIrgendwoAufDerHDD.au3"
    #include "..\..\relativePfadangabe.au3"
    ; nur bei Standard includes wird <includename.au3> verwendet, ansonsten immer Anführungszeichen.

    [/autoit]

    Man sollte ausserdem darauf achten, dass globale Variablen in den Includes so benannt werden sollten, dass sich diese nicht mit den globalen Variablen im Hauptscript überschneiden, bevorzugt sollte man in zu inkludierenden Dateien lediglich Funktionen mit lokal deklarierten Variablen verwenden. Ausserdem darf es nicht passieren, dass Funktionen im Hauptscript gleich benannt sind wie in der Include Datei, auch hier sollte man bei der Namensgebung in den includes aufpassen.

  • Virtuellen Zweitbildschirm erstellen

    • misterspeed
    • 1. August 2012 um 17:37

    Naja sofern es dir eher nur darum geht das Verhalten deines Programmes auf einem Multimonitor System zu testen/simulieren und weniger darum geht wirklich deinen Laptop als Zweitmonitor zu verwenden oder eine derartige Simulation zu programmieren, dann würde ich mir mal virtualbox ansehen. Virtualbox erlaubt es nämlich bis zu 4 Monitore zu simulieren und diese dem Gastbetriebssystem als solche zu melden. Angezeigt wird der Inhalt der virtuellen Monitore dann in jeweils seperaten Virtualbox Fenstern. Neben virtualbox, also einer kompletten Virtualisierungslösung gibt es laut google aber auch noch einige andere Tools, die lediglich virtuelle Monitore erzeugen, also keinen kompletten PC emulieren. Eines wäre z.B. das hier http://ishadow.com/?tabid=115

  • RequireAdmin in If

    • misterspeed
    • 31. Juli 2012 um 22:13

    Warum das löschen nicht gehen soll versteh ich nicht, das sollte ja soweit identisch mit deiner Lösung sein, oder ging es da auch nicht? Grundsätzlich kannste doch aber auch eine selfdelete Funktion in diese "gibmiradminrechte.exe" reinschreiben.

    Zitat von Xenobiologist

    nutz Scite und gibt selfdelete ein und dann STRG+B

  • Daten aus CSV Datei in ein Array Übernehmen

    • misterspeed
    • 31. Juli 2012 um 21:54
    Zitat von autoBert

    stimmt ich habe die Lösung bereits eingestellt. Allerdings ist die Laufzeit enorm langsam. Mein Benchmarktest:


    Dein Hauptfehler war es, dass du die Splitergebnisse der Zeilen auch noch in Buchstaben zerlegt hast, was garnicht notwendig ist. Hier mal mein oben skizzierter Lösungsweg ohne Reguläre Ausdrücke:

    Spoiler anzeigen
    [autoit]


    #include <file.au3>
    #include <array.au3>

    [/autoit] [autoit][/autoit] [autoit]

    $csv = @ScriptDir & "\test_fail.csv"

    [/autoit] [autoit][/autoit] [autoit]

    ;~ dim $anew
    ;~ _FileReadToArray($csv,$anew)
    ;~ dim $temp
    ;~ For $i = 1 to $anew[0]
    ;~ $temp &= $anew[$i] & @CRLF
    ;~ Next

    [/autoit] [autoit][/autoit] [autoit]

    ;~ Dim $temp2
    ;~ for $i=1 to 25000
    ;~ $temp2 &= $temp
    ;~ Next

    [/autoit] [autoit][/autoit] [autoit]

    ;~ FileWrite(@ScriptDir & "\testbig.csv",$temp2)

    [/autoit] [autoit][/autoit] [autoit]

    $start = TimerInit()
    $aResult = _csv2array2d($csv)
    ConsoleWrite("ZeitTotal: " & TimerDiff($start) & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    ;_ArrayDisplay($aResult)

    [/autoit] [autoit][/autoit] [autoit]

    Func _csv2array2d($file)

    [/autoit] [autoit][/autoit] [autoit]

    Local $aCSV
    $start1 = TimerInit()
    _FileReadToArray($file,$aCSV)
    ConsoleWrite("ZeitReadArray: " & TimerDiff($start1) & @CRLF) ; bisschen lahm, geht vermutlich mit fileread flotter
    $start2 = TimerInit()
    _ArrayDelete($aCSV,0)
    ConsoleWrite("ZeitDelArray: " & TimerDiff($start2) & @CRLF) ; wäre ebenfalls nicht notwendig wenn man fileread verwendet

    [/autoit] [autoit][/autoit] [autoit]

    Local $aSplitRows = StringSplit($aCSV[0],",",2)
    $aSplitRows = fixSplitFail($aSplitRows) ; referenzwert für die Spaltenanzahl

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Local $aReturn[UBound($aCSV)][UBound($aSplitRows)]

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 0 to UBound($aCSV)-1
    $aSplit = StringSplit($aCSV[$i],",",2)
    If UBound($aSplit) <> UBound($aSplitRows) Then $aSplit = fixSplitFail($aSplit) ; nur wenn spaltenanzahl vom referenzwert abweicht liegt ein splitfehler vor
    ;$aSplit = fixSplitFail($aSplit) ; kostet zuviel zeit das jedesmal zu machen
    For $j = 0 to UBound($aSplit)-1
    $aReturn[$i][$j]=StringReplace($aSplit[$j],'"',"")
    ;ConsoleWrite($aSplit[$j] & @CRLF)
    Next
    Next

    [/autoit] [autoit][/autoit] [autoit]

    Return $aReturn

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    EndFunc

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func fixSplitFail(ByRef $aFail)

    [/autoit] [autoit][/autoit] [autoit]

    Local $aReturn[UBound($aFail)]
    Local $k=0

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 0 to UBound($aFail)-1
    If StringLeft($aFail[$i],1) = '"' And StringRight($aFail[$i],1) <> '"' Then
    Do
    $aReturn[$k]&=$aFail[$i] & ","
    $i+=1
    Until StringRight($aFail[$i-1],1) = '"'
    $i-=1
    $aReturn[$k]=StringTrimRight($aReturn[$k],1)
    Else
    $aReturn[$k]=$aFail[$i]
    EndIf
    $k+=1
    Next

    [/autoit] [autoit][/autoit] [autoit]

    ReDim $aReturn[$k]
    ;_ArrayDisplay($aReturn)
    Return $aReturn
    EndFunc

    [/autoit]


    Bei 100.000 Datensätzen mit Splitfehlern (kopierte Beispiel CSV) braucht meine Variante ca. 11sek.
    Deine/Oscars 2D-RegEx Version benötigt für das selbe ca. 6sek, ist also auf jedenfall schneller.
    Bei einer CSV, welche keine splitfehler enthält erreicht meine Variante 7sek, die Regex Version bleibt unverändert bei 6sek.

    Allerdings ist mit aufgefallen, dass dein Output Array 1 Zeile zu groß geraten ist. Ausserdem ist es bei meiner Lösung nicht notwendig, dass der Referenzdatensatz (Zeile 1) fehlerfrei gesplittet wird (deine Version) bzw die Spaltenanzahl bekannt ist (regex 2D Version).

    Man kann also durchaus auch ohne RegEx eine performante Lösung basteln, mit einigen kleineren Optimierungen könnte meine Variante im günstigsten Fall (also ohne Splitfehler) evtl. sogar an die RegEx Variante rankommen. :)

  • RequireAdmin in If

    • misterspeed
    • 31. Juli 2012 um 19:14
    Zitat von m-obi

    misterspeed: Eben nicht. Ich will ja nicht das die Exe bei jedem Starten des Programms erstellt wird. Ich benötige sie ja nur beim ersten Start.

    Joar und genau das kann man soweit ich mich recht entsinne auch mit fileinstall machen. Die "installierten" Files in der main.exe werden nämlich erst dann entpackt, wenn die fileinstall Zeile des Scriptes ausgeführt wird. Hier kann man dann wie bei deiner hexstring Methode natürlich auch mit if Bedingungen arbeiten.


    Beispiel:

    [autoit]


    $doinstall = False ; bei False wird nix "installiert", bei true schon ;)

    [/autoit][autoit][/autoit][autoit]

    If $doinstall = True Then
    FileInstall("C:\test\filestoinstall\install.txt",@ScriptDir & "\itwasdone.txt",1)
    Else
    MsgBox(0,"false","nothing was installed")
    EndIf

    [/autoit]
  • Daten aus CSV Datei in ein Array Übernehmen

    • misterspeed
    • 30. Juli 2012 um 23:27
    Zitat von rollod

    Gibt es hier Eurer Meinung nach eine Lösung?

    Vermutlich kommen dann nur noch reguläre Ausdrücke in Frage. Da fehlt es mir selbst jedoch an Erfahrung...

    [autoit]


    stringregexp()

    [/autoit]

    Alternativ wäre noch folgendes Vorgehen denkbar:

    1. normaler stringsplit aufs Komma ohne Zusatzzeichen für jede Zeile, also --> StringSplit($SCVline,",")
    2. Prüfung des Stringsplit Ergebnisses der Zeile. Array durchlaufen und für jedes Feld prüfen, ob der String mit " anfängt. Wenn ja, dann muss er auch mit " aufhören. Ist das nicht so haben wie einen Splitfehler , den wir beim schreiben ins Zielarray durch zusammenfügen zweier Splitergebnisse korrigieren müssen.
    3. Sofern gewünscht vor dem Schreiben der Zeile ins Zielarray noch alle Anführungszeichen mit stringreplace ersetzen.

  • RequireAdmin in If

    • misterspeed
    • 30. Juli 2012 um 23:18
    Zitat

    und als Hex-Stream in mein Hauptscript reingemacht. Ist zwar nen bisschen viel, aber egal erstmal. Mal schauen evtl. mach ich da später noch Base64.

    [autoit]

    fileinstall()

    [/autoit]

    hätte aber auch gereicht ^^

  • RequireAdmin in If

    • misterspeed
    • 30. Juli 2012 um 22:36

    Das hat nix mit dem was #requireadmin bewirkt zu tun, sondern damit, dass #requireadmin wie alle Code Zeilen mit "#" Präprozessor bzw Präcompiler Anweisungen sind. Diese werden nicht zur Laufzeit interpretiert, sondern bereits vor dem compilen, sie haben also Einfluss darauf wie der compiler den eigentlichen Quellcode verarbeitet und letzten Endes die ausführbare exe Datei erstellt.

    So weist #include den Compiler z.B. an Quellcode von weiteren Dateien mit zu kompilieren. Diverse andere Anweisungen sorgen dafür, dass z.B eine Versionsnummer, ein Icon, Copyright Infos usw. in die exe eingebunden werden, eine Komprimierung (UPX) oder Verschleierung (Obfuscator) des Quellcodes erfolgt, oder aber im Falle von #requireadmin ein bestimmtes Attribut gesetzt wird, dass das Betriebssystem veranlasst höhere Rechte für die exe anzufordern.

  • Bestimmte Dateien in .Ini schreiben lassen

    • misterspeed
    • 30. Juli 2012 um 21:38

    Was heisst die haben einen anderen Dateinamen? Wird nach jeder Änderung eine neue Datei angelegt und die alte bleibt wie sie ist mit altem Namen? Wenn ja, dann brauchst du ja nur die neu hinzugekommenen Dateien kopieren, sprich den Ordner auf neue Dateien überwachen, die beim letzten mal noch nicht da waren und wenn eine neue dazu gekommen ist eben auf deinen Stick oder sonstwohin kopieren.

Spenden

Jeder Euro hilft uns, Euch zu helfen.

Download

AutoIt Tutorial
AutoIt Buch
Onlinehilfe
AutoIt Entwickler
  1. Datenschutzerklärung
  2. Impressum
  3. Shoutbox-Archiv
Community-Software: WoltLab Suite™