Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
tractor fanatic
Sep 9, 2005

Pillbug
Does anyone actually use pointer-to-member-functions (outside of the safe bool idiom)? I thought the wonky syntax and the existence of templates and virtual functions kept most people away.

Adbot
ADBOT LOVES YOU

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

tractor fanatic posted:

Does anyone actually use pointer-to-member-functions (outside of the safe bool idiom)? I thought the wonky syntax and the existence of templates and virtual functions kept most people away.

Well, not all code is appropriate or possible to template, and member function pointers are more lightweight than std::function. On the other hand, normal function pointers are even more lightweight, and std::function is a lot more flexible, so member function pointers only fill the very specific niche of wanting to do virtual dispatch without the extra overhead of std::function.

Abrahamsen
Jul 1, 2009
I hope it is okay if I link to the stackoverflow.com page for my question. It's basically about how I can't figure out setting up CEGUI in Visual Studio 2010 without getting an error or another. The reason I can't get it working is lack of experience.. well, the link explains it:
http://stackoverflow.com/questions/7857011/how-do-i-get-cegui-0-7-5-compiling-and-running-with-sfml-2-0-on-vs2010-c

I guess it is easier for me to keep track of the answers in there as well.

TasteMyHouse
Dec 21, 2006
I don't know anything about CEGui, but I might be able to help if you post your compiler errors.

Captain Cappy
Aug 7, 2008

Are you getting the errors at link time?

Open up the project settings (Project -> Properties) and see if there is anything CEGUI related in VC++ Directories, C/C++ Additional Include Directories, or Linker Additional Dependencies.

shrughes
Oct 11, 2008

(call/cc call/cc)

tractor fanatic posted:

Does anyone actually use pointer-to-member-functions (outside of the safe bool idiom)? I thought the wonky syntax and the existence of templates and virtual functions kept most people away.

Ever do this?

code:
boost::bind(&SomeType::SomeMethod, this, blah, blah, blah)
I do it all the time.

Abrahamsen
Jul 1, 2009

TasteMyHouse posted:

I don't know anything about CEGui, but I might be able to help if you post your compiler errors.

I'm spent for today heading to bed, but I would like to take you up on your offer tomorrow. I'll post my errors then. Thanks!

TasteMyHouse
Dec 21, 2006
haha what, okay. How long would it take you to post your errors before going to bed though?

Abrahamsen
Jul 1, 2009

Captain Cappy posted:

Are you getting the errors at link time?

Open up the project settings (Project -> Properties) and see if there is anything CEGUI related in VC++ Directories, C/C++ Additional Include Directories, or Linker Additional Dependencies.

I have included what I think I need in the VC++ Directories, C/C++ Additional Include Directories, or Linker Additional Dependencies.
Now I'm getting new errors though:

