Java-Gaming.org    
Featured games (91)
games approved by the League of Dukes
Games in Showcase (580)
games submitted by our members
Games in WIP (500)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  FileSystem for games  (Read 5482 times)
0 Members and 1 Guest are viewing this topic.
Offline euroboy

Senior Newbie





« Posted 2006-05-27 01:34:37 »

Well... this is my contribution to this forum...
My experience in java is just a week!  Lips Sealed
So... try to don't hit me too much! xD

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
131  
132  
133  
134  
135  
136  
137  
138  
139  
140  
141  
142  
143  
144  
145  
146  
147  
148  
149  
150  
151  
152  
153  
154  
155  
156  
157  
158  
159  
160  
161  
162  
163  
164  
165  
166  
167  
168  
169  
170  
171  
172  
173  
174  
175  
176  
177  
178  
179  
180  
181  
182  
183  
184  
185  
186  
187  
188  
189  
190  
191  
192  
193  
194  
195  
196  
197  
198  
199  
200  
201  
202  
203  
204  
205  
206  
207  
208  
209  
210  
211  
212  
213  
214  
215  
216  
217  
218  
219  
220  
221  
222  
223  
224  
225  
226  
227  
228  
229  
230  
231  
232  
233  
234  
235  
236  
237  
238  
239  
240  
241  
242  
243  
244  
245  
246  
247  
248  
249  
250  
251  
252  
253  
254  
255  
256  
257  
258  
259  
260  
261  
262  
263  
264  
265  
266  
267  
268  
269  
270  
271  
272  
273  
274  
275  
276  
277  
278  
279  
280  
281  
282  
283  
284  
285  
286  
287  
288  
289  
290  
291  
292  
293  
294  
295  
296  
297  
298  
299  
300  
301  
302  
303  
304  
305  
306  
307  
308  
309  
310  
311  
312  
313  
314  
315  
316  
317  
318  
319  
320  
321  
322  
323  
324  
325  
326  
327  
328  
329  
330  
331  
332  
333  
334  
335  
336  
337  
338  
339  
340  
341  
342  
343  
344  
345  
346  
347  
348  
349  
350  
351  
352  
353  
354  
355  
356  
357  
358  
359  
360  
361  
362  
363  
364  
365  
366  
367  
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;
import java.util.*;
import java.util.zip.*;

public class FileSystem
{
    /*
     * Constants
     */

    public static final int     INT     = 0;
    public static final double  DOUBLE  = 1;
    public static final long    LONG    = 2;
    public static final float   FLOAT   = 3;
    public static final short   SHORT   = 4;
    public static final char    CHAR    = 5;
    public static final byte    BYTE    = 6;

    /*
     * Variables
     */

    private static File file = null;
    private static FileInputStream file_input = null;
    private static DataInputStream data_in = null;
    public static file_t filesystem = null;
    public static file_t work_node = null;
    private static int id_counter = 0;

    /*
     * Start
     */

    public static void Start ()
    {
        id_counter = 0;
        filesystem = null;
        filesystem = Node_Create (filesystem, "<null>", null);

        work_node = filesystem;
    }

    /*
     * -------------------------------------------------------------------------
     * Node implementation
     */

    /*
     * Node_Create
     */

    private static file_t Node_Create (file_t a, String name, ByteBuffer buffer)
    {
        a = new file_t ();
        a.filename = name;
        a.backbuffer = buffer;
        a.next = null;
        return a;
    }

    /*
     * Node_Add
     */

    private static file_t Node_Add (file_t a, String name, ByteBuffer buffer)
    {
        if (a.next == null)
        {
            a.next = Node_Create (a.next, name, buffer);
            work_node = a.next;
        }

        return a;
    }

    /*
     * Node_Find
     */

    private static file_t Node_Find (file_t start, String name)
    {
        file_t a = start;
        file_t tmp = null;

        while (a != null)
        {
            if (a.filename.indexOf (name, 0) != -1)
            {
                if (a.backbuffer != null)
                {
                    return a;
                }
            }

            tmp = a.next;
            a = tmp;
        }

        return null;
    }

    /*
     * Node_ReadInt
     */

    private static int Node_ReadInt (file_t fp)
    {
        if (fp.backbuffer == null)
        {
            return -1;
        }

        return fp.backbuffer.getInt ();
    }

    /*
     * Node_ReadDouble
     */

    private static double Node_ReadDouble (file_t fp)
    {
        if (fp.backbuffer == null)
        {
            return -1;
        }

        return fp.backbuffer.getDouble ();
    }

    /*
     * Node_ReadLong
     */

    private static long Node_ReadLong (file_t fp)
    {
        if (fp.backbuffer == null)
        {
            return -1;
        }

        return fp.backbuffer.getLong ();
    }

    /*
     * Node_ReadFloat
     */

    private static float Node_ReadFloat (file_t fp)
    {
        if (fp.backbuffer == null)
        {
            return -1;
        }

        return fp.backbuffer.getFloat ();
    }

    /*
     * Node_ReadShort
     */

    private static short Node_ReadShort (file_t fp)
    {
        if (fp.backbuffer == null)
        {
            return -1;
        }

        return fp.backbuffer.getShort ();
    }

    /*
     * Node_ReadChar
     */

    private static char Node_ReadChar (file_t fp)
    {
        if (fp.backbuffer == null)
        {
            return 0;
        }

        return fp.backbuffer.getChar ();
    }

    /*
     * Node_ReadByte
     */

    private static byte Node_ReadByte (file_t fp)
    {
        if (fp.backbuffer == null)
        {
            return 0;
        }

        return fp.backbuffer.get ();
    }

    /*
     * -------------------------------------------------------------------------
     * Public interface
     */


    /*
     * fadd
     */

    public static boolean fadd (String name)
    {
        File file = null;

        int fileLength = 0;
        FileChannel channel = null;
        FileInputStream input = null;
        ByteBuffer buffer = null;
        boolean ispak = false;

        if (name.indexOf (Global.FS_PAK_EXTENSION, 0) != -1)
        {
            ispak = true;
        }

        try
        {
            if (!ispak)
            {
                file = new File(name);
                if (file.canRead())
                {
                    input = new FileInputStream(file);
                    channel = input.getChannel();
                    fileLength = (int) channel.size();
                    buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0,
                                        fileLength);
                    input.close();

                    buffer.order (ByteOrder.LITTLE_ENDIAN);
                    work_node = Node_Add (work_node, name, buffer);
                    work_node = work_node.next;

                    System.out.println ("loaded >> " + name);
                    return true;
                }
            }
            else
            {
                ZipInputStream zip_in_stream;
                file = new File(name);

                if (file.canRead())
                {
                    FileInputStream in = new FileInputStream (file);
                    BufferedInputStream source = new BufferedInputStream (in);
                    zip_in_stream = new ZipInputStream (source);

                    while (true)
                    {
                        ZipEntry zip_entry = zip_in_stream.getNextEntry ();

                        if (zip_entry == null)
                        {
                            break;
                        }

                        int size = (int)zip_entry.getSize ();
                        byte[] input_buffer = new byte[size];
                        int len = 0;
                        String filename = zip_entry.getName ();

                        len = zip_in_stream.read (input_buffer, 0, size);
                        buffer = ByteBuffer.wrap (input_buffer);

                        buffer.order (ByteOrder.LITTLE_ENDIAN);
                        work_node = Node_Add (work_node, filename, buffer);
                        work_node = work_node.next;

                        System.out.println ("loaded >> " + zip_entry.getName ());
                    }

                    zip_in_stream.close ();
                    return true;
                }
            }
        }
        catch (Exception e)
        {
            System.out.println ("exception >> " + e);
        }


        return false;
    }


    /*
     * fopen
     */

    public static file_t fopen (String name)
    {
        // file_t ret = Node_Search (name, filesystem);
        file_t ret = Node_Find (filesystem, name);

        if (ret != null)
        {
            ret.backbuffer.position (0);
            return ret;
        }

        return null;
    }

    /*
     * fclose
     */

    public static void fclose (file_t fp)
    {
    }

    /*
     * -------------------------------------------------------------------------
     * fread
     */

    /*
     * int
     */

    public static int fread (file_t fp, int a)
    {
        return Node_ReadInt (fp);
    }

    /*
     * double
     */

    public static double fread (file_t fp, double a)
    {
        return Node_ReadDouble (fp);
    }

    /*
     * long
     */

    public static long fread (file_t fp, long a)
    {
        return Node_ReadLong (fp);
    }

    /*
     * float
     */

    public static float fread (file_t fp, float a)
    {
        return Node_ReadFloat (fp);
    }

    /*
     * short
     */

    public static short fread (file_t fp, short a)
    {
        return Node_ReadShort (fp);
    }

    /*
     * char
     */

    public static char fread (file_t fp, char a)
    {
        return Node_ReadChar (fp);
    }

    /*
     * byte
     */

    public static byte fread (file_t fp, byte a)
    {
        return Node_ReadByte (fp);
    }
}


Any comments or something like that will be apreciated. Smiley
Offline Orangy Tang

JGO Kernel


Medals: 51
Projects: 11


