mingw and js

Want to discuss changes to the UOX3 source code? Got a code-snippet you'd like to post? Anything related to coding/programming goes here!
Post Reply
punt
VIP
Posts: 244
Joined: Wed Mar 24, 2004 7:46 pm
Has thanked: 0
Been thanked: 9 times

mingw and js

Post by punt »

I don't know if UOX even compiles under mingw, but if one wants the js engine to compile under mingw, I offer the following (credit goes to two sources with modifications).

1. First, incorperation of jsjen might simplify a lot of uox code. http://www.cs.unm.edu/~cello/jsgen/

2. Another source of mingw/spidermonkey is on SF
http://sourceforge.net/docman/display_d ... p_id=50913


Ok, so you have checked out the mozilla js source (will let another thread cover that topic).

This does not address building the nslib for threaded operation. Not sure that the current UOX worries about that either.

The following make file will build fdlib. Modify SRCDIR to where you have the code:

Code: Select all

# Project: fdlibm

CC = mingw32-gcc.exe
SRCDIR	= mozilla/js/src/fdlibm

OBJECTS= \
	$(SRCDIR)/w_sqrt.o \
	$(SRCDIR)/e_pow.o \
	$(SRCDIR)/e_sqrt.o \
	$(SRCDIR)/k_standard.o \
	$(SRCDIR)/s_atan.o \
	$(SRCDIR)/s_finite.o \
	$(SRCDIR)/s_isnan.o \
	$(SRCDIR)/s_matherr.o \
	$(SRCDIR)/s_rint.o \
	$(SRCDIR)/s_scalbn.o \
	$(SRCDIR)/w_atan2.o \
	$(SRCDIR)/e_atan2.o \
	$(SRCDIR)/s_fabs.o \
	$(SRCDIR)/s_copysign.o \
	$(SRCDIR)/w_pow.o \
	$(SRCDIR)/s_lib_version.o

LIBS =	-llibm
BIN  = fdlibm.lib
CFLAGS = -D_IEEE_LIBM -DWIN32 -D_WINDOWS -s

.c.o:
	$(CC) -c $(CFLAGS) -o $@ $*.c

$(BIN): $(OBJECTS)
	ar r $(BIN) $(OBJECTS)
	ranlib $(BIN)


Now, two files must be edited in mozilla/js/src

Before building SpiderMonkey you have to change jsosdep.h. Basically you have to add the following:
#ifdef _MINGW
#undef JS_HAVE_LONG_LONG
#else
#define JS_HAVE_LONG_LONG
#endif



In jslibmath.h change
#if defined(_WIN32) && !defined(__MWERKS__)
#define JS_USE_FDLIBM_MATH 1

to
#if defined(_WIN32) && !defined(__MWERKS__)
#define JS_USE_FDLIBM_MATH 0


Now the make file for building js is:

Code: Select all


# Project: js32

CC   = mingw32-gcc.exe

WINDRES = windres.exe
RES  = js.res
SRCDIR	= mozilla/js/src
OBJECTS = \
	$(SRCDIR)/jsapi.o \
	$(SRCDIR)/jsarena.o \
	$(SRCDIR)/jsarray.o \
	$(SRCDIR)/jsatom.o \
	$(SRCDIR)/jsbool.o \
	$(SRCDIR)/jscntxt.o \
	$(SRCDIR)/jsdate.o \
	$(SRCDIR)/jsdbgapi.o \
	$(SRCDIR)/jsdhash.o \
	$(SRCDIR)/jsdtoa.o \
	$(SRCDIR)/jsemit.o \
	$(SRCDIR)/jsexn.o \
	$(SRCDIR)/jsfun.o \
	$(SRCDIR)/jsgc.o \
	$(SRCDIR)/jshash.o \
	$(SRCDIR)/jsinterp.o \
	$(SRCDIR)/jslock.o \
	$(SRCDIR)/jslog2.o \
	$(SRCDIR)/jslong.o \
	$(SRCDIR)/jsmath.o \
	$(SRCDIR)/jsnum.o \
	$(SRCDIR)/jsobj.o \
	$(SRCDIR)/jsopcode.o \
	$(SRCDIR)/jsparse.o \
	$(SRCDIR)/jsprf.o \
	$(SRCDIR)/jsregexp.o \
	$(SRCDIR)/jsscan.o \
	$(SRCDIR)/jsscope.o \
	$(SRCDIR)/jsscript.o \
	$(SRCDIR)/jsstr.o \
	$(SRCDIR)/jsutil.o \
	$(SRCDIR)/jsxdrapi.o \
	$(SRCDIR)/prmjtime.o \
	$(SRCDIR)/jsxml.o \
	$(RES)