In debug configuration:
(The weird thing about this one is that "c:\cegui-0.7.5\cegui\include\CEGUISingleton.h" isn't the directory I have specified anywhere. CEGUI is located in "c:\libs\CEGUI-SDK-0.7.5-vc10\"


In release configuration:


TasteMyHouse posted:

haha what, okay. How long would it take you to post your errors before going to bed though?
I had shut my computer down and it was very late, I just wanted to ask for help before I went.


Edit: It's not like I prefer CEGUI over something else, I just need a GUI for my SFML C++ 2d game. CEGUI was just the system that seemed to cater to game development more directly than other options. It seems that all GUI systems I find are abandoned by their developers or at the very least poorly documented.

I see the recommended GUIs in the OP but I don't know which to choose when I'm doing a game..

Abrahamsen fucked around with this message at 12:57 on Oct 22, 2011

Bruegels Fuckbooks
Sep 14, 2004

Now, listen - I know the two of you are very different from each other in a lot of ways, but you have to understand that as far as Grandpa's concerned, you're both pieces of shit! Yeah. I can prove it mathematically.

Abrahamsen posted:

I have included what I think I need in the VC++ Directories, C/C++ Additional Include Directories, or Linker Additional Dependencies.
Now I'm getting new errors though:

In debug configuration:
(The weird thing about this one is that "c:\cegui-0.7.5\cegui\include\CEGUISingleton.h" isn't the directory I have specified anywhere. CEGUI is located in "c:\libs\CEGUI-SDK-0.7.5-vc10\"


Is this a DLL that gets included with the project or is it actually compiled on your machine? This would happen if a debug DLL was linked to the project - the path the assert failure would show would be where the source code was on the machine where it was originally compiled (I'm inferring directory structure of lib directory includes DLLS).

Kosani
Jun 30, 2004
Ni ni.
I have a little useless C++ program that I am writing to explore objects, classes, and pointers.

Currently I am trying to modify my (previously working) "Car" class so that it has an overloaded == operator with which to compare two Car objects for equality with respect to their 5 private member variable ("properties"). I am currently getting a compilation error which I assume has to do with pointers. I have no idea whats going on and could really use some help. I try to read resources/text books but they just don't explain the concepts well for me.

Here is the compilation error: (VS 2010):

code:
carEff.cpp(229) : error C3646: 'Car' : unknown override specifier
carEff.cpp (233): error C2662: 'Car::getMake' : cannot convert 'this' pointer from 'const Car' to 'Car &' 
... and repeats itself about 11 times.

Here is the header file:

code:
class Car
{
	public:
	
		// Prototypes for member functions

		// Constructor that takes no parameters (default constructor)
		Car();
		
		// Constructor that takes five parameters
		Car(string mK, string yR, 
		    double fL, double fC, double fE);
		
		//destructor
		
		
			
		// Accessor functions that retrieve the five parameters
		string getMake();
		string getYear();
		double getFuelLevel();
		double getFuelCapacity();
		double getFuelEff();
		
		// Mutator functions that modify the values of each property
		void setMake(string mK);
		void setYear(string yR);
		void setFuelLevel(double fL);
		void setFuelCapacity(double fC);
		void setFuelEff(double fE);
		
		// Member function that simulates driving the car for a certain distance
		void drive(double mL);
		
		// Member function that determines and reports which of two cars has 
		// better fuel efficiency
		string compareFuelEff(Car otherCar);
		
		// Member function that prints all of a car's object properties
		void print();
		
		// Member function that simulates trading a car object for a new car object
		void trade(Car otherCar);
		
		// Member function that simulates trading a car object for a new car object with specified properties
		void trade(string mK, string yR, 
		    double fL, double fC, double fE);
		
		// Member function that compares the properties of two car objects
		
		bool hasSameProperties(const Car &f) const; 
		
		// Define "==" for for two car objects
		bool operator==(const Car &f) const;
		
		//Destructor
		~Car();
		
	private:
		string make;
		string year;
		double fuelLvl;
		double fuelCap;
		double fuelEff;
		double miles;
			
		
		
	
	};//end class Car
and here are the problematic functions in the class definitions: line 229 from the compilation error starts at "bool Car:: hasSameProperties".

code:
bool Car::operator==(const Car &f) const {

	return hasSameProperties(f);
	}

bool Car::hasSameProperties(const Car &f) const {

	bool compare;
	
if (f.getMake() != getMake())
	compare = false;
else if (f.getYear() != getYear())
	compare = false;
else if (f.getFuelLevel() != getFuelLevel())
	compare = false;
else if (f.getFuelCapacity() != getFuelCapacity())
	compare = false;
else if (f.getFuelEff() != getFuelEff())
	compare = false;
else
	compare = true;

return compare;
	
}
I know it's a bullshit problem due to my lack of understanding, but if anyone feels like taking the time to set me straight I'd really appreciate it because I have no idea whats going on. Pointers are confusing to me at this point and I can't find a single resource that explains their precise usage in a way that I understand.

Kosani fucked around with this message at 18:28 on Oct 22, 2011

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!
The problem is that your compare functions are 'const' (ie. explicitly do not modify their 'this'), and all your 'getSomething' functions are not const. Since you call these not const functions from within the const function, the compiler is concerned that the const function might be trying to modify things.

Solution - make your get functions const.
string getMake() const;

and add a const in the same place for the function definition.

(Probably also "compareFuelEff" should be const, since it's not going to be modifying anything. It should also take a const Car& rather than a Car as a parameter, since otherwise a whole new Car is copied into that function.)

roomforthetuna fucked around with this message at 18:38 on Oct 22, 2011

Kosani
Jun 30, 2004
Ni ni.

roomforthetuna posted:

The problem is that your compare functions are 'const' (ie. explicitly do not modify their 'this'), and all your 'getSomething' functions are not const. Since you call these not const functions from within the const function, the compiler is concerned that the const function might be trying to modify things.

Solution - make your get functions const.
string getMake() const;

and add a const in the same place for the function definition.

(Probably also "compareFuelEff" should be const, since it's not going to be modifying anything. It should also take a const Car& rather than a Car as a parameter, since otherwise a whole new Car is copied into that function.)

Thank you. Your solution enabled it to compile. Is it good coding to just make everything that doesn't modify it's 'this' into a const? I thought I remembered reading that but I'm not sure why.

Abrahamsen
Jul 1, 2009

hieronymus posted:

Is this a DLL that gets included with the project or is it actually compiled on your machine? This would happen if a debug DLL was linked to the project - the path the assert failure would show would be where the source code was on the machine where it was originally compiled (I'm inferring directory structure of lib directory includes DLLS).

I got the DLL from http://www.cegui.org.uk/wiki/index.php/CEGUI_Downloads_0.7.5 - under CEGUI 0.7.5 Binary Downloads for Microsoft Visual C++ 2010. I figured that I wouldn't have to do anything to the DLLs other than link them.

tractor fanatic
Sep 9, 2005

Pillbug

Kosani posted:

Thank you. Your solution enabled it to compile. Is it good coding to just make everything that doesn't modify it's 'this' into a const? I thought I remembered reading that but I'm not sure why.

Yes, because otherwise you will run into the problem you just ran into.

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Kosani posted:

Thank you. Your solution enabled it to compile. Is it good coding to just make everything that doesn't modify it's 'this' into a const? I thought I remembered reading that but I'm not sure why.
Or at least everything that by design doesn't modify its 'this', yes. A function that currently doesn't but reasonably might is better left non-const. (eg. Car::StopAtDriveThrough(Driver&,Restaurant&) might originally change only things from the two parameters, but later you might want to have it take money from the car's glovebox or passengers or something if the driver doesn't have it on them. It's also not likely to be called from any const function, so that sort of thing you might be better off not making const.)

Technically you can avoid your compilation problem by making nothing const, but using const properly protects you from some mistakes.

tractor fanatic
Sep 9, 2005

Pillbug

roomforthetuna posted:

Technically you can avoid your compilation problem by making nothing const, but using const properly protects you from some mistakes.

The other problem with avoiding const is you can't use temporaries.

raminasi
Jan 25, 2005

a last drink with no ice

tractor fanatic posted:

The other problem with avoiding const is you can't use temporaries.

Or third-party libraries that use const.

shodanjr_gr
Nov 20, 2007
I'm porting some windows code over to OSX. Parts of the code were using windows-specific typedefs for some at some places (UINT for unsigned int, LONGLONG for long long, HRESULT, etc).

Is there some header file that I can include that will allow me to ameliorate this easily or should I do some manual typedefs instead?

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
Anywhere you write HRESULT almost certainly needs to be properly ported. You could make your own typedefs for UINT and LONGLONG, and it would probably be faster than finding someone else who's done so, but be aware that the most important OSX architecture these days is 64-bit; you might be a lot happier using uint32_t and int64_t and the like, which should also work fine on Windows.

Quebec Bagnet
Apr 28, 2009

mess with the honk
you get the bonk
Lipstick Apathy
By the way, if stdint.h isn't available on your system (e.g. Visual Studio <2010) pstdint.h is a good portable implementation.

shodanjr_gr
Nov 20, 2007

rjmccall posted:

Anywhere you write HRESULT almost certainly needs to be properly ported. You could make your own typedefs for UINT and LONGLONG, and it would probably be faster than finding someone else who's done so, but be aware that the most important OSX architecture these days is 64-bit; you might be a lot happier using uint32_t and int64_t and the like, which should also work fine on Windows.

This is some code that interfaces with the MSR Kinect API (that looks like Win32 on the C++ side and of course uses HRs). I plan to have the preprocessor take out the offending bits and pieces of code based on #defines.

So uint32_t and int64_t safely assign to UINT and LONGLONG?

Also, why does Xcode complain when I try to #typedef unsigned int UINT?

MutantBlue
Jun 8, 2001

shodanjr_gr posted:

Also, why does Xcode complain when I try to #typedef unsigned int UINT?

Because the '#' is for preprocessor directives. Don't prefix the typedef keyword with '#'.

Souper
Mar 28, 2010
Whooooore! Why won't you work?! :argh:

I'm failing at overloading the iostream << operator... someone tell me how I'm being retarded so I can hopefully be less retarded in the future. Doing this:

FractionClass.h
code:
#ifndef _FRACTIONCLASS_H
#define _FRACTIONCLASS_H
#include <iostream>

class Fraction{

private:
	int num_, den_;
//snip BS

public:
Fraction operator+(const Fraction &other) {return add(other);}
Fraction operator-(const Fraction &other) {return subtract(other);}
Fraction operator*(const Fraction &other) {return multiply(other);}
Fraction operator/(const Fraction &other) {return divide(other);}
bool operator==(const Fraction &other) { return (num_ == other.num_ && den_ == other.den_);}

//gently caress line 36 \/
friend ostream &operator<<(ostream &os, Fraction &fr);
#endif
I get these errors on compile:

1>...\fractionclass.h(36): error C2143: syntax error : missing ';' before '&'
1>...\fractionclass.h(36): error C2433: 'ostream' : 'friend' not permitted on data declarations
1>...\fractionclass.h(36): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>...\fractionclass.h(36): error C2061: syntax error : identifier 'ostream'
1>...\fractionclass.h(36): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>...\fractionclass.h(36): error C2805: binary 'operator <<' has too few parameters

delta534
Sep 2, 2011
It is a namespace issue. Put std:: before ostream and the errors will go away.

Souper
Mar 28, 2010

delta534 posted:

It is a namespace issue. Put std:: before ostream and the errors will go away.

I could kiss you right now. :h: I forgot to add using namespace std when I flipped it into it's own .h file.

Quebec Bagnet
Apr 28, 2009

mess with the honk
you get the bonk
Lipstick Apathy

Souper posted:

I could kiss you right now. :h: I forgot to add using namespace std when I flipped it into it's own .h file.

You should indeed forget this. Reference the namespace directly in the header and only put using statements in source files. Otherwise you're bound to get some very strange namespace collisions sooner or later.

Souper
Mar 28, 2010
Mmm, that makes sense. Thank you for the heads-up.

The book I'm working out of keeps all it's examples in one file. Not really workable in the real world, so I'm deliberating breaking things out into their own files to learn via trial and error.

Does anyone know of.. I dunno, an online idiot's guide to good form when making headers/ multiple file projects?

shodanjr_gr
Nov 20, 2007

MutantBlue posted:

Because the '#' is for preprocessor directives. Don't prefix the typedef keyword with '#'.

God I am a moron. Thanks....

TasteMyHouse
Dec 21, 2006

Souper posted:

I could kiss you right now. :h: I forgot to add using namespace std when I flipped it into it's own .h file.

Do not put using namespace std; into a .h file! Then the entire std namespace will be imported into everything that includes that file without the knowledge of the person using that header. e: beaten oops

TasteMyHouse fucked around with this message at 07:25 on Oct 23, 2011

Lazlo
May 1, 2002
Lately I've come to realize that I have certain materialistic needs.
I'm trying to brush up on some coding, re-doing a maze solving program from college.

I'm trying to read a maze file (just a text file with "X" for walls, "O" for end point, "I" for start point) into a pointer array, then I'll use a stack to find the solution. The problem is that I'm loving up the part where I write the individual characters of the maze into a char array.

If I output the contents of the pointer array, only the last row has any characters in it. I figure I must be overwriting something in my array building for loop, I think the "array_ptr[i] = new char[mazeSize];" isn't doing quite what I think it is. But I can't think of another way to do it.

code:
int main () {
  ifstream myMaze("Maze1.maz"); //Make this cmnd line input later
  ifstream myCountMazeRow("Maze1.maz");
  string line;
  int mazeSize, x=0,y=0, startPos, numRows;
  char pos;
  bool startFound=0;
  stack<int> R,C;
  char **array_ptr; //two * are needed because it is a pointer to a pointer

  printf("Maze Program For Funz.\n");

  if (myMaze.is_open())
    {
      numRows = findRows();  //returns number of rows
      int arrayset=0;
   
      
      while (myMaze.good() )
	{
	  getline (myMaze,line);  //Assume start point is on first line and not in the corners
	  mazeSize = line.length(); //mazeSize is the number of columns  
	  int nextline=0;

	  if (arrayset==0) 
	  {    
	      array_ptr=new char*[numRows]; //array of pointers to char objects
	      arrayset=1;
	  }
	 
     //************Something is goofed up in here	  	  
	  for(int i=0; i < (mazeSize); i++) {  //Fill in the 2 array with the coordinate info for current line	 
	    array_ptr[i] = new char[mazeSize];	// This isn't doing what I think it should be doing....   
	    array_ptr[i][y] = line[i];
	    cout << "Just written into the array at: (" << i << "," << y << ")" << " " << array_ptr[i][y] << endl;
	  }
    //***********************	 

	  while ((startFound == 0) && (x < mazeSize))  //Loop while we haven't found the start point
	    { 
	      pos = line[x];
	      startPos = findstart(pos, mazeSize); 
	      if (startPos !=0)
		startFound=1;
	      x++;                //x will be the start location when loop exits
	    
	    }
	  y++;
	  
	}   
code:

output:

      for (int t=0; t < numRows; t++)
	{
	  for (int z=0; z < mazeSize; z++)
	    {
	      cout << "Writing out from array at: (" << z << "," << t << ")" << array_ptr[z][t] << endl;
	    }
	  cout << endl;
	}
      
      myMaze.close();   

Writing out from array at: (0,0)
Writing out from array at: (1,0)
Writing out from array at: (2,0)
Writing out from array at: (3,0)
Writing out from array at: (4,0)
Writing out from array at: (5,0)
Writing out from array at: (6,0)
Writing out from array at: (7,0)
Writing out from array at: (8,0)
Writing out from array at: (9,0)
Writing out from array at: (10,0)
Writing out from array at: (11,0)
Writing out from array at: (12,0)
Writing out from array at: (13,0)
Writing out from array at: (14,0)
Writing out from array at: (15,0)

.
.
.
Writing out from array at: (0,8)X
Writing out from array at: (1,8)X
Writing out from array at: (2,8)X
Writing out from array at: (3,8)X
Writing out from array at: (4,8)X
Writing out from array at: (5,8)X
Writing out from array at: (6,8)X
Writing out from array at: (7,8)X
.
.
.
Writing out from array at: (16,8)X
Writing out from array at: (17,8)X
Writing out from array at: (18,8)X


end

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!
You've got your x and y confused in places, is the problem. You're making a new array-line every character instead of every line (your 'i' is a synonym of 'x'). Instead of array_ptr[ i] = new char[mazeSize]; inside that loop, you want array_ptr[y] = new char[mazeSize]; before the loop, and then when you're reading to it you want array_ptr[y][ i] rather than array_ptr[ i][y].

(Probably other related changes too, but hopefully that will get you going.)

TasteMyHouse
Dec 21, 2006
if the maze is square, you don't need to check what it's width it every iteration. Also, what is myCountMazeRow for? you never use it.

OneEightHundred
Feb 28, 2008

Soon, we will be unstoppable!
What's the usual strategy for dealing with circular dependencies in inline functions that are in separate headers?

i.e. Header A defines some types and some inline functions that depend on some structures in header B, but the reverse is also true.

Paniolo
Oct 9, 2007

Heads will roll.
Well, it's kind of hackish but you can turn the functions into templates.

That Turkey Story
Mar 30, 2003

OneEightHundred posted:

What's the usual strategy for dealing with circular dependencies in inline functions that are in separate headers?

i.e. Header A defines some types and some inline functions that depend on some structures in header B, but the reverse is also true.

I don't know what "usual" is, but this is what I do:

code:
// File foo.hpp
#ifndef FOO_HPP
#define FOO_HPP 

struct foo { int value; };

struct bar;

inline void use_bar( bar& );

#include "bar.hpp"

inline void use_bar( bar& bar_ )
{
  bar_.value = 5;
}

#endif //FOO_HPP
code:
// File bar.hpp
#ifndef BAR_HPP
#define BAR_HPP

struct bar { int value; };

struct foo;

inline void use_foo( foo& );

#include "foo.hpp"

inline void use_foo( foo& foo_ )
{
  foo_.value = 5;
}

#endif //BAR_HPP
So, just separate your declarations from your definitions. Put the #include in between the declaration section of your header (what would normally go in a header had you not had inline functions) and the definition section (what would normally go in a cpp).

You also don't need to write inline in both places, I'm just doing it here for clarity.

Edit: I consider this to be better than introducing separate "implementation" headers since it reduces the number of files and makes it difficult to misuse.

Lazlo
May 1, 2002
Lately I've come to realize that I have certain materialistic needs.

roomforthetuna posted:

You've got your x and y confused in places, is the problem. You're making a new array-line every character instead of every line (your 'i' is a synonym of 'x'). Instead of array_ptr[ i] = new char[mazeSize]; inside that loop, you want array_ptr[y] = new char[mazeSize]; before the loop, and then when you're reading to it you want array_ptr[y][ i] rather than array_ptr[ i][y].

(Probably other related changes too, but hopefully that will get you going.)

Thanks, I was convinced the problem was elsewhere, working now.

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!
I have a question about boost multithreading and variables. I have some threads looping on their own bools. When they go false, I exit the thread. I think sometimes this isn't working. What I've seen in the long past last time I dealt with this was that the value was getting cached, so one thread's true was another thread's false. What is there in boost's own stuff to eliminate this kind of problem. I assume there's something more robust than just declaring all the relevant stuff volatile, and I don't think mutexes are going to protect me from that. Wouldn't a mutex just ensure at one time only one thread is touching a representation of the variable?

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

Rocko Bonaparte posted:

I have some threads looping on their own bools. When they go false, I exit the thread. I think sometimes this isn't working. What I've seen in the long past last time I dealt with this was that the value was getting cached, so one thread's true was another thread's false. What is there in boost's own stuff to eliminate this kind of problem. I assume there's something more robust than just declaring all the relevant stuff volatile, and I don't think mutexes are going to protect me from that. Wouldn't a mutex just ensure at one time only one thread is touching a representation of the variable?

Volatile may or may not be what you're looking for. What you need to understand is what volatile guarantees, and what it doesn't guarantee.

Declaring a variable as volatile essentially means that all reads and writes to it actually go and touch that storage location, and it's guaranteed that those accesses won't be optimized away. It's also guaranteed that accesses to volatile variables won't be reordered with respect to each other.

What volatile doesn't guarantee is ordering with respect to non-volatile accesses. In the common multithreading scenario, your shared data isn't volatile (because that's a significant performance hit in a lot of cases), but you're using some other variable to synchronize access. In that case, volatile isn't enough, because the compiler is allowed to move the access to shared data on to the wrong side of the volatile access.

In your specific scenario, volatile may be sufficient, depending on what you're actually doing in these threads.

Adbot
ADBOT LOVES YOU

TasteMyHouse
Dec 21, 2006
Interesting reading regarding threading, reordering, and the problems therein http://www.hpl.hp.com/techreports/2004/HPL-2004-209.html

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply