Board index
FAQ Search Members Groups Register Login
 
 
 

Post new topic Reply to topic  [ 113 posts ]  Go to page Previous  1 ... 4, 5, 6, 7, 8  Next
Author Message
Post Posted: 25.07.2008 17:52  Post subject:
Offline
Heimwerkstatttuner
Heimwerkstatttuner
User avatar

Joined: 18.10.2004 15:02
Posts: 1113
Location: Schweiz
Hier mal was aus der Sparte skuriles:

Code:
for (int i = 0; i < 256; i++)
{   
   if (Match->PDF[i].iAmount != 0)
   {         
      dPi = Match->PDF[i].iGrayValue * Match->PDF[i].iAmount / 256;
      dEntropySum = dEntropySum + dPi * log(dPi);
   }
}


Dies ergibt am Schluss "NaN". Warum? Folgendes:

Code:
dPi = Match->PDF[i].iGrayValue * Match->PDF[i].iAmount / 256;


Ergibt jedesmal 0 - selbst wenn die beiden Komponenten vor dem Bruch sehr wohl mit Zahlen besetzt sind. dPi ist als double definiert.

Wenn ich jede Komponente einzeln in einer Variable speichere und dann diese sehr triviale Operation durchführe, funktioniert es.

Kann mich mal jemand erleuchten? Ich steh auf dem Schlauch.


Top
  Profile 
 
Post Posted: 25.07.2008 20:08  Post subject:
Offline
Synetic Developer
Synetic Developer
User avatar

Joined: 18.10.2004 13:48
Posts: 758
Hypothraxer wrote:
Kann mich mal jemand erleuchten? Ich steh auf dem Schlauch.


Die Berechnung wird mit Integern durchgeführt. Integer durch Integer ist immer ein Integer im Resultat, dadurch gehen die Nachkommastellen verloren. Erst nach diesem Verlust wird das Ergebnis in einen Double umgewandelt. Wenn du die Operanden erst in Doubles zwischenspeicherst, wird die Berechnung natürlich mit dem "gewünschten" Typ durchgeführt und das Ergebnis paßt.

Versuche es mal mit explizitem Casten und einem ".0" (markiert die Zahl als Double) an der Konstante:
(double) Match->PDF[i].iGrayValue * (double) Match->PDF[i].iAmount / 256.0


Top
  Profile 
 
Post Posted: 27.07.2008 12:48  Post subject:
Offline
Heimwerkstatttuner
Heimwerkstatttuner
User avatar

Joined: 18.10.2004 15:02
Posts: 1113
Location: Schweiz
Daniel wrote:

Die Berechnung wird mit Integern durchgeführt. Integer durch Integer ist immer ein Integer im Resultat, dadurch gehen die Nachkommastellen verloren. Erst nach diesem Verlust wird das Ergebnis in einen Double umgewandelt. Wenn du die Operanden erst in Doubles zwischenspeicherst, wird die Berechnung natürlich mit dem "gewünschten" Typ durchgeführt und das Ergebnis paßt.

Versuche es mal mit explizitem Casten und einem ".0" (markiert die Zahl als Double) an der Konstante:
(double) Match->PDF[i].iGrayValue * (double) Match->PDF[i].iAmount / 256.0


Das ist ja interessant. Es war mir nicht bekannt, dass der Datentyp eines Resultats durch die Datentypen in der Gleichung bestimmt werden und nicht durch die Variable, in der die Gleichung gespeichert wird.
Ich hatte zwar so etwas ähnliches vermutet und habe auch folgendes probiert:

Code:
dPi = (double)(Match->PDF[i].iGrayValue * Match->PDF[i].iAmount / 256);


Aber das funktionierte nicht. Ich werde aber deine Methode mal probieren, danke! :)

P.S.: Aus Neugier: Angenommen ich hätte in der Gleichung einen Double und einen Integer Wert. Würde dann der nächst Präzisere Datentyp gewählt? In dem Fall Double?


Top
  Profile 
 
Post Posted: 27.07.2008 13:46  Post subject:
Offline
Synetic Developer
Synetic Developer
User avatar

Joined: 18.10.2004 13:48
Posts: 758
Hypothraxer wrote:
Code:
dPi = (double)(Match->PDF[i].iGrayValue * Match->PDF[i].iAmount / 256);


Aber das funktionierte nicht. Ich werde aber deine Methode mal probieren, danke! :)


Das ist ja auch nicht ähnlich, sondern ganz anders. Da wird erst in den Klammern die komplette Berechnung mit Integern durchgeführt inklusive Division, wodurch Nachkommastellen verloren gehen. Dieses "beschädigte" Ergebnis wird, statt implizit bei der Zuweisung gecastet zu werden, jetzt halt explizit vor der Zuweisung gecastet, aber der Schaden ist längst entstanden.

Genau deshalb müssen die Operanden schon vorher umgewandelt werden, damit die Operation selbst mit dem richtigen Typ und daher ohne Verlust von Nachkommastellen durchgeführt wird.

Hypothraxer wrote:
P.S.: Aus Neugier: Angenommen ich hätte in der Gleichung einen Double und einen Integer Wert. Würde dann der nächst Präzisere Datentyp gewählt? In dem Fall Double?


Ja, im Prinzip schon. In deiner Berechnung sollte es schon reichen, wenn du 256 durch 256.0 ersetzt, damit ist der zweite Operand der Division ein Double statt Integer und der erste Operand wird implizit gecastet. Der erste Operand ist in dem Fall das Ergebnis der Multiplikation, die noch mit zwei Integern durchgeführt wird. Nachkommastellen sind an dieser Stelle unwichtig, die Multiplikation zweier Ganzzahlen erzeugt ja keine. Wenn die Zahlen groß genug sind, kann es trotzdem kritisch werden. Beispiel:

Code:
int a = 100000;
int b = 100000;
double c = 100000.0;
double d = a * b / c;
double e = (double) a * (double) b / c;


Was passiert hier? Für e ist das leicht zu klären. Dank explizitem Casting wird jede Operation mit Doubles durchgeführt, das Ergebnis in e ist 100000.0 oder zumindest etwas mit nur sehr kleiner Abweichung dazu. Floatingpoint-Werte sind nämlich niemals ganz präzise, das kann auch noch zur Stolperfalle werden falls du nicht aufpaßt. Wenn du das Ergebnis prüfen willst, greift unter Umständen (e == 100000.0) nicht, sondern erst sowas wie (abs(e - 100000.0) < 1.0e-6). Bei speziell diesen Zahlen ist aber ein exaktes Ergebnis wahrscheinlich, weil sie exakt als Double dargestellt werden können.

Aber erstmal zur Berechnung ohne explizites Casten. Erst wird a * b berechnet, was 10 Milliarden ergibt. Das paßt leider nicht in einen Integer, es werden also nur die unteren 32 Bit des Ergebnisses behalten. Das entspricht 1410065408, was für die nächste Operation implizit (weil der Divisor von einem genaueren Typ ist) in 1410065408.0 gecastet wird. Nach der Division steht in d also 14100.65408 (bzw. eine Double-Repräsentation sehr nah dran), was nicht ganz dem erwarteten Ergebnis entspricht.


Top
  Profile 
 
Post Posted: 28.07.2008 19:15  Post subject:
Offline
Heimwerkstatttuner
Heimwerkstatttuner
User avatar

Joined: 18.10.2004 15:02
Posts: 1113
Location: Schweiz
Daniel wrote:

Das ist ja auch nicht ähnlich, sondern ganz anders. Da wird erst in den Klammern die komplette Berechnung mit Integern durchgeführt inklusive Division, wodurch Nachkommastellen verloren gehen. Dieses "beschädigte" Ergebnis wird, statt implizit bei der Zuweisung gecastet zu werden, jetzt halt explizit vor der Zuweisung gecastet, aber der Schaden ist längst entstanden.

Genau deshalb müssen die Operanden schon vorher umgewandelt werden, damit die Operation selbst mit dem richtigen Typ und daher ohne Verlust von Nachkommastellen durchgeführt wird.


Tatsache - dein Code hat funktioniert :)

Daniel wrote:

Wenn du das Ergebnis prüfen willst, greift unter Umständen (e == 100000.0) nicht, sondern erst sowas wie (abs(e - 100000.0) < 1.0e-6). Bei speziell diesen Zahlen ist aber ein exaktes Ergebnis wahrscheinlich, weil sie exakt als Double dargestellt werden können.