LIBS =  --add-stdcall-alias -lfdlibm -L.
BIN  = js.dll
CFLAGS = -DXP_PC -DXP_WIN -DEXPORT_JS_API -D_WINDOWS -DWIN32 -D_MINGW -D_declspec=__declspec -s 

DLLWRAP=dllwrap.exe
DEFFILE=libjs.def
STATICLIB=libjs.a

.c.o:
	$(CC) -c $(CFLAGS) -o $@ $*.c

$(BIN): $(OBJECTS)
	$(CC) -shared -o $@ \
	-Wl,--output-def,$(DEFFILE) \
	-Wl,--out-implib,$(STATICLIB) \
	$(OBJECTS) \
	$(LIBS)

$(RES): 
	$(WINDRES) -i $(SRCDIR)/js3240.rc -I rc -o $(RES) -O coff 


Note this make file is slightly different then the one on the references Sourceforge page (it has the xml file, and the declrations are slightly different).
punt
VIP
Posts: 244
Joined: Wed Mar 24, 2004 7:46 pm
Has thanked: 0
Been thanked: 9 times

Post by punt »

I can now say, I do know if UOX compiles under mingw from cvs. The answer is no, it doesn't.

A lot of the issue is the use of a platform to determine things versus basing it off the compilier.
The other major culprit is pasing defined classes (like a ustring) to a va_arg versus having it resolve to a native type first.

there are others as well. But not really sure where UOX stands anymore on other platforms/compiliers other then MSVC. Probably would have to understand that before any consistent approach to changing it could be undertaken.
giwo
Developer
Posts: 1780
Joined: Fri Jun 18, 2004 4:17 pm
Location: California
Has thanked: 0
Been thanked: 0

Post by giwo »

Not suprised it doesn't compile under mingw (actually quite obvious it wouldn't since we do all the WIN32 comparisons) just sad that it doesn't.

I'd like to actually go about getting this worked out as soon as possible, at least in areas that aren't scheduled to receive love in the nearby future.

I think the goal for UOX3 should be Win32 (MSVC, mingw) and Linux (gcc) as the primary platforms, with any other major variation being a port. Based on this, I would like to develop a good system to support specific platform... needs... with as little #define's as possible, using them just where necesarry.
Scott
jr
UOX3 Newbie
Posts: 15
Joined: Mon Mar 07, 2005 1:40 pm
Location: Kiel
Has thanked: 0
Been thanked: 0

Post by jr »

I can now say, I do know if UOX compiles under mingw from cvs. The answer is no, it doesn't.

A lot of the issue is the use of a platform to determine things versus basing it off the compilier.
The other major culprit is pasing defined classes (like a ustring) to a va_arg versus having it resolve to a native type first.
Yes, but getting it to compile and do something on cygwin and gcc 3.4.1 was not that difficult. (cygwin is easier than mingw, because platform.h assumes gcc -> unix, which obviously works better with unix like headers and libc :) )

After adding configure.in and the mozilla directory from the uox3 CVS to the openuo CVS and updating automake.am with the current source list it only needed some slight tweaking to allow startup with an empty world, logging in and walking around, and clean shutdown. Probably not much else will work, but it should be a starting point.

Following are the (pretty minor) diffs to satisfy the compiler (without fixing the va_arg issue yet, which fortunately is just a warning and not necessary for logging in :) ):

Code: Select all

Index: Platform.h
===================================================================
RCS file: /cvsroot/openuo/projects/uox3/source/Platform.h,v
retrieving revision 1.2
diff -b -B -d -u -I\$$ -r1.2 Platform.h
--- Platform.h	19 Feb 2005 02:38:32 -0000	1.2
+++ Platform.h	7 Mar 2005 13:05:52 -0000
@@ -33,6 +33,8 @@
 #elif defined( __GNUC__ )
 #   define UOX_COMPILER COMPILER_GNUC
 #   define UOX_COMP_VER __VERSION__