Monkey for a head


« Reply #1 - Posted 2006-05-27 02:24:21 »

Trying to code C in Java rarely gives good results...

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Offline oNyx

JGO Coder


Medals: 1


pixels! :x


« Reply #2 - Posted 2006-05-27 03:09:34 »

Uhm... whats the purpose of all that? I mean you can just mount any jars/zip files into the classpath (even during runtime) and simply access those files directly (getResourceAsStream)... or load files from zip files etc.

弾幕 ☆ @mahonnaiseblog
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline noblemaster

JGO Ninja


Medals: 19
Projects: 9


Age of Conquest makes your day!


« Reply #3 - Posted 2006-05-27 03:34:51 »

I don't quite see the purpose either  Huh  How about a simple example on what you can do with it?

Offline euroboy

Senior Newbie





« Reply #4 - Posted 2006-05-27 06:38:02 »

Hey! it's just a code of a week...
The basic idea of this is:

FileSystem.Start ();
FileSystem.fadd ("base/valkyrie.mdl");
FileSystem.fadd ("base/mytextfile.txt");
FileSystem.fadd ("base/test.zip");
FileSystem.fadd ("base/test.tga");

Filesystem creates nodes with a byte buffer in memory with all the above files (in zip or jar files filesystem will add all the files in the zip or jar file).
As you can see.. im a C programmer... xD
I really miss the functions fopen, fread and fclose.

Well... you wanna read 3 bytes of a file?

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
FileSystem.Start ();
FileSystem.fadd ("base/valkyrie.mdl");

file_t a = FileSystem.fopen ("base/valkyrie.mdl");
if (a == null)
{
       return;
}

byte[] a = new byte[3];
byte[0] = FileSystem.fread (a, FileSystem.BYTE);
byte[1] = FileSystem.fread (a, FileSystem.BYTE);
byte[2] = FileSystem.fread (a, FileSystem.BYTE);

FileSystem.fclose (a);


I put FileSystem here to see another alternatives so, if im wrong, please, tell me... im just wanna learn.Smiley
(in fact, just point me at the right direction if this is wrong).
Offline kevglass

JGO Kernel


Medals: 85
Projects: 25


Coder, Trainee Pixel Artist, Game Reviewer


« Reply #5 - Posted 2006-05-27 06:51:00 »

Generally you'd just use the classpath as your filesystem. Stick resources in your jars, or in directories in your classpath. Then to do what you've just done you could do:

1  
2  
3  
4  
5  
6  
7  
8  
9  
try {
    InputStream in = ThisClass.class.getClassLoader().getResourceAsStream("base/valkyrie.mdl");

    byte[] data = new byte[3];
    in.read(data);
    in.close();
} catch (IOException e) {
    e.printStackTrace();
}


where the MDL could be in any of the jars or directories in your class path. This helps later when you start using other distribution mediums - like for instance webstart. Also means you can play around with your classpath, put test resources etc in the way of the real ones to try things out.

Though I think most people here would sensibly wrap the classload bits and pieces up in an lightweight utility.

Kev

Offline oNyx

JGO Coder


Medals: 1


pixels! :x


« Reply #6 - Posted 2006-05-27 07:13:13 »

>Though I think most people here would sensibly wrap the classload bits and pieces up in an lightweight utility.

Ye... for me its just InputStream=getInputStream("foo/bar.ext"); or DataInputStream=getDataInputStream("foo/bar.ext");

I also dont need an extra try/catch there. If an exception occurs the module gets stopped and I get some stacktrace in the (quake alike) console. It doesnt really get any simpler than that Wink

弾幕 ☆ @mahonnaiseblog
Offline kevglass

JGO Kernel


Medals: 85
Projects: 25


Coder, Trainee Pixel Artist, Game Reviewer


« Reply #7 - Posted 2006-05-27 07:24:29 »

Me also, I consider a runtime error if something can't be loaded at game time. Hence thats a "stop and complain" rather than an possible exception case.

Kev

Offline Orangy Tang

JGO Kernel


Medals: 51
Projects: 11


Monkey for a head


« Reply #8 - Posted 2006-05-27 14:06:51 »

As you can see.. im a C programmer... xD

If you want to write C code thats fine, but don't try and write C code in Java.
- Use the classpath
- Loose the statics
- Don't bring your awkward C naming conventions (file_t, Node_Create, a, tmp) with you.
- Don't convert exceptions into return codes.
- Your use of dummy parameters to overloaded functions is hideous
- You appear to have a whole bunch of unused variables
- Read this, this and this.

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Offline kevglass

JGO Kernel


Medals: 85
Projects: 25


