ArrayIndexOutOfBoundException 1<=1

Paul279

Aktives Mitglied
Guten Abend,
hier habe ich einen Codeteil, der mir bei mehrmaligen aufrufen einen ArrayIndexoutOfBoundsException liefert.

Das komische ist 2,3,4 mal geht der Code und beim fünften Mal nicht mehr?
Es ist auch nicht immer das fünfte mal. Der Fehler kommt immer zufällig wann es ihm gefällt. D.h. es kann schon manchmal sein, dass die Methode 10mal aufgerufen wird und dann erst eine ArrayOutOfBoundException liefert. Manchmal schon beim 2tenmal.

Der Fehler tritt bei "Client.defaultTableModelTaenze = new DefaultTableModel(dataTable, COL_IDENTIFIER_TAENZE);" auf.

Wo ist der Fehler, was mache ich falsch, darf ich es nicht so schreiben?

Als Zusatzinformation:
Ich ändere nicht die COL_IDENTIFIER_TAENZE oder bekomme andere Daten(dataTable)
dataTable haben immer die selbe Row-Anzahl und Columanzahl.

dataTable ist von den Daten auch immer fast ident, höchstens, dass sich eine Zahl von 4 auf 6 oder ein Name von "Paul" zu "Mari" ändert.

Bin auch ein Newbie in JavaProgrammierung, deshalb kann ich das Problem leider nicht selbst lösen.
Ich hoffe, hier kann mir jemand weiterhelfen

Danke sehr

Java:
    public static void setjTableTaenze(Object[][] dataTable) {
        int rowCount;
        
        Client.defaultTableModelTaenze = new DefaultTableModel(dataTable, COL_IDENTIFIER_TAENZE);
        jTable_taenze.setModel(defaultTableModelTaenze);       
        
        anpassen_Columns_jTable("jTable_Taenze");
        
        rowCount = jTable_taenze.getModel().getRowCount();
        Client.stringArrayAllePunkte = new String[rowCount][7];
        send("getAllePunkte");
        send(jurorid);
    }

Java:
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 1 >= 1
	at java.util.Vector.elementAt(Vector.java:470)
	at javax.swing.table.DefaultTableColumnModel.getColumn(DefaultTableColumnModel.java:294)
	at javax.swing.plaf.synth.SynthTableUI.paintCells(SynthTableUI.java:577)
	at javax.swing.plaf.synth.SynthTableUI.paint(SynthTableUI.java:365)
	at javax.swing.plaf.synth.SynthTableUI.update(SynthTableUI.java:276)
	at javax.swing.JComponent.paintComponent(JComponent.java:778)
	at javax.swing.JComponent.paint(JComponent.java:1054)
	at javax.swing.JComponent.paintChildren(JComponent.java:887)
	at javax.swing.JComponent.paint(JComponent.java:1063)
	at javax.swing.JViewport.paint(JViewport.java:725)
	at javax.swing.JComponent.paintChildren(JComponent.java:887)
	at javax.swing.JComponent.paint(JComponent.java:1063)
	at javax.swing.JComponent.paintChildren(JComponent.java:887)
	at javax.swing.JComponent.paint(JComponent.java:1063)
	at javax.swing.JComponent.paintChildren(JComponent.java:887)
	at javax.swing.JComponent.paint(JComponent.java:1063)
	at javax.swing.JComponent.paintChildren(JComponent.java:887)
	at javax.swing.JComponent.paint(JComponent.java:1063)
	at javax.swing.JLayeredPane.paint(JLayeredPane.java:585)
	at javax.swing.JComponent.paintChildren(JComponent.java:887)
	at javax.swing.JComponent.paint(JComponent.java:1063)
	at javax.swing.JComponent.paintToOffscreen(JComponent.java:5221)
	at javax.swing.BufferStrategyPaintManager.paint(BufferStrategyPaintManager.java:295)
	at javax.swing.RepaintManager.paint(RepaintManager.java:1206)
	at javax.swing.JComponent._paintImmediately(JComponent.java:5169)
	at javax.swing.JComponent.paintImmediately(JComponent.java:4980)
	at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:770)
	at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:728)
	at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:677)
	at javax.swing.RepaintManager.access$700(RepaintManager.java:59)
	at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1621)
	at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251)
	at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:705)
	at java.awt.EventQueue.access$000(EventQueue.java:101)
	at java.awt.EventQueue$3.run(EventQueue.java:666)
	at java.awt.EventQueue$3.run(EventQueue.java:664)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:675)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:211)
	at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:128)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:117)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:113)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:105)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
 

HarryG32