+#define FALSE 0L
+#define TRUE  1L
 
 #elif defined( __BORLANDC__ )
 #   define UOX_COMPILER COMPILER_BORL
Index: boats.cpp
===================================================================
RCS file: /cvsroot/openuo/projects/uox3/source/boats.cpp,v
retrieving revision 1.8
diff -b -B -d -u -I\$$ -r1.8 boats.cpp
--- boats.cpp	30 Dec 2004 07:02:24 -0000	1.8
+++ boats.cpp	7 Mar 2005 13:05:52 -0000
@@ -582,7 +582,8 @@
 
 	CPPauseResume prSend( 1 );
 	SOCKLIST nearbyChars = FindNearbyPlayers( b, DIST_BUILDRANGE );
-	for( SOCKLIST_CITERATOR cIter = nearbyChars.begin(); cIter != nearbyChars.end(); ++cIter  )
+	SOCKLIST_CITERATOR cIter;
+	for( cIter = nearbyChars.begin(); cIter != nearbyChars.end(); ++cIter  )
 	{
 		(*cIter)->Send( &prSend );
 	}
Index: cAccountClass.h
===================================================================
RCS file: /cvsroot/openuo/projects/uox3/source/cAccountClass.h,v
retrieving revision 1.3
diff -b -B -d -u -I\$$ -r1.3 cAccountClass.h
--- cAccountClass.h	13 Jan 2005 06:49:26 -0000	1.3
+++ cAccountClass.h	7 Mar 2005 13:05:52 -0000
@@ -23,7 +23,7 @@
 
 #if UOX_PLATFORM != PLATFORM_WIN32
 	#include <dirent.h>
-	#define strnicmp(a,b,c) strncasecmp(a,b,c)
+//	#define strnicmp(a,b,c) strncasecmp(a,b,c)
 	#define _stat stat
 	#define _mkdir mkdir
 	#define _rmdir rmdir