Coder, Trainee Pixel Artist, Game Reviewer


« Reply #9 - Posted 2006-05-27 19:11:04 »

Hey come on OT, go easy, at least this wasn't spam Smiley

Kev

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Orangy Tang

JGO Kernel


Medals: 51
Projects: 11


Monkey for a head


« Reply #10 - Posted 2006-05-27 20:51:24 »

Actually on re-reading that it sounds a little harsher than I intended. Lips Sealed

The first link is still very recommended though, it's a pretty good read.

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Offline euroboy

Senior Newbie





« Reply #11 - Posted 2006-05-27 21:19:09 »

Well thanks...

As you can see.. im a C programmer... xD

...
- Don't bring your awkward C naming conventions (file_t, Node_Create, a, tmp) with you.
- Don't convert exceptions into return codes.
- Your use of dummy parameters to overloaded functions is hideous
- You appear to have a whole bunch of unused variables
...

Can you explain this points?
Offline Ask_Hjorth_Larsen

Junior Member




Java games rock!


« Reply #12 - Posted 2006-05-28 01:34:42 »

Generally it's a bit overambitious to get into file I/O first thing. You should make some more useless programs and learn object oriented stuff before you can appreciate the design of the Java I/O classes.

About the naming conventions, in java you don't use names like do_something, you use doSomething. I'm sure the relevant document was linked above.
Offline Orangy Tang

JGO Kernel


Medals: 51
Projects: 11


Monkey for a head


« Reply #13 - Posted 2006-05-28 11:58:34 »

Well thanks...

As you can see.. im a C programmer... xD

...
- Don't bring your awkward C naming conventions (file_t, Node_Create, a, tmp) with you.
- Don't convert exceptions into return codes.
- Your use of dummy parameters to overloaded functions is hideous
- You appear to have a whole bunch of unused variables
...

Can you explain this points?

Sure. For the first one see the link I posted for naming conventions. The main ones to get are that classes start with a capital, method names start with lower case and underscores aren't used.

2. fadd() catches an exception and converts it into a bool return code. It would be better to simply throw the exception, or catch it and re-throw it as a runtime exception.

3. The syntax of FileSystem.fread(foo, BYTE) is just plain weird. You're introducing a dummy variable that doesn't get used just and forcing the caller to do odd things. Why not just try FileSystem.readByte(foo) / readInt(foo) / etc.

4. file_input, data_in and id_counter all seem to be unused.

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Offline CommanderKeith
« Reply #14 - Posted 2006-05-29 05:37:07 »

Hi Kev,
I was just reading your excellent webstart tutorial http://www.cokeandcode.com/webstarthowto where you recommend resources be accessed the following way:

Thread.currentThread().getContextClassLoader().getClassLoader().getResource("sprites/mySprite.png");

In the above posts you prescribed this:

ThisClass.class.getClassLoader().getResource("base/valkyrie.mdl");

Is the latter equivalent to the first and will both work with JWS's special class loader you mentioned in the tutorial?

Thanks

Offline kevglass

JGO Kernel


Medals: 85
Projects: 25


Coder, Trainee Pixel Artist, Game Reviewer


« Reply #15 - Posted 2006-05-29 17:38:10 »

Tremendous question. I'm afraid I was being sloppy. The ThisClass.class version is the way we worked out for ourselfs when webstart first started becoming useful for games. However, there was a post that I've been unable to find from one of the guys at Sun that recommended the Thread.getContextClassLoader() method.

I think the correct thing to use the getContextClassLoader() version since you may find the class that use to find the ClassLoader may have been loaded in some special way - where as the getContextClassLoader() will return you the class loader that would be used to load classes at the current point in process execution.

I've use both ways lots and lots and never had a problem with either. However this is one of the reasons I wrap my resource access up in little static class - if someone eventually decides that one way is better than the other - or a third version comes up thats now the "right thing (tm)" - then its easy to change Smiley

For reference my ResourceLoader wrapper is available as part of my FECK code here:

http://www.cokeandcode.com/code/src/util/org/newdawn/util/ResourceLoader.java

This isn't for review - just for reference Smiley I know lots of people won't like the System.exit(0) in there - but it works beautifully for my usage Smiley

Kev

Offline CommanderKeith
« Reply #16 - Posted 2006-05-31 10:17:53 »

Thanks  Smiley

That code's handy.

getContextClassLoader() is annoying to use because its so verbose but also I'm having to give it absolute names for the resource since I can't tell where its relative position is like  SomeClass.class.getClassLoader(). 

I'm going to use it in the following way to get around this:

Thread.currentThread().getContextClassLoader().getResource("mypackage.resources."+resourceName);