Mitglied
Hier tritt der 1. Fehler auf: at java.util.Vector.elementAt(Vector.java:470 => also in Zeile 470). Du solltest vorher abfragen, ob es noch ein Element gibt, so kannst du solche Exceptions vermeiden. Lass dir die Größe des Vektors ausgeben, sowas hilft ungemein.
 

Paul279

Aktives Mitglied
so also in zeile 470 kann es mal nicht sein, da es in der Klasse "Vector.java" auftritt. Das ist die integrierte Java Klasse, da programmier ich gar nichts rum.

Könntest du mir bitte genauer erklären was du mit diesem Satz genauer meinst:
Du solltest vorher abfragen, ob es noch ein Element gibt

Also meinst du, dass ich in meinem Code abfragen soll, ob es noch ein DefaultTableModel defaultTableModelTaenze gibt?
Das kann schon leicht möglich sein, aber ich überschreibe es doch mit einem new DefaultTableModel.

Und so viel ich weiß, gibt es keinen Befehl unter Java, damit man Variablen "zerstören" kann.
Macht doch eh der Garbage Collector von Java.

Lass dir die Größe des Vektors ausgeben, sowas hilft ungemein

Wenn du meinst, dass ich mir die Größe meiner Object[][] dataTable ausgeben lassen soll, das habe ich schon gemacht. Sie ist immer exakt 405 zeilen groß.

mfg Paul
 

Marco13

Top Contributor
Der Symptombeschreibung nach ist das mit an Wahrscheinlichkeit grenzender Sicherheit ein Threading-Problem. Aus welchem Thead wird die Methode aufgerufen? Wird das TableModel von irgendeinem Thread verändert, der NICHT der EDT ist? Im Zweifelsfall eine Zeile wie

machWasWasDasTableModelÄndert();

einwickeln in ein
Java:
SwingUtilities.invokeLater(new Runnable()
{
    @Override
    public void run()
    {
        machWasWasDasTableModelÄndert();
    }
});
Falls diese Aktion länger dauert (irgendwelche Daten gelesen oder aufbereitet werden müssen) die Klasse SwingWorker ansehen.
 

Travel

Mitglied
so also in zeile 470 kann es mal nicht sein, da es in der Klasse "Vector.java" auftritt. Das ist die integrierte Java Klasse, da programmier ich gar nichts rum.

mfg Paul

Manchmal hilft einfach ein "Reinschauen":

Java:
    /**
     * Returns the component at the specified index.
     *
     * <p>This method is identical in functionality to the {@link #get(int)}
     * method (which is part of the {@link List} interface).
     *
     * @param      index   an index into this vector
     * @return     the component at the specified index
     * @throws ArrayIndexOutOfBoundsException if the index is out of range
     *         ({@code index < 0 || index >= size()})
     */
    public synchronized E elementAt(int index) {
        if (index >= elementCount) {
            throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
        }

        return elementData(index);
    }

Das ist der Code von java.util.Vector in Zeile 470.
 

Paul279

Aktives Mitglied
So, ich kann nicht schlafen, das Thema hält mich wach, jetzt hab ich den PC wieder eingeschalten.
(Morgen wird ein wunderbarer Tag in der Arbeit)

@Travel:
Konnte ich leider nichts entnehmen :(

@Marco13
Ja, das wars!

Meine "Fehlermethode":
Java:
    public static void setjTableTaenze(Object[][] dataTable) {    
                Client.defaultTableModelTaenze = new DefaultTableModel(dataTable, COL_IDENTIFIER_TAENZE);
                jTable_taenze.setModel(defaultTableModelTaenze); 
                
                anpassen_Columns_jTable("jTable_Taenze");

                int rowCount = jTable_taenze.getModel().getRowCount();
                Client.stringArrayAllePunkte = new String[rowCount][7];
                send("getAllePunkte");
                send(jurorid);                     
    }

habe ich jetzt umgebaut, wie du gesagt hast:
Java:
    public static void setjTableTaenze(final Object[][] dataTable) {    
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                Client.defaultTableModelTaenze = new DefaultTableModel(dataTable, COL_IDENTIFIER_TAENZE);
                jTable_taenze.setModel(defaultTableModelTaenze); 
                
                anpassen_Columns_jTable("jTable_Taenze");

                int rowCount = jTable_taenze.getModel().getRowCount();
                Client.stringArrayAllePunkte = new String[rowCount][7];
                send("getAllePunkte");
                send(jurorid);                
            }
        });        
    }

danach ist der Fehler nicht mehr aufgetreten! ;)