Index: pcmanage.cpp
===================================================================
RCS file: /cvsroot/openuo/projects/uox3/source/pcmanage.cpp,v
retrieving revision 1.12
diff -b -B -d -u -I\$$ -r1.12 pcmanage.cpp
--- pcmanage.cpp	1 Mar 2005 04:59:21 -0000	1.12
+++ pcmanage.cpp	7 Mar 2005 13:05:52 -0000
@@ -305,7 +305,7 @@
 //o--------------------------------------------------------------------------o
 void CPICreateCharacter::newbieItems( CChar *mChar )
 {
-	const enum NewbieItems
+        /*const*/ enum NewbieItems
 	{
 		HAIR = 0,
 		BEARD,
Erros in the console thread caused Shutdown to be called from the console thread which crashes. The fix is:

Code: Select all

Index: uox3.cpp
===================================================================
RCS file: /cvsroot/openuo/projects/uox3/source/uox3.cpp,v
retrieving revision 1.17
diff -b -B -d -u -I\$$ -r1.17 uox3.cpp
--- uox3.cpp	5 Mar 2005 18:40:07 -0000	1.17
+++ uox3.cpp	7 Mar 2005 13:05:53 -0000
@@ -146,7 +146,7 @@
 	if( s < 0 )
 	{
 		Console.Error( 1, "Error scanning key press" );
-		Shutdown( 10 );
+                messageLoop << MSG_SHUTDOWN;
 	}
 	if( s > 0 )
 	{
@@ -173,7 +173,7 @@
 	if( bytes_written != 1 || asw == 0 )
 	{
 		Console.Warning( 1, "Using cluox-io" );
-		Shutdown( 10 );
+                messageLoop << MSG_SHUTDOWN;
 	}
 	c = (UI08)fgetc( stdin );
 	if( c == 0 )
@@ -258,7 +258,7 @@
 #endif
 	messageLoop << "Thread: CheckConsoleKeyThread Closed";
 #if UOX_PLATFORM != PLATFORM_WIN32
-	return NULL;
+	pthread_exit( NULL );
 #endif
 }
 //	EviLDeD	-	End
To find all DFNs (if they are read correctly, I don't know) the following fix is necessary:

Code: Select all

Index: cServerDefinitions.cpp
===================================================================
RCS file: /cvsroot/openuo/projects/uox3/source/cServerDefinitions.cpp,v
retrieving revision 1.9
diff -b -B -d -u -I\$$ -r1.9 cServerDefinitions.cpp
--- cServerDefinitions.cpp	19 Feb 2005 02:38:32 -0000	1.9
+++ cServerDefinitions.cpp	7 Mar 2005 13:05:52 -0000
@@ -492,13 +492,12 @@
 		{ 
 			if( strcmp( dirp->d_name, "." ) && strcmp( dirp->d_name, ".." ) ) 
 			{ 
-				subdirectories.push_back( cDirectoryListing( currentDir + "/" + dirp->d_name, extension, doRecursion ) ); 
-				Console.Print( "%s/%s/n", currentDir.c_str(), dirp->d_name ); 
+				subdirectories.push_back( cDirectoryListing( dirp->d_name, extension, doRecursion ) ); 
 				continue; 
 			} 
 		} 
 		shortList.push_back( dirp->d_name ); 
-		sprintf( filePath, "%s/%s", currentDir.c_str(), dirp->d_name ); 
+		sprintf( filePath, "%s/%s", CurrentWorkingDir().c_str(), dirp->d_name ); 
 		filenameList.push_back( filePath ); 
 	} 
 
The following fix is probably only necessary for cygwin, but it also fixes a potential security problem: the first connection is accepted to file descriptor 81 (using the default DFN/JS files), probably because not all opened files are closed. Since cygwin FD_SETSIZE defaults to 64, the result is that select doesn't work correctly and causes memory corruption (a quick google search indicates that this doesn't seem to be a problem for windows). The fix is setting FD_SETSIZE to something large enough and catching too large fd numbers:

Code: Select all

Index: network.cpp
===================================================================
RCS file: /cvsroot/openuo/projects/uox3/source/network.cpp,v
retrieving revision 1.11
diff -b -B -d -u -I\$$ -r1.11 network.cpp
--- network.cpp	5 Mar 2005 18:40:07 -0000	1.11
+++ network.cpp	7 Mar 2005 13:05:52 -0000
@@ -1,3 +1,5 @@
+#define FD_SETSIZE 256
+
 #include "uox3.h"
 #include "network.h"
 #include "books.h"
@@ -292,6 +294,11 @@
 		newClient = accept( a_socket, (struct sockaddr *)&client_addr, &len );
 #else
 		newClient = accept( a_socket, (struct sockaddr *)&client_addr, (socklen_t *)&len );
+                if (newClient >= FD_SETSIZE)
+                {
+			Console.Error( 0, "accept() returning unselectable fd!" );
+                        return;
+                }
 #endif
 		CSocket *toMake = new CSocket( newClient );
 		if( newClient < 0 )
I've also done some slight changes to the unix console support:

Code: Select all

Index: uox3.cpp
===================================================================
RCS file: /cvsroot/openuo/projects/uox3/source/uox3.cpp,v
retrieving revision 1.17
diff -b -B -d -u -I\$$ -r1.17 uox3.cpp
--- uox3.cpp	5 Mar 2005 18:40:07 -0000	1.17
+++ uox3.cpp	7 Mar 2005 13:05:53 -0000
@@ -3218,17 +3218,16 @@
 #endif
 		const UI32 currentTime = 0;
 		
-#if UOX_PLATFORM == PLATFORM_WIN32
 		sprintf( temp, "%s v%s.%s", CVersionClass::GetProductName().c_str(), CVersionClass::GetVersion().c_str(), CVersionClass::GetBuild().c_str() );
 		Console.Start( temp );
-#else
+
+#if UOX_PLATFORM != PLATFORM_WIN32
 		signal( SIGPIPE, SIG_IGN ); // This appears when we try to write to a broken network connection
 		signal( SIGTERM, &endmessage );
 		signal( SIGQUIT, &endmessage );
 		signal( SIGINT, &endmessage ); 
 		signal( SIGILL, &illinst );
 		signal( SIGFPE, &aus );
-		
 #endif
 		
 		Console.PrintSectionBegin();
Index: cConsole.cpp
===================================================================
RCS file: /cvsroot/openuo/projects/uox3/source/cConsole.cpp,v
retrieving revision 1.5
diff -b -B -d -u -I\$$ -r1.5 cConsole.cpp
--- cConsole.cpp	27 Aug 2004 07:03:10 -0000	1.5
+++ cConsole.cpp	7 Mar 2005 13:05:52 -0000
@@ -15,6 +15,13 @@
 #include "uox3.h"
 #include "cConsole.h"
 
+#if UOX_PLATFORM != PLATFORM_WIN32
+#include <stdio.h>
+#include <unistd.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#endif
+
 namespace UOX
 {
 
@@ -34,7 +41,7 @@
 //|   Purpose     -  Class Constructor and deconstructor
 //o---------------------------------------------------------------------------o
 CConsole::CConsole() : left( 0 ), top( 0 ), height( 25 ), width( 80 ), filterSettings( 0xFFFF ), 
-currentMode( NORMALMODE ),currentLevel( 0 ), previousColour( CNORMAL ), logEcho( false )
+currentMode( NORMALMODE ),currentLevel( 0 ), previousColour( CNORMAL ), logEcho( false ), forceNL (false)
 {
 }
 
@@ -397,6 +404,11 @@
 	curLeft = 0;
 	curTop = 0;
 	TurnNormal();
+
+        if (forceNL)
+        {
+          (*this) << myendl;
+        }
 }
 
 //o---------------------------------------------------------------------------o
@@ -408,12 +420,42 @@
 //o---------------------------------------------------------------------------o
 void CConsole::Start( char *temp )
 {
-#if !defined(__unix__)
+#if UOX_PLATFORM == PLATFORM_WIN32
 	hco		= GetStdHandle( STD_OUTPUT_HANDLE );
 	GetConsoleScreenBufferInfo( hco, &csbi );
 	width	= csbi.dwSize.X;
 	height	= csbi.dwSize.Y;
 	SetConsoleTitle( temp );
+#else
+        // TODO: unix console handling should really be replaced by (n)curses or
+        // something
+
+        if (isatty (0))
+        {
+          struct termios tio;
+          struct winsize winsz;
+
+          // switch to raw mode
+          tcgetattr (0, &tio);
+
+          tio.c_lflag &= ~ICANON & ~ECHO;
+
+          tcsetattr (0, TCSAFLUSH, &tio); //ignore errors
+
+          // get window size
+          ioctl (0, TIOCGWINSZ, &winsz);
+
+          width = winsz.ws_col;
+          height = winsz.ws_row;
+
+          // disable stdout buffering
+          setvbuf (stdout, NULL, _IONBF, 0);
+        }
+        else
+        {
+          // produce readable log
+          forceNL = true;
+        }
 #endif
 }
 
Index: cConsole.h
===================================================================
RCS file: /cvsroot/openuo/projects/uox3/source/cConsole.h,v
retrieving revision 1.4
diff -b -B -d -u -I\$$ -r1.4 cConsole.h
--- cConsole.h	25 Nov 2004 04:14:05 -0000	1.4
+++ cConsole.h	7 Mar 2005 13:05:52 -0000
@@ -102,7 +102,7 @@
 	UI16	filterSettings;
 	UI08	currentMode, currentLevel;
 	UI08	previousColour;
-	bool	logEcho;
+	bool	logEcho, forceNL;
 #if UOX_PLATFORM == PLATFORM_WIN32
 	HANDLE						hco;
 	CONSOLE_SCREEN_BUFFER_INFO	csbi;
giwo
Developer
Posts: 1780
Joined: Fri Jun 18, 2004 4:17 pm
Location: California
Has thanked: 0
Been thanked: 0

Post by giwo »

Wow, excellent work!

I would very much appreciate if you could send me your changes (jowig_81 at yahoo.com) so I can put them up on the CVS. As for the va_arg issue, I plan on fixing that as soon as I get some spare moments, I don't see it being much of a problem to address.

Thanks :)
Scott
punt
VIP
Posts: 244
Joined: Wed Mar 24, 2004 7:46 pm
Has thanked: 0
Been thanked: 9 times

