[jetrix-cvs] SF.net SVN: jetrix:[851] jetrix/trunk
Brought to you by:
smanux
|
From: <sm...@us...> - 2010-05-04 12:47:31
|
Revision: 851
http://jetrix.svn.sourceforge.net/jetrix/?rev=851&view=rev
Author: smanux
Date: 2010-05-04 12:47:25 +0000 (Tue, 04 May 2010)
Log Message:
-----------
Automatic generation of the commands documentation
Modified Paths:
--------------
jetrix/trunk/build.xml
jetrix/trunk/doc/todo.txt
jetrix/trunk/src/site/style.css
jetrix/trunk/src/site/user-guide.php
Added Paths:
-----------
jetrix/trunk/src/java/net/jetrix/tools/DocumentationGenerator.java
jetrix/trunk/src/site/commands.html
Modified: jetrix/trunk/build.xml
===================================================================
--- jetrix/trunk/build.xml 2010-05-04 10:10:28 UTC (rev 850)
+++ jetrix/trunk/build.xml 2010-05-04 12:47:25 UTC (rev 851)
@@ -337,8 +337,19 @@
<fileset dir="${deploy}/jetrix-${version}"/>
</ftp>
</target>
-
- <target name="site" description="Generate and publish the web site to SourceForge">
+
+ <target name="docgen" depends="compile" description="Generates the documentation of the server commands">
+ <java classname="net.jetrix.tools.DocumentationGenerator" fork="true">
+ <classpath>
+ <pathelement path="${build}/classes"/>
+ <pathelement path="${src}/etc"/>
+ <pathelement path="${src}/lang"/>
+ <fileset dir="lib" includes="*.jar"/>
+ </classpath>
+ </java>
+ </target>
+
+ <target name="site" depends="docgen" description="Generate and publish the web site to SourceForge">
<!-- Create the site distribution directory -->
<mkdir dir="${dist}/site/docs"/>
Modified: jetrix/trunk/doc/todo.txt
===================================================================
--- jetrix/trunk/doc/todo.txt 2010-05-04 10:10:28 UTC (rev 850)
+++ jetrix/trunk/doc/todo.txt 2010-05-04 12:47:25 UTC (rev 851)
@@ -19,6 +19,7 @@
- bonus points when the same player wins several games in a row
- immunity mode: a tetris grants a 10 seconds immunity against any special (detrimental and beneficial)
- check the end of the game when a player leaves the channel
+- handicap filter: increase the difficulty for the winner (increased starting height)
Commands
- /mute <nick>
@@ -41,12 +42,14 @@
- run as a service on Windows (using Java Service Wrapper)
- run as a service on Linux (init.d script)
- deploy as a web application
+- UPnP support (with http://www.cybergarage.org and http://jupnp.dev.java.net, or UPNPLib from http://www.sbbi.net)
Website
- feature matrix similar to http://damagecontrol.codehaus.org/Continuous+Integration+Server+Feature+Matrix
-- automatic generation of the commands documentation
- java web start demo
- compress the files on the patch server
Code
- split the code in two parts : the core tetrinet classes and the server specific classes
+- reusable project to develop an independent command/filter
+- publish Maven artifacts to SonaType (http://nexus.sonatype.org/oss-repository-hosting.html)
Added: jetrix/trunk/src/java/net/jetrix/tools/DocumentationGenerator.java
===================================================================
--- jetrix/trunk/src/java/net/jetrix/tools/DocumentationGenerator.java (rev 0)
+++ jetrix/trunk/src/java/net/jetrix/tools/DocumentationGenerator.java 2010-05-04 12:47:25 UTC (rev 851)
@@ -0,0 +1,165 @@
+/**
+ * Jetrix TetriNET Server
+ * Copyright (C) 20010 Emmanuel Bourg
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package net.jetrix.tools;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.TreeMap;
+
+import net.jetrix.AccessLevel;
+import net.jetrix.commands.Command;
+import net.jetrix.commands.CommandManager;
+import net.jetrix.config.ChannelConfig;
+import net.jetrix.config.FilterConfig;
+import net.jetrix.config.ServerConfig;
+
+/**
+ * Generates the documentation for the server commands.
+ *
+ * @author Emmanuel Bourg
+ * @version $Revision$, $Date$
+ */
+public class DocumentationGenerator
+{
+ public static void main(String[] args) throws Exception
+ {
+ File configFile = new File("src/etc/conf/server.xml");
+ ServerConfig config = new ServerConfig();
+ config.load(configFile);
+
+ File file = new File("src/site/commands.html");
+ file.getParentFile().mkdirs();
+
+ System.out.println("Exporting commands documentation from " + configFile + " to " + file);
+ System.out.println("");
+
+ // collect the general commands
+ TreeMap<String, Command> commands = new TreeMap<String, Command>();
+ Iterator<Command> it = CommandManager.getInstance().getCommands(AccessLevel.ADMINISTRATOR);
+ while (it.hasNext())
+ {
+ Command command = it.next();
+ commands.put(command.getAliases()[0], command);
+ }
+
+ // collect the filter commands
+ for (ChannelConfig channel : config.getChannels())
+ {
+ Iterator<FilterConfig> filters = channel.getFilters();
+ while (filters.hasNext())
+ {
+ FilterConfig filter = filters.next();
+ if (!filter.isGlobal() && filter.getName().equals("command"))
+ {
+ String cls = filter.getProperties().getProperty("class");
+ Command command = (Command) Class.forName(cls).newInstance();
+ commands.put(command.getAliases()[0], command);
+ }
+ }
+ }
+
+ PrintWriter out = new PrintWriter(new FileWriter(file));
+
+ for (Command command : commands.values())
+ {
+ String alias = command.getAliases()[0];
+
+ out.println("<h2 id=\"command-" + alias + "\">" + alias + "</h2>");
+ out.println();
+ out.println("<p>" + command.getDescription(Locale.ENGLISH) + "</p>");
+ out.println();
+ out.println("<div><b>Usage:</b> <tt>" + htmlizeUsage(command.getUsage(Locale.ENGLISH)) + "</tt></div>");
+ if (command.getAliases().length > 1)
+ {
+ out.println("<div><b>Aliases:</b> <tt>" + Arrays.toString(command.getAliases()) + "</tt></div>");
+ }
+ String role = getRoleName(command.getAccessLevel());
+ if (role != null)
+ {
+ out.println("<div><b>Access Level:</b> " + role + "</div>");
+ }
+ out.println();
+ out.println();
+
+ System.out.println(command.getUsage(Locale.ENGLISH));
+ }
+
+
+ out.flush();
+ out.close();
+ }
+
+ private static String getRoleName(int level)
+ {
+ if (level == 0)
+ {
+ return "Player";
+ }
+ else if (level == 1)
+ {
+ return "Channel Operator";
+ }
+ else if (level == 2)
+ {
+ return "Operator";
+ }
+ else if (level == 100)
+ {
+ return "Administrator";
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Return a colorized usage string of the specified command.
+ */
+ private static String htmlizeUsage(String usage)
+ {
+ StringBuffer htmlized = new StringBuffer();
+ htmlized.append("<span style=\"color: red\">");
+
+ for (char c : usage.toCharArray())
+ {
+ if (c == '<')
+ {
+ htmlized.append("<span style=\"color: blue\"><");
+ }
+ else if (c == '>')
+ {
+ htmlized.append("></span>");
+ }
+ else
+ {
+ htmlized.append(c);
+ }
+ }
+
+ htmlized.append("</span>");
+
+ return htmlized.toString();
+ }
+}
Property changes on: jetrix/trunk/src/java/net/jetrix/tools/DocumentationGenerator.java
___________________________________________________________________
Added: svn:keywords
+ Date Author Id Revision HeadURL
Added: svn:eol-style
+ native
Added: jetrix/trunk/src/site/commands.html
===================================================================
--- jetrix/trunk/src/site/commands.html (rev 0)
+++ jetrix/trunk/src/site/commands.html 2010-05-04 12:47:25 UTC (rev 851)
@@ -0,0 +1,268 @@
+<h2 id="command-away">away</h2>
+
+<p>Set your away status.</p>
+
+<div><b>Usage:</b> <tt><span style="color: red">/afk <span style="color: blue"><message></span></span></tt></div>
+<div><b>Aliases:</b> <tt>[away, afk]</tt></div>
+<div><b>Access Level:</b> Player</div>
+
+
+<h2 id="command-broadcast">broadcast</h2>
+
+<p>Send a message to all clients on the server.</p>
+
+<div><b>Usage:</b> <tt><span style="color: red">/br <span style="color: blue"><message></span></span></tt></div>
+<div><b>Aliases:</b> <tt>[broadcast, br, gmsg, shout]</tt></div>
+<div><b>Access Level:</b> Operator</div>
+
+
+<h2 id="command-config">config</h2>
+
+<p>Display the channel settings.</p>
+
+<div><b>Usage:</b> <tt><span style="color: red">/config</span></tt></div>
+<div><b>Aliases:</b> <tt>[config, conf, settings]</tt></div>
+<div><b>Access Level:</b> Player</div>
+
+
+<h2 id="command-emote">emote</h2>
+
+<p>Display an emote.</p>
+
+<div><b>Usage:</b> <tt><span style="color: red">/me</span></tt></div>
+<div><b>Aliases:</b> <tt>[emote, me]</tt></div>
+<div><b>Access Level:</b> Player</div>
+
+
+<h2 id="command-goto">goto</h2>
+
+<p>Go to the channel of the specified player.</p>
+
+<div><b>Usage:</b> <tt><span style="color: red">/goto <span style="color: blue"><player name></span></span></tt></div>
+<div><b>Aliases:</b> <tt>[goto, go]</tt></div>
+<div><b>Access Level:</b> Player</div>
+
+
+<h2 id="command-help">help</h2>
+
+<p>List all commands available.</p>
+
+<div><b>Usage:</b> <tt><span style="color: red">/help</span></tt></div>
+<div><b>Aliases:</b> <tt>[help, ?, h]</tt></div>
+<div><b>Access Level:</b> Player</div>
+
+
+<h2 id="command-ignore">ignore</h2>
+
+<p>Add or remove a player from the ignore list.</p>
+
+<div><b>Usage:</b> <tt><span style="color: red">/ignore <span style="color: blue"><player name|number></span></span></tt></div>
+<div><b>Access Level:</b> Player</div>
+
+
+<h2 id="command-ip">ip</h2>
+
+<p>Display the IP of a player.</p>
+
+<div><b>Usage:</b> <tt><span style="color: red">/ip <span style="color: blue"><player name|number></span></span></tt></div>
+<div><b>Access Level:</b> Operator</div>
+
+
+<h2 id="command-join">join</h2>
+
+<p>Join or create a channel.</p>
+
+<div><b>Usage:</b> <tt><span style="color: red">/join <span style="color: blue"><channel name|number></span> <span style="color: blue"><password></span></span></tt></div>
+<div><b>Aliases:</b> <tt>[join, j]</tt></div>
+<div><b>Access Level:</b> Player</div>
+
+
+<h2 id="command-kick">kick</h2>
+
+<p>Kick a player out of the server.</p>
+
+<div><b>Usage:</b> <tt><span style="color: red">/kick <span style="color: blue"><player name|number></span></span></tt></div>
+<div><b>Aliases:</b> <tt>[kick, disconnect]</tt></div>
+<div><b>Access Level:</b> Operator</div>
+
+
+<h2 id="command-language">language</h2>
+
+<p>Set the language of the user.</p>
+
+<div><b>Usage:</b> <tt><span style="color: red">/language <span style="color: blue"><language code></span></span></tt></div>
+<div><b>Aliases:</b> <tt>[language, lang]</tt></div>
+<div><b>Access Level:</b> Player</div>
+
+
+<h2 id="command-list">list</h2>
+
+<p>List available channels.</p>
+
+<div><b>Usage:</b> <tt><span style="color: red">/list</span></tt></div>
+<div><b>Aliases:</b> <tt>[list, l]</tt></div>
+<div><b>Access Level:</b> Player</div>
+
+
+<h2 id="command-mode">mode</h2>
+
+<p>Change the channel's configuration.</p>
+
+<div><b>Usage:</b> <tt><span style="color: red">/mode <span style="color: blue"><0-9></span></span></tt></div>
+<div><b>Access Level:</b> Player</div>
+
+
+<h2 id="command-motd">motd</h2>
+
+<p>Display the message of the day.</p>
+
+<div><b>Usage:</b> <tt><span style="color: red">/motd</span></tt></div>
+<div><b>Access Level:</b> Player</div>
+
+
+<h2 id="command-move">move</h2>
+
+<p>Move a player to a new slot.</p>
+
+<div><b>Usage:</b> <tt><span style="color: red">/move <span style="color: blue"><player number></span> <span style="color: blue"><slot number></span></span></tt></div>
+<div><b>Access Level:</b> Player</div>
+
+
+<h2 id="command-operator">operator</h2>
+
+<p>Gain authenticated operator status.</p>
+
+<div><b>Usage:</b> <tt><span style="color: red">/op <span style="color: blue"><password></span></span></tt></div>
+<div><b>Aliases:</b> <tt>[operator, op]</tt></div>
+<div><b>Access Level:</b> Player</div>
+
+
+<h2 id="command-pause">pause</h2>
+
+<p>Pause or unpause the game.</p>
+
+<div><b>Usage:</b> <tt><span style="color: red">/pause</span></tt></div>
+<div><b>Access Level:</b> Operator</div>
+
+
+<h2 id="command-petition">petition</h2>
+
+<p>Send a request for assistance to all operators online.</p>
+
+<div><b>Usage:</b> <tt><span style="color: red">/petition <span style="color: blue"><message></span></span></tt></div>
+<div><b>Aliases:</b> <tt>[petition, omsg]</tt></div>
+<div><b>Access Level:</b> Player</div>
+
+
+<h2 id="command-ping">ping</h2>
+
+<p>Display the ping to the server.</p>
+
+<div><b>Usage:</b> <tt><span style="color: red">/ping</span></tt></div>
+<div><b>Access Level:</b> Player</div>
+
+
+<h2 id="command-random">random</h2>
+
+<p>Display a random number.</p>
+
+<div><b>Usage:</b> <tt><span style="color: red">/random <span style="color: blue"><min></span> <span style="color: blue"><max></span></span></tt></div>
+<div><b>Aliases:</b> <tt>[random, roll]</tt></div>
+<div><b>Access Level:</b> Player</div>
+
+
+<h2 id="command-reply">reply</h2>
+
+<p>Reply to the previous private message.</p>
+
+<div><b>Usage:</b> <tt><span style="color: red">/reply <span style="color: blue"><message></span></span></tt></div>
+<div><b>Aliases:</b> <tt>[reply, r]</tt></div>
+<div><b>Access Level:</b> Player</div>
+
+
+<h2 id="command-speclist">speclist</h2>
+
+<p>Show the spectators in the channel</p>
+
+<div><b>Usage:</b> <tt><span style="color: red">/speclist</span></tt></div>
+<div><b>Aliases:</b> <tt>[speclist, slist]</tt></div>
+<div><b>Access Level:</b> Player</div>
+
+
+<h2 id="command-start">start</h2>
+
+<p>Start the game.</p>
+
+<div><b>Usage:</b> <tt><span style="color: red">/start <span style="color: blue"><seconds></span></span></tt></div>
+<div><b>Access Level:</b> Player</div>
+
+
+<h2 id="command-stop">stop</h2>
+
+<p>Stop the game.</p>
+
+<div><b>Usage:</b> <tt><span style="color: red">/stop</span></tt></div>
+<div><b>Access Level:</b> Operator</div>
+
+
+<h2 id="command-summon">summon</h2>
+
+<p>Summon a player to the current channel.</p>
+
+<div><b>Usage:</b> <tt><span style="color: red">/summon <span style="color: blue"><player name></span></span></tt></div>
+<div><b>Access Level:</b> Operator</div>
+
+
+<h2 id="command-teleport">teleport</h2>
+
+<p>Teleport a player to another channel.</p>
+
+<div><b>Usage:</b> <tt><span style="color: red">/teleport <span style="color: blue"><player name|number></span> <span style="color: blue"><channel name|number></span></span></tt></div>
+<div><b>Aliases:</b> <tt>[teleport, tp]</tt></div>
+<div><b>Access Level:</b> Operator</div>
+
+
+<h2 id="command-tell">tell</h2>
+
+<p>Send a private message to a player.</p>
+
+<div><b>Usage:</b> <tt><span style="color: red">/tell <span style="color: blue"><player name|number></span> <span style="color: blue"><message></span></span></tt></div>
+<div><b>Aliases:</b> <tt>[tell, msg, cmsg, send]</tt></div>
+<div><b>Access Level:</b> Player</div>
+
+
+<h2 id="command-time">time</h2>
+
+<p>Display the server's time.</p>
+
+<div><b>Usage:</b> <tt><span style="color: red">/time</span></tt></div>
+<div><b>Aliases:</b> <tt>[time, date]</tt></div>
+<div><b>Access Level:</b> Player</div>
+
+
+<h2 id="command-tmsg">tmsg</h2>
+
+<p>Send a message to the team.</p>
+
+<div><b>Usage:</b> <tt><span style="color: red">/tmsg <span style="color: blue"><message></span></span></tt></div>
+<div><b>Aliases:</b> <tt>[tmsg, gu]</tt></div>
+<div><b>Access Level:</b> Player</div>
+
+
+<h2 id="command-version">version</h2>
+
+<p>Display the version of the server.</p>
+
+<div><b>Usage:</b> <tt><span style="color: red">/version</span></tt></div>
+<div><b>Access Level:</b> Player</div>
+
+
+<h2 id="command-who">who</h2>
+
+<p>List all players connected to the server.</p>
+
+<div><b>Usage:</b> <tt><span style="color: red">/who</span></tt></div>
+<div><b>Aliases:</b> <tt>[who, w, cwho]</tt></div>
+<div><b>Access Level:</b> Player</div>
+
+
Property changes on: jetrix/trunk/src/site/commands.html
___________________________________________________________________
Added: svn:keywords
+ Date Author Id Revision HeadURL
Added: svn:eol-style
+ native
Modified: jetrix/trunk/src/site/style.css
===================================================================
--- jetrix/trunk/src/site/style.css 2010-05-04 10:10:28 UTC (rev 850)
+++ jetrix/trunk/src/site/style.css 2010-05-04 12:47:25 UTC (rev 851)
@@ -1,4 +1,4 @@
-body { color: black; background-color: white; margin: 0; font-family: Arial, Helvetica, Sans Serif }
+body { color: black; background-color: white; margin: 0 1em; font-family: Arial, Helvetica, Sans Serif; }
a { color: #525d76 }
a:hover { color: #2B313D }
Modified: jetrix/trunk/src/site/user-guide.php
===================================================================
--- jetrix/trunk/src/site/user-guide.php 2010-05-04 10:10:28 UTC (rev 850)
+++ jetrix/trunk/src/site/user-guide.php 2010-05-04 12:47:25 UTC (rev 851)
@@ -17,41 +17,7 @@
</ul>
</li>
<li><a href="#section3">Web Administration</a></li>
- <li><a href="#section4">Command Reference</a>
- <ul>
- <li><a href="#section4-away">Away</a></li>
- <li><a href="#section4-broadcast">Broadcast</a></li>
- <li><a href="#section4-config">Config</a></li>
- <li><a href="#section4-emote">Emote</a></li>
- <li><a href="#section4-goto">Goto</a></li>
- <li><a href="#section4-help">Help</a></li>
- <li><a href="#section4-ignore">Ignore</a></li>
- <li><a href="#section4-ip">Ip</a></li>
- <li><a href="#section4-join">Join</a></li>
- <li><a href="#section4-kick">Kick</a></li>
- <li><a href="#section4-language">Language</a></li>
- <li><a href="#section4-list">List</a></li>
- <li><a href="#section4-mode">Mode</a></li>
- <li><a href="#section4-motd">Motd</a></li>
- <li><a href="#section4-move">Move</a></li>
- <li><a href="#section4-operator">Operator</a></li>
- <li><a href="#section4-pause">Pause</a></li>
- <li><a href="#section4-petition">Petition</a></li>
- <li><a href="#section4-ping">Ping</a></li>
- <li><a href="#section4-random">Random</a></li>
- <li><a href="#section4-reply">Reply</a></li>
- <li><a href="#section4-speclist">Speclist</a></li>
- <li><a href="#section4-start">Start</a></li>
- <li><a href="#section4-stop">Stop</a></li>
- <li><a href="#section4-summon">Summon</a></li>
- <li><a href="#section4-teleport">Teleport</a></li>
- <li><a href="#section4-tell">Tell</a></li>
- <li><a href="#section4-time">Time</a></li>
- <li><a href="#section4-tmsg">Tmsg</a></li>
- <li><a href="#section4-version">Version</a></li>
- <li><a href="#section4-who">Who</a></li>
- </ul>
- </li>
+ <li><a href="#section4">Command Reference</a></li>
</ol>
<h1><a id="section1"></a>Installation</h1>
@@ -60,7 +26,7 @@
<ul>
<li>Linux, Windows, Solaris or MacOS X</li>
- <li>Java Runtime Environnement 1.5.x or higher</li>
+ <li>Java 6 or higher</li>
<li>32 Mb RAM</li>
<li>5 Mb hard drive space</li>
<li>If you have a firewall, open the ports 31456, 31457 and 31458</li>
@@ -68,10 +34,9 @@
<h3>Running & Upgrading</h3>
-<p>You need a JRE 1.5 or higher installed on your server to run Jetrix. You can
-download it here :</p>
+<p>You need Java 6 or higher installed on your server to run Jetrix. You can
+download it on <a href="http://java.com">http://java.com</a></p>
-<a href="http://java.sun.com/j2se/1.5.0/download.jsp">http://java.sun.com/j2se/1.5.0/download.jsp</a>
<h4>Unix</h4>
@@ -79,7 +44,7 @@
environnement variable pointing to your Java directory. For example on
Linux you can add this line to your /etc/profile file:</p>
-<code>export JAVA_HOME=/usr/java/jre_1.5.0</code>
+<code>export JAVA_HOME=/usr/java/jre_1.6.0</code>
<p>Then decompress the Jetrix archive to the installation directory:</p>
@@ -154,55 +119,6 @@
<h1><a id="section4"></a>Command Reference</h1>
-<h2><a id="section4-broadcast"></a>Broadcast</h2>
+<? include("commands.html") ?>
-<h2><a id="section4-config"></a>Config</h2>
-
-<h2><a id="section4-emote"></a>Emote</h2>
-
-<h2><a id="section4-goto"></a>Goto</h2>
-
-<h2><a id="section4-help"></a>Help</h2>
-
-<h2><a id="section4-ip"></a>Ip</h2>
-
-<h2><a id="section4-join"></a>Join</h2>
-
-<h2><a id="section4-kick"></a>Kick</h2>
-
-<h2><a id="section4-language"></a>Language</h2>
-
-<h2><a id="section4-list"></a>List</h2>
-
-<h2><a id="section4-motd"></a>Motd</h2>
-
-<h2><a id="section4-move"></a>Move</h2>
-
-<h2><a id="section4-operator"></a>Operator</h2>
-
-<h2><a id="section4-pause"></a>Pause</h2>
-
-<h2><a id="section4-ping"></a>Ping</h2>
-
-<h2><a id="section4-random"></a>Random</h2>
-
-<h2><a id="section4-reply"></a>Reply</h2>
-
-<h2><a id="section4-start"></a>Start</h2>
-
-<h2><a id="section4-stop"></a>Stop</h2>
-
-<h2><a id="section4-summon"></a>Summon</h2>
-
-<h2><a id="section4-teleport"></a>Teleport</h2>
-
-<h2><a id="section4-tell"></a>Tell</h2>
-
-<h2><a id="section4-time"></a>Time</h2>
-
-<h2><a id="section4-version"></a>Version</h2>
-
-<h2><a id="section4-who"></a>Who</h2>
-
-
<? include("footer.inc.php") ?>
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|