Jup - das Thema hatten wir schonmal - mit ausführlicher Erklärung deinerseits weshalb das so ist (war glaub sogar in diesem Thread - ich fand die Erklärung auf jeden Fall super). I prüfe allerdings praktisch nie den Zahlwert exakt, sondern breche ab, sobald die zu prüfende Variable(n) unter einen bestimmten Wert sinkt/en (wie auch üblich in statistischen Ausgleichungen). Somit umschiffe ich das dann recht schön.


Top
  Profile 
 
Post Posted: 03.07.2009 10:55  Post subject: Re: Lustiges Programmieren mit Hypo (Teil n-1)
Offline
Heimwerkstatttuner
Heimwerkstatttuner
User avatar

Joined: 18.10.2004 15:02
Posts: 1113
Location: Schweiz
Ich habe mal wieder ein Problem (juhui :) ). Es sind, mal wieder, die beliebten Pointer. Zumindest glaube ich, dass dies das Problem ist. Und zwar stürzt mir das Programm ab, je nachdem, wohin ich meine 'new ...' Anweisungen setze.

Ich habe in meiner Klasse 3 Methoden:

- m_LSM_Initialize (gibt den Variablen Werte - idR. 0, 0.0, NULL)

- m_LSM_Iteration (Eine iterationsschleife, die eine Ausgleichung ausführt)

- m_LSM_Main (Liest die Bilder und Files ein und ruft dann anschliessend m_LSM_Iteration auf - wenn die Methode 'true' zurück gibt, werden die Koordinaten geschrieben)

Und nun das Problem: Ich habe im Header File (LSM.h) folgendes definiert:

Code:
// Pointers for the windows
SearchWindow *SW;
SearchValues *SV;


Und im Source-File (LSM.CPP) platziere ich das da:

Code:
SW = new SearchWindow[2];
SV = new SearchValues[iSearchSize * iSearchSize];


Das Problem? Je nachdem, in welche Methode ich den zweiten Teil platziere, funktioniert das Programm oder eben nicht.

Platziere ich die beiden 'new' Anweisungen ins m_LSM_Initialize, dann stürzt das Programm mit einer OpenCV Fehlermeldung ab, dass die Werte ausserhalb des Bildbereiches liegen, was aber nicht stimmt. Was wirklich passiert ist, dass er in der ersten Iteration die richtigen Werte aus den beiden Files rausliest und in der nächsten Iteration nicht auf die nächste Zeile springt - somit immer beim gleichen Punkt bleibt.

Ich habe mal valgrind drüber laufen lassen, und das da stach mir ins Auge (es gibt noch 3-4 gleiche Fehler):

Code:
==8404== Invalid write of size 8
==8404==    at 0x804AB81: LSM::m_LSM_Iteration(double, double, double, double, int, int, double) (LSM.cpp:304)
==8404==    by 0x804BA8B: LSM::m_LSM_Main(std::string, std::string, std::string, std::string, std::string, char*, char*, char*) (LSM.cpp:158)
==8404==    by 0x804C455: main (main.cpp:64)
==8404==  Address 0x5719608 is 0 bytes after a block of size 0 alloc'd
==8404==    at 0x402536E: operator new[](unsigned int) (vg_replace_malloc.c:268)
==8404==    by 0x804B54D: LSM::m_LSM_Initialize() (LSM.cpp:78)
==8404==    by 0x804B5F9: LSM::m_LSM_Main(std::string, std::string, std::string, std::string, std::string, char*, char*, char*) (LSM.cpp:95)
==8404==    by 0x804C455: main (main.cpp:64)


Sieht so aus, als würde er auf etwas zugreifen, was nicht mehr existiert. Da ich den Pointer aber nicht gelöscht habe, verwundert mich das ein wenig.
Wenn ich dann die beiden 'new' Anweisungen ins m_LSM_Iteration reinpacke, funktioniert es einwandfrei. Valgrind hat dann auch keine grösseren Probleme mehr gefunden:

Code:
==8703== LEAK SUMMARY:
==8703==    definitely lost: 0 bytes in 0 blocks.
==8703==      possibly lost: 0 bytes in 0 blocks.
==8703==    still reachable: 4,188 bytes in 3 blocks.
==8703==         suppressed: 0 bytes in 0 blocks.
==8703== Rerun with --leak-check=full to see details of leaked memory.


Verwundern tut mich das v.a. deshalb, weil ich eine ähnliche Konstruktion in einem anderen Programm habe und es da einwandfrei funktioniert.