Post by punt »

I never expected cygwin to be has hard, as it makes it windows look like a linux environment. However, I don't know many "windows" dev who actually use cygwin (with the platform dll).


I know for my windows stuff, I don't use it.


So yea, a step of course, but wasn't what I started with as an objective.

The point is simplier, it has system that defines platform and compilier. Many of the checks are checking platform, whehn it should be checking compilier, or even more , platform and then compilier. If that isn't going to be done correctly, then why add the system to define both? Just an unecessary complication.
giwo
Developer
Posts: 1780
Joined: Fri Jun 18, 2004 4:17 pm
Location: California
Has thanked: 0
Been thanked: 0

Post by giwo »

So in an effort to get UOX3 compliant with gcc and working both on Linux and mingw, I've downloaded and setup mingw, with the help of punt.

Currently I'm working on a makefile, making use of tmake, but I'm running into an issue.

When compiling about half of the .cpp files, the compiler exits with an error level of 1. It will only continue to build the next file down the line if I do a -i switch to have it ignore the errors. This, however, causes the .o files not to be built, and thus I cannot build an exe.

The odd thing is, it doesn't spit out any info on what the error is. Even when I comile with a -Wall switch, I get various warnings (like the build order in constructor declares) but no information on what the error is. Any ideas on this would be helpful, though I still have a few more thoughts on how to get it working properly.
Scott
punt
VIP
Posts: 244
Joined: Wed Mar 24, 2004 7:46 pm
Has thanked: 0
Been thanked: 9 times