Offline kevglass

JGO Kernel


Medals: 85
Projects: 25


Coder, Trainee Pixel Artist, Game Reviewer


« Reply #17 - Posted 2006-05-31 18:14:36 »

Some people also add a file system fallback to the whole thing for testing purposes. Personally I just sort the classpath out earlier but I thought it was worth noting.

Kev

Offline blahblahblahh

JGO Coder


Medals: 1


http://t-machine.org


« Reply #18 - Posted 2006-06-02 14:48:47 »

For reference my ResourceLoader wrapper is available as part of my FECK code here:
This isn't for review - just for reference Smiley I know lots of people won't like the System.exit(0) in there - but it works beautifully for my usage Smiley

I've got an improved one I keep meaning to post Smiley. So ...

Code: http://javagamesfactory.org/sourceformatter/sourcecode/8/ResourceLoader.java

Instructions: http://javagamesfactory.org/views/view-sourcesnippet?id=8

malloc will be first against the wall when the revolution comes...
Offline kevglass

JGO Kernel


Medals: 85
Projects: 25


Coder, Trainee Pixel Artist, Game Reviewer


« Reply #19 - Posted 2006-06-02 18:21:47 »

Crikey, I can just about remember that Smiley

Kev

Offline beowulf03809

Junior Member




We live for the code, we die for the code


« Reply #20 - Posted 2006-06-23 21:47:07 »


Although I won't comment on the expressivness of OT (  Wink ) I will second and third the recommendation for Thinking in Java.  A fantastic read.  i bought the physical copy and also keep an electronic ( free as in beer  Cool ) copy on my computer and in my PDA. 
Offline fletchergames

Senior Member





« Reply #21 - Posted 2006-06-26 04:10:32 »

Generally it's a bit overambitious to get into file I/O first thing. You should make some more useless programs and learn object oriented stuff before you can appreciate the design of the Java I/O classes.

About the naming conventions, in java you don't use names like do_something, you use doSomething. I'm sure the relevant document was linked above.
What's special about file I/O?

I can see telling someone not to start out with writing their own web server, but writing a program that reads some files is the sort of thing I would want people to start out doing as soon as they'd learned the syntax of the language.

And since he knows C anyways, he might as well do whatever he wants.  He hasn't figured out all the advantages of using Java yet, but that's to be expected when he's only been using Java for a week.

What Euroboy should do is read some stuff like the links Orangy Tang posted.  I don't think file I/O is the problem.  It's just "newness" to Java.
Offline Ask_Hjorth_Larsen

Junior Member




Java games rock!


« Reply #22 - Posted 2006-06-28 02:31:31 »

Quote
What's special about file I/O?

I can see telling someone not to start out with writing their own web server, but writing a program that reads some files is the sort of thing I would want people to start out doing as soon as they'd learned the syntax of the language.

And since he knows C anyways, he might as well do whatever he wants.  He hasn't figured out all the advantages of using Java yet, but that's to be expected when he's only been using Java for a week.

What Euroboy should do is read some stuff like the links Orangy Tang posted.  I don't think file I/O is the problem.  It's just "newness" to Java.

There's nothing special about I/O, it's just that the program above is a non-object oriented wrapper for an object-oriented API. Its primary application is to convert object orientedness to non-object orientedness. This is a logical thing to do when you're a C programmer, yes, but doing more tutorial-like stuff will show that it isn't the way to go in Java.
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

xsi3rr4x (48 views)
2014-04-15 18:08:23

BurntPizza (44 views)
2014-04-15 03:46:01

UprightPath (60 views)
2014-04-14 17:39:50

UprightPath (42 views)
2014-04-14 17:35:47

Porlus (58 views)
2014-04-14 15:48:38

tom_mai78101 (81 views)
2014-04-10 04:04:31

BurntPizza (140 views)
2014-04-08 23:06:04

tom_mai78101 (240 views)
2014-04-05 13:34:39

trollwarrior1 (200 views)
2014-04-04 12:06:45

CJLetsGame (207 views)
2014-04-01 02:16:10
List of Learning Resources
by SHC
2014-04-18 03:17:39

List of Learning Resources
by Longarmx
2014-04-08 03:14:44

Good Examples
by matheus23
2014-04-05 13:51:37

Good Examples
by Grunnt
2014-04-03 15:48:46

Good Examples
by Grunnt
2014-04-03 15:48:37

Good Examples
by matheus23
2014-04-01 18:40:51

Good Examples
by matheus23
2014-04-01 18:40:34

Anonymous/Local/Inner class gotchas
by Roquen
2014-03-11 15:22:30
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!