Hat jemand grad eine Idee, woran das liegen könnte? Auf Wunsch kann ich auch gerne den ganzen Quellcode zur Verfügung stellen (gekürzt - die Algorithmen selbst sind ja nicht so wichtig).

P.S.: Die übrigen Leaks stammen von der MATPACK-Library. Falls jemand eine gute Mathematik Library kennt, wo man relativ einfach Matrizen, Vektoren etc. basteln und berechnen kann, so wäre ich froh um einen Hinweis :)


Top
  Profile 
 
Post Posted: 03.07.2009 12:05  Post subject: Re: Lustiges Programmieren mit Hypo (Teil n-1)
Offline
Schattenparker
Schattenparker
User avatar

Joined: 18.10.2004 18:02
Posts: 191
Location: Scherzingen
Schwierig, ohne den Code zu sehen. ;)
Sind iSearchSize und iSearchSize konstant? Oder ändern die sich vielleicht irgendwo (werden vielleicht erst später gesetzt?). Es kann auch immer an ganz anderen Variablen liegen, die dann Nebenwirkungen haben.


Top
  Profile 
 
Post Posted: 03.07.2009 12:12  Post subject: Re: Lustiges Programmieren mit Hypo (Teil n-1)
Offline
Synetic Developer
Synetic Developer
User avatar

Joined: 18.10.2004 13:48
Posts: 758
Du definierst globale Variablen in einer Header-Datei? Ganz böse, damit hätte jede der Source-Dateien, die diesen Header inkludiert, eine eigene Kopie. Eigentlich sollte bei sowas der Linker über mehrfach definierte Symbole motzen. Versuch mal stattdessen, deine globalen Pointer in einer Source-Datei zu definieren und im Header nur eine Deklaration unterzubringen. Etwa so:

Code:
// Header (*.h)
extern SearchWindow *SW;
extern SearchValues *SV;

Code:
// Source (*.cpp)
SearchWindow *SW = NULL;
SearchValues *SV = NULL;


Falls die Methoden, die diese Variablen verwenden, auf mehrere Sourcen aufgeteilt sind, ist das mit hoher Wahrscheinlichkeit das Problem. Wenn nur eine Source den Header inkludiert, ist es nur noch unsauber, das Problem müßte dann aber woanders liegen.


Top
  Profile 
 
Post Posted: 03.07.2009 12:45  Post subject: Re: Lustiges Programmieren mit Hypo (Teil n-1)
Offline
Heimwerkstatttuner
Heimwerkstatttuner
User avatar

Joined: 18.10.2004 15:02
Posts: 1113
Location: Schweiz
Dirk Plate wrote:
Schwierig, ohne den Code zu sehen. ;)
Sind iSearchSize und iSearchSize konstant? Oder ändern die sich vielleicht irgendwo (werden vielleicht erst später gesetzt?). Es kann auch immer an ganz anderen Variablen liegen, die dann Nebenwirkungen haben.


Dem kann ich gern nachhelfen :)

http://www.photogrammetry.ethz.ch/gener ... SM_Odd.zip (übersichtshalber ist der Algorithmus selbst im m_LSM_Iteration nicht drin)

Die iSearchSize ändert sich während den Iterationen nicht. Müsste also an sich kein Problem geben.

Daniel wrote:
Du definierst globale Variablen in einer Header-Datei?


Die Variablen sind als 'private' deklariert. Aber es stimmt von daher schon: jede source, die das Ding included, bekommt das. Da ich aber momentan nur mit einer Source arbeiten, wird das wohl der Grund sein, warum er sich nicht beschwert?

Momentan liegen alle methoden in der gleichen source-Datei drin.

Edit: Mit

Code:
   extern SearchWindow *SW;
   extern SearchValues *SV;


im Header, beschwert sich der Compiler:

Code:
../LSM.h:145: error: storage class specified for ‘SW’
../LSM.h:146: error: storage class specified for ‘SV’


Top
  Profile 
 
Post Posted: 03.07.2009 13:34  Post subject: Re: Lustiges Programmieren mit Hypo (Teil n-1)
Offline
Synetic Developer
Synetic Developer
User avatar

Joined: 18.10.2004 13:48
Posts: 758
Hypothraxer wrote:
Die Variablen sind als 'private' deklariert.