Post by punt »

It is causing an internal compilier error. Thus why I was curious if working on linux, 3.4.2. If it is, then one can work on just the windows specific sections that would be compilied.
giwo
Developer
Posts: 1780
Joined: Fri Jun 18, 2004 4:17 pm
Location: California
Has thanked: 0
Been thanked: 0

Post by giwo »

But one would think it would show what exactly was causing the error. Is there a flag I need to use to show that?
Scott
punt
VIP
Posts: 244
Joined: Wed Mar 24, 2004 7:46 pm
Has thanked: 0
Been thanked: 9 times

Post by punt »

giwo wrote:But one would think it would show what exactly was causing the error. Is there a flag I need to use to show that?

No, this means the error is so severe, it is aborting the code. MSVC does this on occasion, if it hits some syntac setup it just never expected. An error in the compilier code, but none the less. So I would first look at any template code that may be in the file. That is a common place for such type of aborts.
giwo
Developer
Posts: 1780
Joined: Fri Jun 18, 2004 4:17 pm
Location: California
Has thanked: 0
Been thanked: 0

Post by giwo »

The major problem here is going to be that I don't think the issue is in a .cpp file. I'm pretty certain it's in a header, especially since it's also happening on ai.cpp (one of our smallest / most simple files).

Anyhow, I will see if i can't track it down...
Scott
punt
VIP
Posts: 244
Joined: Wed Mar 24, 2004 7:46 pm
Has thanked: 0
Been thanked: 9 times

Post by punt »

giwo wrote:The major problem here is going to be that I don't think the issue is in a .cpp file. I'm pretty certain it's in a header, especially since it's also happening on ai.cpp (one of our smallest / most simple files).

Anyhow, I will see if i can't track it down...
If a header, then make a test.cpp that has nothing in it. or some simple routine.

Compile, and ensure the compile completes successfully. Now, start adding the includes for the header files(one at a time) in, until it aborts.

Tedious, but simple it should be.
giwo
Developer
Posts: 1780
Joined: Fri Jun 18, 2004 4:17 pm
Location: California
Has thanked: 0
Been thanked: 0

Post by giwo »

Nod, I had the same idea. Instead, I just found a file that wasn't erroring out (which immediately drew a sigh of relief, since any of them compiling means it's likely not uox3.h or an included header from there).

The problem is actually in regions.h, though I'm not sure why gcc doesn't like it (I can assume, but not sure).

Code: Select all

const SI16 MapColSize = 32;
const SI16 MapRowSize = 128;

const SI16 UpperX = static_cast<SI16>(6144 / MapColSize);
const SI16 UpperY = static_cast<SI16>(4096 / MapRowSize);

class cMapRegion
{
private:
	SI16			upperArrayX[UOMT_COUNT];
	SI16			upperArrayY[UOMT_COUNT];
	SubRegion		internalRegions[UpperX][UpperY][NumberOfWorlds];
The final line is actually the culprit. It aparrantly doesn't like creating a member array based on non-static information (at least this is my guess).

Thus drawing the question... "what now?" I was under the impression people have gotten linux compiling with 0.9x builds, and this has been in since .9x so perhaps something new to the later builds?

Anyhow, I'll continue working on it
Scott
Post Reply