So, habe sofort gegoogelt was SwingUtilities.invokeLater macht und warum man es macht.
Habe es so verstanden, dass wir unser Anliegen, das jTable upzudaten, einreihen müssen, beim Event dispatcher Thread.

Muss mir jetzt schwere Gedanken darüber machen, da ich des öfteren die GUI update durch solche Methoden. Komischerweise klappts manchmal, manchmal nicht.
Warum ist das so?

Danke an Marco, für die Lösung, könntest du mir vielleicht noch meine letzte Frage beantworten, warum es manchmal funktioniert und manchmal nicht?

Wenn ich es falsch verstanden habe, dann bitte ich wieder um Entschuldigung und vielleicht um eine Korrigierung, damit ich es auch verstehe.

Danke an alle für eure Hilfe und euer Bemühen
Mfg Paul

//EDIT
Danke für den Tipp mit SwingWorker. Das brauche ich auch
 
Zuletzt bearbeitet:

Marco13

Top Contributor
Schau z.B. mal in The Event Dispatch Thread (The Java™ Tutorials > Creating a GUI With JFC/Swing > Concurrency in Swing)

In Swing gilt die "Single Thread Rule": Jede Aktion, die das Aussehen einer Swing-Component verändert (oder vom Zustand einer Swing-Component abhängt) muss auf dem Event-Dispatch-Thread ausgeführt werden.

Oft ist das klein Problem, weil z.B. eine Aktion direkt durch einen Buttonklick ausgelöst wird - und der wird ohnehin schon auf dem EDT verarbeitet.

Wenn man aber einen eigenen Thread hat, darf der nicht irgendwo (z.B. in einem TableModel) rumpfuschen, weil sonst Swing während des Zeichnens einen ungültigen/inkonsistenten Zustand sieht.

In vielen Fällen scheint diese Regel nicht wichtig zu sein. Wenn man z.B. sowas wie label.setText("text") oder button.setEnabled(false) (also irgendwas "kleines") auf dem falschen Thread macht, funktioniert das vielleicht oft - vielleicht sogar "immer". Es gibt aber keine Garantie dafür. Deswegen sollte man immer, wenn man einen eigenen Thread hat, und der "mit Swing zu tun hat" entsprechend aufpassen. Im Zweifelsfall kann manchmal ein
Java:
System.out.println(Thread.currentThread());
am Anfang der Methode schon einen Hinweis liefern (und nur zur Sicherheit könntest/solltest du das mal als erste Zeile in setjTableTaenze einfügen, um zu sehen, ob es wirklich daran lag ;) )
 

Paul279

Aktives Mitglied
Das nenne ich mal eine 1A Erklärung.

Den geposteten Link werde ich mir jetzt mal genauer ansehen, bin schon gespannt.
Schon wieder einiges gelernt danke :rtfm:

So, wenn du mir natürlich immer neue Codeschnippsel bereit stellst, hört die Fragerei nicht auf :oops:

Java:
    public static void setjTableTaenze(final Object[][] dataTable) {    
        
        System.out.println(Thread.currentThread());
        
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                Client.defaultTableModelTaenze = new DefaultTableModel(dataTable, COL_IDENTIFIER_TAENZE);
                jTable_taenze.setModel(defaultTableModelTaenze); 
                
                anpassen_Columns_jTable("jTable_Taenze");

                int rowCount = jTable_taenze.getModel().getRowCount();
                Client.stringArrayAllePunkte = new String[rowCount][7];
                send("getAllePunkte");
                send(jurorid);                
            }
        });        
    }

Die Ausgabe liefert mir:

Thread[Thread-2,6,main]

was kann man daraus schließen?

Ich denke, zuerst war er im Thread 2 dann 6 und jetzt in der main.
Aber was kann man daraus noch schließen? Ich würde gerne bei meinen anderen Methoden auch diesen currentThread einbauen, doch ich kann noch nicht daraus entnehmen, dass ich jetzt ein SwingUtilities.invokelater brauche.

Oder sagt mir die Ausgabe, dass wenn ich von einem anderen Thread komme, immer ein invokeLater brauche?

Was kannst du daraus bitte schließen?

Ich kann mich immer nur bedanken für dein Bemühen, mir das so gut zu erklären
 

HarryG32

Mitglied
Sorry, hab das irgendwie übersehen, dass das eine Java-Bibliothek ist, da sollte man natürlich nix rumbasteln....

Ich habe ein ganz ähnliches Problem und bin deshalb sehr interessiert an deinen Fragen und den daraus resultierenden Antworten.

Mein Problem ist, dass ich eine "java.util.ConcurrentModificationException" bekomme. Ich weiss auch warum, leider weiss ich ned genau wie ich dieses Problem beseitigen kann. Bei mir wird ein Vektor durch einen Thread verändert und dann wird der Inhalt des Vektors (Linien) gezeichnet. Während durch den Vektor iteriert wird, verändert der Thread diesen abermals und die Fehlermeldung kommt.

Java:
private synchronized void performAction(){
		if(state != PLAYING){
			return;
		}
		//show("Process Path");
		processor.processPath(); => hier wird der Vektor der Board-Klasse upgedated.
		board.repaint(); => hier zeichnet das Board den Inhalt des Vektors neu
}

Java:
	public void paintComponent(Graphics g) {
		show("REPAINT!");
		//System.out.println(tag+"Aufruf pntC: "+aufr++);
		super.paintComponent(g);
		//System.out.println(tag+"Aufruf von paintComponent");
		
		this.drawGrid(g);
		
		if(doSimulation){
			//Garten mit Farbe füllen
			model.fillGarden((Graphics2D) g);
			//Mähweg zeichnen
			if(mowingPath.size()>0){
				show("repaint path");
				Iterator <Line2D.Double>iter1 = this.mowingPath.iterator();
				while(iter1.hasNext()){
					Line2D.Double l2d = iter1.next();  => HIER tritt der 1. Fehler auf!
					Graphics2D g2d = (Graphics2D)g;
					g2d.setStroke(new BasicStroke(7));
					g2d.setColor(Color.GREEN);
					g2d.draw(l2d);
					g2d.setStroke(new BasicStroke(1));	
				}
				//Rasenmäher zeichnen
				drawMower((Graphics2D) g);
			}
			//Objekte neu zeichnen
			model.drawModel((Graphics2D) g);
			return;
		}
...

Bei mir is es ein eigener Thread, kein EDT, es geht eigentlich darum, dass der Thread solange wartet bis die andere Klasse mit dem Zeichnen fertig ist. Es hilft leider ned einen Boolean-Wert zu retournieren auf den der Thread wartet, bevor er weitermacht....Ich werde mir jetzt die Klasse SwingWorker und die anderen hier genannten genauer anschauen.
 
Zuletzt bearbeitet:

Michael...

Top Contributor
Thread[Thread-2,6,main]

was kann man daraus schließen?
currentThread liefert einfach nur eine Referenz auf das aktuell den Code ausführende Thread Objekt. (s. API Doku)
Was man daraus schließen kann?: Welcher Thread gerade den Code ausführt.
Ein Blick in die toString() Methode der Klasse Thread, liefert Aufschluss über die Bestandteile des ausgegeben Inhalts.
Java:
    public String toString() {
        ThreadGroup group = getThreadGroup();
	if (group != null) {
	    return "Thread[" + getName() + "," + getPriority() + "," + 
		           group.getName() + "]";
	} else {
	    return "Thread[" + getName() + "," + getPriority() + "," + 
		            "" + "]";
	}
    }
=> Thread-2: Name des Thread Objekts
=> 6, Priorität des Threads
=> Gruppe

Das hat eigentlich kaum etwas bis gar nichts mit der Verwendung von invokeLater zu tun. Die Verwendung des invokeLater Konstrukts stellt einfach nur sicher, dass der in der run() implementierte Code von EDT ausgeführt wird. Dieser Thread ist u.a. für die Darstellung der graphischen Oberfläche verantwortlich. Code der Konsequenzen auf die GUI hat sollte daher innerhalb dieses Threads ausgeführt werden.
 

Michael...

Top Contributor
Hat nur wenig mit dem Problem hier zu tun und sollte daher in einem eigenen Thread behandelt werden.
Ein Iterator ist im allgemeinen nicht thread-safe. In was für einem Objekt werden die Linien Objekte gehalten? Es gibt Thread-safe Listen über die man direkt iteriern kann.
Man könnte eine
Code:
Collections.synchronizedCollection(Collection c)
oder Collections.synchronizedList(java.util.List) verwenden.
Will man mittels Iterator über solche Listen, o.ä. iterieren, muss man dies innerhalb eines synchronized Blockes tun. (s. obigen Link in die API Doku)
 

HarryG32

Mitglied
Danke für deine Antwort, dachte die Probleme sind ziemlich ähnlich, da bei mir auch einige Swing-Klassen und der EDT Fehlermeldungen raushauen...

Das is meine Collection:

Code:
private Vector <Line2D.Double> mowingPath = new Vector <Line2D.Double>();
 

Michael...

Top Contributor
Danke für deine Antwort, dachte die Probleme sind ziemlich ähnlich, da bei mir auch einige Swing-Klassen und der EDT Fehlermeldungen raushauen...

Das is meine Collection:

Code:
private Vector <Line2D.Double> mowingPath = new Vector <Line2D.Double>();
Eine
Code:
ConcurrentModificationException
tritt bei fehlender Synchronisation und gleichzeitigem Zugriff mehrerer Threads auf. Da muss nicht mal ein EDT die Finger mit im Spiel haben.
Vector ist thread-safe entweder direkt per Schleife über den Vector iterieren oder wie in der verlinkten API Doku erst auf das Vector Objekt synchronizieren und dann mittels Iterator iterieren.
 

HarryG32

Mitglied
Danke, es geht jetzt besser, aber dennoch bekomme ich hier eine Fehlermeldung:

Code:
 for(Line2D.Double l2d : mowingPath){

Exception in thread "AWT-EventQueue-1" java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(Unknown Source)
at java.util.AbstractList$Itr.next(Unknown Source)
at drawing.DrawingBoard.paintComponent(DrawingBoard.java:115)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintToOffscreen(Unknown Source)
at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(Unknown Source)
at javax.swing.RepaintManager$PaintManager.paint(Unknown Source)
at javax.swing.RepaintManager.paint(Unknown Source)
at javax.swing.JComponent._paintImmediately(Unknown Source)
at javax.swing.JComponent.paintImmediately(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.seqPaintDirtyRegions(Unknown Source)
at javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(Unknown Source)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)

Kann ich den Thread nicht solange warten lassen bis das Zeichnen fertig is??? Das wäre im meinem Fall auch logisch??

PS: Vielleicht könnte ein Admin meine Beiträge verschieben? Tut mir leid, dass ich das Thema hier vereinnehme...
 
Zuletzt bearbeitet:

Paul279

Aktives Mitglied
So ich danke allen für Ihre Hilfe!

Jetzt habe ich einiges gelernt, danke sehr. Werde mich jetzt genauer mit SwingWorkers beschäftigen und gleichzeitig mal etwas über "The Event Dispatcher" lesen.

Es gibt noch so viel zu lernen in Java. :rtfm:

Also meine Frage wäre damit erledigt, lasse den Thread aber "offen" da ich denke, dass man sonst nichts mehr Antworten kann und ich HarryG32 noch die Möglichkeit geben will, sein Thema zu lösen.


Obwohl ich nur wenig bis gar nichts hier im Forum einbringen kann, da ich selbst noch sehr unerfahren in Java bin und ich die meisten anderen Fragen nicht verstehe um was es geht, danke ich trotzdem, dass ihr mir helft, obwohl ich selber leider nicht helfen kann.

Ich denke aber, dass meine Zeit mal kommen wird, wo ich anderen Unterstützung geben werde.

Hochachtungsvoll allen Java-Gurus
Paul
 

Marco13

Top Contributor
Die Ausgabe liefert mir:

Thread[Thread-2,6,main]

was kann man daraus schließen?

Was da steht ist eigentlich wurscht: Solange dort im Namen nicht irgendwas wie "AWT EventQueue" vorkommt, ist es nicht der EDT. Man kann auch direkt abfragen, was manchmal sinnvoll sein kann:
Java:
void doSomethingFromAnyThread()
{
    if (SwingUtilities.html.isEventDispatchThread())
    {
        // We're on the EDT, hooray!
        doSomething();
    }
    else
    {
        // That's not the EDT - wrap the action using SwingUtilities
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                doSomething();
            }
        });
    }
}
Aber das ist kein Allheilmittel - man sollte sich immer genau überlegen, welche Veränderungen an Swing-Components man von fremden Threads zulassen will (und wie gesagt, oft kommt die Aktion ohnehin schon vom EDT)

@HarryG32: Das hat wirklich nichts mit dem eigentlichen Thema zu tun. Abhilfen gibt's hier mehrere mögliche (Forensuche liefert z.B. auch http://www.java-forum.org/awt-swing...-currentmodificationexception.html#post852420 ). Allgemein könnte man sagen: Jede Änderung und jedes iterieren müssen durch "synchronized"-Blöcke vor konrurrierendem Zugriff geschützt werden. Aber auch da muss man sich überlegen, wie man das am geschicktesten macht, um nicht alles unnötig zu blockieren. Vielleicht gibt es das ja mal NOCH einen eigenen Thread dazu ;)
 

HarryG32

Mitglied
Danke Marco13 für die Hilfe, ich werde diesen Thread mal durchforsten und auch das Forum...danke auch an Paul für sein Verständnis. Für mich ist die Sache somit hier abgeschlossen.
 

Neue Themen


Oben