Ah, also Membervariablen innerhalb einer Klasse. Ich bin von globalen Variablen ausgegangen, weil für mich nichts anderes ersichtlich war aus deinem Posting. In dem Fall solltest du das dazu von mir gesagte ignorieren.


Top
  Profile 
 
Post Posted: 03.07.2009 16:01  Post subject: Re: Lustiges Programmieren mit Hypo (Teil n-1)
Offline
Schattenparker
Schattenparker
User avatar

Joined: 18.10.2004 18:02
Posts: 191
Location: Scherzingen
Vielleicht irre ich mich, aber in der "m_LSM_Initialize" erstellst du das SearchValues-Array immer mit [0], da iSearchSize in der selben Methode auf 0 gesetzt wird und nirgends sonst in der Methode einen sinnvollen Wert bekommt.


Top
  Profile 
 
Post Posted: 03.07.2009 16:34  Post subject: Re: Lustiges Programmieren mit Hypo (Teil n-1)
Offline
Heimwerkstatttuner
Heimwerkstatttuner
User avatar

Joined: 18.10.2004 15:02
Posts: 1113
Location: Schweiz
Dirk Plate wrote:
Vielleicht irre ich mich, aber in der "m_LSM_Initialize" erstellst du das SearchValues-Array immer mit [0], da iSearchSize in der selben Methode auf 0 gesetzt wird und nirgends sonst in der Methode einen sinnvollen Wert bekommt.


Du hast ja so recht! Manchmal sieht man den Wald vor lauter Bäumen nicht mehr. Dank dir! :)

Daniel wrote:
Ich bin von globalen Variablen ausgegangen, weil für mich nichts anderes ersichtlich war aus deinem Posting.


Ja - ich wollte ursprünglich den ganzen Quellcode posten, was jedoch etwas zu lang geworden wäre. Ich habe so die Angewohnheit, nicht genau genug zu spezifizieren (mehr aus Unwissenheit als aus Absicht :) ).

Da wir ja grad so schön dabei sind, hier noch ein kleines Problem:

Code:
while (!fsInputFile.eof())
      {
         // Read Values from file
         fsInputFile >> dAzimuth;
         fsInputFile >> dElevation;
         fsInputFile >> dRoll;

         m_CalculateAngles(iSwitch); // Calculate angles

         // Write values back to the output file
         fsOutputFile << dOmega << " ";
         fsOutputFile << dPhi << " ";
         fsOutputFile << dKappa << "\n";
      }


Ist ja ein relativ simpler Fall - ich lese aus einem File so lange aus, bis keine Einträge mehr drin sind. Soweit so gut - nur scheint er mir immer noch einen zusätzlichen Eintrag zu lesen. D.h. wenn ich 3 Einträge in der Quelldatei habe, schreibt er mir 4 raus. Ich vermute, dass ein Carriage-Return versteckt ist, den ich nicht löschen kann. Im Editor ist auf jeden Fall keiner zu sehen und ich bin da ein wenig irritiert. Die Ausgabe der 4. Zeile ist nämlich wilkürlich (also irgendwelche Zahlen und nicht etwa die letzte Reihe nochmal).

Der gesamte Quellcode ist hier zu finden: http://www.photogrammetry.ethz.ch/gener ... angles.zip


Top
  Profile 
 
Post Posted: 05.07.2009 10:54  Post subject: Re: Lustiges Programmieren mit Hypo (Teil n-1)
Offline
Schattenparker
Schattenparker
User avatar

Joined: 18.10.2004 18:02
Posts: 191
Location: Scherzingen
Hallo Hypo,
bei mir ist am Ende der Datei noch ein Zeilenumbruch (sogar ein windowsmäßiger). Dadurch ist das eof() noch nicht durch das letzte Float einlesen erreicht. Hier eine recht interessante Beschreibung der Fallstricke bei eof():
http://fara.cs.uni-potsdam.de/~kaufmann//faqs/eof.pdf


Top
  Profile 
 
Post Posted: 05.07.2009 22:25  Post subject: Re: Lustiges Programmieren mit Hypo (Teil n-1)
Offline
Heimwerkstatttuner
Heimwerkstatttuner
User avatar

Joined: 18.10.2004 15:02
Posts: 1113
Location: Schweiz
Dirk Plate wrote:
Hallo Hypo,
bei mir ist am Ende der Datei noch ein Zeilenumbruch (sogar ein windowsmäßiger). Dadurch ist das eof() noch nicht durch das letzte Float einlesen erreicht. Hier eine recht interessante Beschreibung der Fallstricke bei eof():
http://fara.cs.uni-potsdam.de/~kaufmann//faqs/eof.pdf


Interessant. Unter Linux seh ich da irgendwie nichts. Ich werde sehen, ob mir dein PDF weiterhilft. Sieht ja sehr gut aus - danke! :)


Top
  Profile 
 
Post Posted: 20.10.2009 20:14  Post subject: Re: Lustiges Programmieren mit Hypo (Teil n-1)
Offline
Heimwerkstatttuner
Heimwerkstatttuner
User avatar

Joined: 18.10.2004 15:02
Posts: 1113
Location: Schweiz
Ich hab hier wieder so ein interessantes Problem:

Und zwar habe ich ein Programm, das in C geschrieben wurde. Den Quellcode habe ich, aber ich bin zu faul und zu wenig erfahren, das Ganze nach C++ zu konvertieren. Idee: Ich rufe die Binary aus dem C++ code auf.

Soweit so gut - das funktioniert auch. Wenn ich aber dem C-Programm sage, es soll einen Integer 'return'-en, gibt's Ärger.

Dieser Aufruf geht ohne weiteres (ohne return im C-Programm):

Code:
system(sFilenameWithArguments.c_str());


Wenn ich allerdings den integer-Wert, den das C-Programm ins return speichert, so im C++ Programm speichern will, gibt's ein kleines Chaos:

Code:
DB->cs->iImagePointCount = system(sFilenameWithArguments.c_str());


Der Code im C-Programm sieht so aus (teilweise):

Code:
for( i = 0; i < n1; i++ )
     {
        feat = feat1 + i;
        k = kdtree_bbf_knn( kd_root, feat, 2, &nbrs, KDTREE_BBF_MAX_NN_CHKS );
        if( k == 2 )
        {
           d0 = descr_dist_sq( feat, nbrs[0] );
           d1 = descr_dist_sq( feat, nbrs[1] );
           if( d0 < d1 * NN_SQ_DIST_RATIO_THR )
           {

              pt1 = cvPoint( cvRound( feat->x ), cvRound( feat->y ) );
              pt2 = cvPoint( cvRound( nbrs[0]->x ), cvRound( nbrs[0]->y ) );

              fprintf (pLeft, "%d ", m);
              fprintf (pLeft, "%f ", feat->x);
              fprintf (pLeft, "%f \n", feat->y);

              fprintf (pRight, "%d ", m);
              fprintf (pRight, "%f ", nbrs[0]->x);
              fprintf (pRight, "%f \n", nbrs[0]->y);

              pt2.y += img1->height;
              cvLine( stacked, pt1, pt2, CV_RGB(0,255,0), 1, 8, 0 );
              m++;
              feat1[i].fwd_match = nbrs[0];
           }
        }
        free( nbrs );
     }
    fprintf( stderr, "Found %d total matches\n", m );

  cvReleaseImage( &stacked );
  cvReleaseImage( &img1 );
  cvReleaseImage( &img2 );
  kdtree_release( kd_root );
  free( feat1 );
  free( feat2 );
  return m;


Ich 'return'-e also das 'm'. Wenn das Programm durchläuft, zeigt es mir die richtige Anzahl an, via das fprintf (611). Wenn ich aber dann das m im C++ Programm speichere, habe ich statt 611, 25344 in der Variable DB->cs->iImagePointCount stehen.

Warum, ist mir ein wenig schleierhaft. Was aber noch interessant ist: Das Ganze bleibt konstant. Beispiel: Wenn ich im C Programm m = 1 setze, bekommt die Variable im C++ Programm den Wert 256. Für m = 2 => 512. Das setzt sich so fort - aber ab einem gewissen Punkt stimmt das dann nicht mehr. 611 gibt, wie oben schon gezeigt, 25344 - und nicht 156416 (allerdings wäre das selbst dann noch ein Schmarn - es sollte 611 sein).

Weiss da jemand, was das sein könnte?


Top
  Profile 
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 113 posts ]  Go to page Previous  1 ... 4, 5, 6, 7, 8  Next


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  



 
   
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group