Author: dylan
Date: 2005-04-24 20:49:04 -0400 (Sun, 24 Apr 2005)
New Revision: 671

Added:
   trunk/clients/javer/
   trunk/clients/javer/TODO
   trunk/clients/javer/build.xml
   trunk/clients/javer/manifest.mf
   trunk/clients/javer/nbproject/
   trunk/clients/javer/nbproject/build-impl.xml
   trunk/clients/javer/nbproject/genfiles.properties
   trunk/clients/javer/nbproject/project.properties
   trunk/clients/javer/nbproject/project.xml
   trunk/clients/javer/src/
   trunk/clients/javer/src/javer/
   trunk/clients/javer/src/javer/CMod.java
   trunk/clients/javer/src/javer/ChannelTab.form
   trunk/clients/javer/src/javer/ChannelTab.java
   trunk/clients/javer/src/javer/GameMod.java
   trunk/clients/javer/src/javer/HaverClient.java
   trunk/clients/javer/src/javer/JaverApplet.java
   trunk/clients/javer/src/javer/JaverUI.form
   trunk/clients/javer/src/javer/JaverUI.java
   trunk/clients/javer/src/javer/JaverUIPanel.form
   trunk/clients/javer/src/javer/JaverUIPanel.java
   trunk/clients/javer/src/javer/NonblockingOutputStream.java
   trunk/clients/javer/src/javer/QueryTab.java
   trunk/clients/javer/src/javer/SimpleTextTab.form
   trunk/clients/javer/src/javer/SimpleTextTab.java
   trunk/clients/javer/src/javer/TextFormatter.java
   trunk/clients/javer/src/javer/TextTab.java
   trunk/clients/javer/src/javer/ThreadRendezvous.java
   trunk/clients/javer/src/javer/TimedInvoker.java
   trunk/clients/javer/src/javer/TimerThread.java
   trunk/clients/javer/src/javer/UserQueryTab.java
   trunk/clients/javer/test/
Removed:
   trunk/main/server/lib/Haver/Server/Plugin/
   trunk/misc/guile/
   trunk/misc/javer/
Modified:
   trunk/
   trunk/main/server/lib/Haver/Server/Base.pm
   trunk/main/server/lib/Haver/Server/Listener.pm
Log:
 [EMAIL PROTECTED]:  dylan | 2005-04-24 18:28:52 -0400
 Moved javer from misc/ to clients/



Property changes on: trunk
___________________________________________________________________
Name: svk:merge
   - 1f59643a-e6e5-0310-bc24-f7d4c744f460:/haver/local/trunk:11166
1f59643a-e6e5-0310-bc24-f7d4c744f460:/haver/local/trunk-merge-10131:11178
27e50396-46e3-0310-8b22-ae223a1f35ce:/local:212
e9404bb1-7af0-0310-a7ff-e22194cd388b:/haver/local:920
edfcd8bd-4ce7-0310-a97e-bb1efd40edf3:/local:238
   + 1f59643a-e6e5-0310-bc24-f7d4c744f460:/haver/local/trunk:11166
1f59643a-e6e5-0310-bc24-f7d4c744f460:/haver/local/trunk-merge-10131:11178
27e50396-46e3-0310-8b22-ae223a1f35ce:/local:212
e9404bb1-7af0-0310-a7ff-e22194cd388b:/haver/local:927
edfcd8bd-4ce7-0310-a97e-bb1efd40edf3:/local:238


Property changes on: trunk/clients/javer
___________________________________________________________________
Name: svn:ignore
   + build
dist

Name: svk:merge
   + 1f59643a-e6e5-0310-bc24-f7d4c744f460:/haver/local/trunk/misc/javer:16426
561eb9fb-c9d5-0310-88ef-b73186cdaa44:/trunk/misc/javer:590

Added: trunk/clients/javer/TODO
===================================================================
--- trunk/clients/javer/TODO    2005-04-12 02:39:42 UTC (rev 670)
+++ trunk/clients/javer/TODO    2005-04-25 00:49:04 UTC (rev 671)
@@ -0,0 +1,7 @@
+Major planned features:
+* Message and error format strings (including timestamps)
+* Logging and menus for standalone client
+* SSL!
+* Colors
+* /set to disable e.g. .commands, ;emotes, etc
+* Synchronous-response API for the client

Added: trunk/clients/javer/build.xml
===================================================================
--- trunk/clients/javer/build.xml       2005-04-12 02:39:42 UTC (rev 670)
+++ trunk/clients/javer/build.xml       2005-04-25 00:49:04 UTC (rev 671)
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- You may freely edit this file. See commented blocks below for -->
+<!-- some examples of how to customize the build. -->
+<!-- (If you delete it and reopen the project it will be recreated.) -->
+<project name="javer" default="default" basedir=".">
+    <description>Builds, tests, and runs the project javer.</description>
+    <import file="nbproject/build-impl.xml"/>
+    <!--
+
+    There exist several targets which are by default empty and which can be 
+    used for execution of your tasks. These targets are usually executed 
+    before and after some main targets. They are: 
+
+      -pre-init:                 called before initialization of project 
properties
+      -post-init:                called after initialization of project 
properties
+      -pre-compile:              called before javac compilation
+      -post-compile:             called after javac compilation
+      -pre-compile-single:       called before javac compilation of single file
+      -post-compile-single:      called after javac compilation of single file
+      -pre-compile-test:         called before javac compilation of JUnit tests
+      -post-compile-test:        called after javac compilation of JUnit tests
+      -pre-compile-test-single:  called before javac compilation of single 
JUnit test
+      -post-compile-test-single: called after javac compilation of single 
JUunit test
+      -pre-jar:                  called before JAR building
+      -post-jar:                 called after JAR building
+      -post-clean:               called after cleaning build products
+
+    (Targets beginning with '-' are not intended to be called on their own.)
+
+    Example of inserting an obfuscator after compilation could look like this:
+
+        <target name="-post-compile">
+            <obfuscate>
+                <fileset dir="${build.classes.dir}"/>
+            </obfuscate>
+        </target>
+
+    For list of available properties check the imported 
+    nbproject/build-impl.xml file. 
+
+
+    Another way to customize the build is by overriding existing main targets.
+    The targets of interest are: 
+
+      -init-macrodef-javac:     defines macro for javac compilation
+      -init-macrodef-junit:     defines macro for junit execution
+      -init-macrodef-debug:     defines macro for class debugging
+      -init-macrodef-java:      defines macro for class execution
+      -do-jar-with-manifest:    JAR building (if you are using a manifest)
+      -do-jar-without-manifest: JAR building (if you are not using a manifest)
+      run:                      execution of project 
+      -javadoc-build:           Javadoc generation
+      test-report:              JUnit report generation
+
+    An example of overriding the target for project execution could look like 
this:
+
+        <target name="run" depends="javer-impl.jar">
+            <exec dir="bin" executable="launcher.exe">
+                <arg file="${dist.jar}"/>
+            </exec>
+        </target>
+
+    Notice that the overridden target depends on the jar target and not only 
on 
+    the compile target as the regular run target does. Again, for a list of 
available 
+    properties which you can use, check the target you are overriding in the
+    nbproject/build-impl.xml file. 
+
+    -->
+</project>


Property changes on: trunk/clients/javer/build.xml
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/clients/javer/manifest.mf
===================================================================
--- trunk/clients/javer/manifest.mf     2005-04-12 02:39:42 UTC (rev 670)
+++ trunk/clients/javer/manifest.mf     2005-04-25 00:49:04 UTC (rev 671)
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+X-COMMENT: Main-Class will be added automatically by build
+


Property changes on: trunk/clients/javer/nbproject
___________________________________________________________________
Name: svn:ignore
   + private


Added: trunk/clients/javer/nbproject/build-impl.xml
===================================================================
--- trunk/clients/javer/nbproject/build-impl.xml        2005-04-12 02:39:42 UTC 
(rev 670)
+++ trunk/clients/javer/nbproject/build-impl.xml        2005-04-25 00:49:04 UTC 
(rev 671)
@@ -0,0 +1,475 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+*** GENERATED FROM project.xml - DO NOT EDIT  ***
+***         EDIT ../build.xml INSTEAD         ***
+
+For the purpose of easier reading the script
+is divided into following sections:
+
+  - initialization
+  - compilation
+  - jar
+  - execution
+  - debugging
+  - javadoc
+  - junit compilation
+  - junit execution
+  - junit debugging
+  - applet
+  - cleanup
+
+-->
+<project name="javer-impl" default="build" basedir="..">
+    <target name="default" depends="test,jar,javadoc" description="Build and 
test whole project."/>
+    <!-- 
+    ======================
+    INITIALIZATION SECTION 
+    ======================
+    -->
+    <target name="-pre-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target name="-init-private" depends="-pre-init">
+        <property file="nbproject/private/private.properties"/>
+    </target>
+    <target name="-init-user" depends="-pre-init,-init-private">
+        <property file="${user.properties.file}"/>
+        <!-- The two properties below are usually overridden -->
+        <!-- by the active platform. Just a fallback. -->
+        <property value="1.4" name="default.javac.source"/>
+        <property value="1.4" name="default.javac.target"/>
+    </target>
+    <target name="-init-project" depends="-pre-init,-init-private,-init-user">
+        <property file="nbproject/project.properties"/>
+    </target>
+    <target name="-do-init" 
depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property">
+        <available property="manifest.available" file="${manifest.file}"/>
+        <condition property="manifest.available+main.class">
+            <and>
+                <isset property="manifest.available"/>
+                <isset property="main.class"/>
+                <not>
+                    <equals trim="true" arg2="" arg1="${main.class}"/>
+                </not>
+            </and>
+        </condition>
+        <available file="${test.src.dir}" property="have.tests"/>
+        <condition property="netbeans.home+have.tests">
+            <and>
+                <isset property="netbeans.home"/>
+                <isset property="have.tests"/>
+            </and>
+        </condition>
+        <condition property="no.javadoc.preview">
+            <isfalse value="${javadoc.preview}"/>
+        </condition>
+        <property value="" name="run.jvmargs"/>
+        <property value="" name="javac.compilerargs"/>
+        <property value="${basedir}" name="work.dir"/>
+        <condition property="no.deps">
+            <and>
+                <istrue value="${no.dependencies}"/>
+            </and>
+        </condition>
+    </target>
+    <target name="-post-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target name="-init-check" 
depends="-pre-init,-init-private,-init-user,-init-project,-do-init">
+        <fail unless="src.dir">Must set src.dir</fail>
+        <fail unless="test.src.dir">Must set test.src.dir</fail>
+        <fail unless="build.dir">Must set build.dir</fail>
+        <fail unless="dist.dir">Must set dist.dir</fail>
+        <fail unless="build.classes.dir">Must set build.classes.dir</fail>
+        <fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
+        <fail unless="build.test.classes.dir">Must set 
build.test.classes.dir</fail>
+        <fail unless="build.test.results.dir">Must set 
build.test.results.dir</fail>
+        <fail unless="build.classes.excludes">Must set 
build.classes.excludes</fail>
+        <fail unless="dist.jar">Must set dist.jar</fail>
+    </target>
+    <target name="-init-macrodef-property">
+        <macrodef name="property" 
uri="http://www.netbeans.org/ns/j2se-project/1";>
+            <attribute name="name"/>
+            <attribute name="value"/>
+            <sequential>
+                <property value="[EMAIL PROTECTED]" name="@{name}"/>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-macrodef-javac">
+        <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/1";>
+            <attribute name="srcdir" default="${src.dir}"/>
+            <attribute name="destdir" default="${build.classes.dir}"/>
+            <attribute name="classpath" default="${javac.classpath}"/>
+            <attribute name="debug" default="${javac.debug}"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <javac srcdir="@{srcdir}" destdir="@{destdir}" 
debug="@{debug}" deprecation="${javac.deprecation}" source="${javac.source}" 
target="${javac.target}" includeantruntime="false">
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <compilerarg line="${javac.compilerargs}"/>
+                    <customize/>
+                </javac>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-macrodef-junit">
+        <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/1";>
+            <attribute name="includes" default="**/*Test.java"/>
+            <sequential>
+                <junit showoutput="true" fork="true" dir="${basedir}" 
failureproperty="tests.failed" errorproperty="tests.failed">
+                    <batchtest todir="${build.test.results.dir}">
+                        <fileset includes="@{includes}" dir="${test.src.dir}"/>
+                    </batchtest>
+                    <classpath>
+                        <path path="${run.test.classpath}"/>
+                    </classpath>
+                    <syspropertyset>
+                        <propertyref prefix="test-sys-prop."/>
+                        <mapper to="*" from="test-sys-prop.*" type="glob"/>
+                    </syspropertyset>
+                    <formatter usefile="false" type="brief"/>
+                </junit>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-macrodef-nbjpda">
+        <macrodef name="nbjpdastart" 
uri="http://www.netbeans.org/ns/j2se-project/1";>
+            <attribute name="name" default="${main.class}"/>
+            <attribute name="classpath" default="${debug.classpath}"/>
+            <attribute name="stopclassname" default=""/>
+            <sequential>
+                <nbjpdastart stopclassname="@{stopclassname}" name="@{name}" 
addressproperty="jpda.address" transport="dt_socket">
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                </nbjpdastart>
+            </sequential>
+        </macrodef>
+        <macrodef name="nbjpdareload" 
uri="http://www.netbeans.org/ns/j2se-project/1";>
+            <attribute name="dir" default="${build.classes.dir}"/>
+            <sequential>
+                <nbjpdareload>
+                    <fileset dir="@{dir}" includes="${fix.includes}*.class"/>
+                </nbjpdareload>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-macrodef-debug">
+        <macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/1";>
+            <attribute name="classname" default="${main.class}"/>
+            <attribute name="classpath" default="${debug.classpath}"/>
+            <attribute name="args" default="${application.args}"/>
+            <sequential>
+                <java classname="@{classname}" fork="true" dir="${work.dir}">
+                    <jvmarg value="-Xdebug"/>
+                    <jvmarg value="-Xnoagent"/>
+                    <jvmarg value="-Djava.compiler=none"/>
+                    <jvmarg 
value="-Xrunjdwp:transport=dt_socket,address=${jpda.address}"/>
+                    <jvmarg line="${run.jvmargs}"/>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <syspropertyset>
+                        <propertyref prefix="run-sys-prop."/>
+                        <mapper to="*" from="run-sys-prop.*" type="glob"/>
+                    </syspropertyset>
+                    <arg line="@{args}"/>
+                </java>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-macrodef-java">
+        <macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1";>
+            <attribute name="classname" default="${main.class}"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <java classname="@{classname}" fork="true" dir="${work.dir}">
+                    <jvmarg line="${run.jvmargs}"/>
+                    <classpath>
+                        <path path="${run.classpath}"/>
+                    </classpath>
+                    <syspropertyset>
+                        <propertyref prefix="run-sys-prop."/>
+                        <mapper to="*" from="run-sys-prop.*" type="glob"/>
+                    </syspropertyset>
+                    <customize/>
+                </java>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-presetdef-jar">
+        <presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1";>
+            <jar compress="${jar.compress}" jarfile="${dist.jar}">
+                <fileset xmlns="http://www.netbeans.org/ns/j2se-project/1"; 
dir="${build.classes.dir}"/>
+            </jar>
+        </presetdef>
+    </target>
+    <target name="init" 
depends="-pre-init,-init-private,-init-user,-init-project,-do-init,-post-init,-init-check,-init-macrodef-property,-init-macrodef-javac,-init-macrodef-junit,-init-macrodef-nbjpda,-init-macrodef-debug,-init-macrodef-java,-init-presetdef-jar"/>
+    <!--
+    ===================
+    COMPILATION SECTION
+    ===================
+    -->
+    <target name="deps-jar" depends="init" unless="no.deps"/>
+    <target name="-pre-pre-compile" depends="init,deps-jar">
+        <mkdir dir="${build.classes.dir}"/>
+    </target>
+    <target name="-pre-compile">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target name="-do-compile" 
depends="init,deps-jar,-pre-pre-compile,-pre-compile">
+        <j2seproject:javac 
xmlns:j2seproject="http://www.netbeans.org/ns/j2se-project/1"/>
+        <copy todir="${build.classes.dir}">
+            <fileset excludes="${build.classes.excludes}" dir="${src.dir}"/>
+        </copy>
+    </target>
+    <target name="-post-compile">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target name="compile" 
depends="init,deps-jar,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" 
description="Compile project."/>
+    <target name="-pre-compile-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target name="-do-compile-single" depends="init,deps-jar,-pre-pre-compile">
+        <fail unless="javac.includes">Must select some files in the IDE or set 
javac.includes</fail>
+        <j2seproject:javac 
xmlns:j2seproject="http://www.netbeans.org/ns/j2se-project/1";>
+            <customize>
+                <patternset includes="${javac.includes}"/>
+            </customize>
+        </j2seproject:javac>
+    </target>
+    <target name="-post-compile-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target name="compile-single" 
depends="init,deps-jar,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single"/>
+    <!--
+    ====================
+    JAR BUILDING SECTION
+    ====================
+    -->
+    <target name="-pre-pre-jar" depends="init">
+        <dirname file="${dist.jar}" property="dist.jar.dir"/>
+        <mkdir dir="${dist.jar.dir}"/>
+    </target>
+    <target name="-pre-jar">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target name="-do-jar-without-manifest" 
depends="init,compile,-pre-pre-jar,-pre-jar" unless="manifest.available">
+        <j2seproject:jar 
xmlns:j2seproject="http://www.netbeans.org/ns/j2se-project/1"/>
+    </target>
+    <target name="-do-jar-with-manifest" 
depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available" 
unless="manifest.available+main.class">
+        <j2seproject:jar 
xmlns:j2seproject="http://www.netbeans.org/ns/j2se-project/1"; 
manifest="${manifest.file}"/>
+    </target>
+    <target name="-do-jar-with-mainclass" 
depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class">
+        <j2seproject:jar 
xmlns:j2seproject="http://www.netbeans.org/ns/j2se-project/1"; 
manifest="${manifest.file}">
+            <manifest xmlns="http://www.netbeans.org/ns/j2se-project/1";>
+                <attribute value="${main.class}" name="Main-Class"/>
+            </manifest>
+        </j2seproject:jar>
+    </target>
+    <target name="-post-jar">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target name="jar" 
depends="init,compile,-pre-jar,-do-jar-with-manifest,-do-jar-without-manifest,-do-jar-with-mainclass,-post-jar"
 description="Build JAR."/>
+    <!--
+    =================
+    EXECUTION SECTION
+    =================
+    -->
+    <target name="run" depends="init,compile" description="Run a main class.">
+        <j2seproject:java 
xmlns:j2seproject="http://www.netbeans.org/ns/j2se-project/1";>
+            <customize>
+                <arg line="${application.args}"/>
+            </customize>
+        </j2seproject:java>
+    </target>
+    <target name="run-single" depends="init,compile-single">
+        <fail unless="run.class">Must select one file in the IDE or set 
run.class</fail>
+        <j2seproject:java 
xmlns:j2seproject="http://www.netbeans.org/ns/j2se-project/1"; 
classname="${run.class}"/>
+    </target>
+    <!--
+    =================
+    DEBUGGING SECTION
+    =================
+    -->
+    <target name="-debug-start-debugger" if="netbeans.home" depends="init">
+        <j2seproject:nbjpdastart 
xmlns:j2seproject="http://www.netbeans.org/ns/j2se-project/1"; 
name="${debug.class}"/>
+    </target>
+    <target name="-debug-start-debuggee" depends="init,compile">
+        <j2seproject:debug 
xmlns:j2seproject="http://www.netbeans.org/ns/j2se-project/1"/>
+    </target>
+    <target name="debug" if="netbeans.home" 
depends="init,compile,-debug-start-debugger,-debug-start-debuggee" 
description="Debug project in IDE."/>
+    <target name="-debug-start-debugger-stepinto" if="netbeans.home" 
depends="init">
+        <j2seproject:nbjpdastart 
xmlns:j2seproject="http://www.netbeans.org/ns/j2se-project/1"; 
stopclassname="${main.class}"/>
+    </target>
+    <target name="debug-stepinto" if="netbeans.home" 
depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee"/>
+    <target name="-debug-start-debuggee-single" if="netbeans.home" 
depends="init,compile-single">
+        <fail unless="debug.class">Must select one file in the IDE or set 
debug.class</fail>
+        <j2seproject:debug 
xmlns:j2seproject="http://www.netbeans.org/ns/j2se-project/1"; 
classname="${debug.class}"/>
+    </target>
+    <target name="debug-single" if="netbeans.home" 
depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-single"/>
+    <target name="-pre-debug-fix" depends="init">
+        <fail unless="fix.includes">Must set fix.includes</fail>
+        <property value="${fix.includes}.java" name="javac.includes"/>
+    </target>
+    <target name="-do-debug-fix" if="netbeans.home" 
depends="init,-pre-debug-fix,compile-single">
+        <j2seproject:nbjpdareload 
xmlns:j2seproject="http://www.netbeans.org/ns/j2se-project/1"/>
+    </target>
+    <target name="debug-fix" if="netbeans.home" 
depends="init,-pre-debug-fix,-do-debug-fix"/>
+    <!--
+    ===============
+    JAVADOC SECTION
+    ===============
+    -->
+    <target name="-javadoc-build" depends="init">
+        <mkdir dir="${dist.javadoc.dir}"/>
+        <javadoc destdir="${dist.javadoc.dir}" source="${javac.source}" 
notree="${javadoc.notree}" use="${javadoc.use}" nonavbar="${javadoc.nonavbar}" 
noindex="${javadoc.noindex}" splitindex="${javadoc.splitindex}" 
author="${javadoc.author}" version="${javadoc.version}" 
windowtitle="${javadoc.windowtitle}" private="${javadoc.private}" 
failonerror="true">
+            <classpath>
+                <path path="${javac.classpath}"/>
+            </classpath>
+            <sourcepath>
+                <pathelement location="${src.dir}"/>
+            </sourcepath>
+            <fileset dir="${src.dir}"/>
+        </javadoc>
+    </target>
+    <target name="-javadoc-browse" if="netbeans.home" 
unless="no.javadoc.preview" depends="init,-javadoc-build">
+        <nbbrowse file="${dist.javadoc.dir}/index.html"/>
+    </target>
+    <target name="javadoc" depends="init,-javadoc-build,-javadoc-browse" 
description="Build Javadoc."/>
+    <!--
+    =========================
+    JUNIT COMPILATION SECTION
+    =========================
+    -->
+    <target name="-pre-pre-compile-test" if="have.tests" 
depends="init,compile">
+        <mkdir dir="${build.test.classes.dir}"/>
+    </target>
+    <target name="-pre-compile-test">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target name="-do-compile-test" if="have.tests" 
depends="init,compile,-pre-pre-compile-test,-pre-compile-test">
+        <j2seproject:javac 
xmlns:j2seproject="http://www.netbeans.org/ns/j2se-project/1"; 
classpath="${javac.test.classpath}" debug="true" 
destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
+        <copy todir="${build.test.classes.dir}">
+            <fileset dir="${test.src.dir}">
+                <exclude name="**/*.java"/>
+            </fileset>
+        </copy>
+    </target>
+    <target name="-post-compile-test">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target name="compile-test" 
depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test"/>
+    <target name="-pre-compile-test-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target name="-do-compile-test-single" if="have.tests" 
depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single">
+        <fail unless="javac.includes">Must select some files in the IDE or set 
javac.includes</fail>
+        <j2seproject:javac 
xmlns:j2seproject="http://www.netbeans.org/ns/j2se-project/1"; 
classpath="${javac.test.classpath}" debug="true" 
destdir="${build.test.classes.dir}" srcdir="${test.src.dir}">
+            <customize>
+                <patternset includes="${javac.includes}"/>
+            </customize>
+        </j2seproject:javac>
+    </target>
+    <target name="-post-compile-test-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target name="compile-test-single" 
depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single,-do-compile-test-single,-post-compile-test-single"/>
+    <!--
+    =======================
+    JUNIT EXECUTION SECTION
+    =======================
+    -->
+    <target name="-pre-test-run" if="have.tests" depends="init">
+        <mkdir dir="${build.test.results.dir}"/>
+    </target>
+    <target name="-do-test-run" if="have.tests" 
depends="init,compile-test,-pre-test-run">
+        <j2seproject:junit 
xmlns:j2seproject="http://www.netbeans.org/ns/j2se-project/1"/>
+    </target>
+    <target name="-post-test-run" if="have.tests" 
depends="init,compile-test,-pre-test-run,-do-test-run">
+        <fail if="tests.failed">Some tests failed; see details above.</fail>
+    </target>
+    <target name="test-report" if="have.tests" depends="init"/>
+    <target name="-test-browse" if="netbeans.home+have.tests" depends="init"/>
+    <target name="test" 
depends="init,compile-test,-pre-test-run,-do-test-run,test-report,-post-test-run,-test-browse"
 description="Run unit tests."/>
+    <target name="-pre-test-run-single" if="have.tests" depends="init">
+        <mkdir dir="${build.test.results.dir}"/>
+    </target>
+    <target name="-do-test-run-single" if="have.tests" 
depends="init,compile-test-single,-pre-test-run-single">
+        <fail unless="test.includes">Must select some files in the IDE or set 
test.includes</fail>
+        <j2seproject:junit 
xmlns:j2seproject="http://www.netbeans.org/ns/j2se-project/1"; 
includes="${test.includes}"/>
+    </target>
+    <target name="-post-test-run-single" if="have.tests" 
depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single">
+        <fail if="tests.failed">Some tests failed; see details above.</fail>
+    </target>
+    <target name="test-single" 
depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single,-post-test-run-single"
 description="Run single unit test."/>
+    <!--
+    =======================
+    JUNIT DEBUGGING SECTION
+    =======================
+    -->
+    <target name="-debug-start-debuggee-test" if="have.tests" 
depends="init,compile-test">
+        <fail unless="test.class">Must select one file in the IDE or set 
test.class</fail>
+        <j2seproject:debug 
xmlns:j2seproject="http://www.netbeans.org/ns/j2se-project/1"; 
args="${test.class}" classpath="${debug.test.classpath}" 
classname="junit.textui.TestRunner"/>
+    </target>
+    <target name="-debug-start-debugger-test" if="netbeans.home+have.tests" 
depends="init,compile-test">
+        <j2seproject:nbjpdastart 
xmlns:j2seproject="http://www.netbeans.org/ns/j2se-project/1"; 
classpath="${debug.test.classpath}" name="${test.class}"/>
+    </target>
+    <target name="debug-test" 
depends="init,compile-test,-debug-start-debugger-test,-debug-start-debuggee-test"/>
+    <target name="-do-debug-fix-test" if="netbeans.home" 
depends="init,-pre-debug-fix,compile-test-single">
+        <j2seproject:nbjpdareload 
xmlns:j2seproject="http://www.netbeans.org/ns/j2se-project/1"; 
dir="${build.test.classes.dir}"/>
+    </target>
+    <target name="debug-fix-test" if="netbeans.home" 
depends="init,-pre-debug-fix,-do-debug-fix-test"/>
+    <!--
+    =========================
+    APPLET EXECUTION SECTION
+    =========================
+    -->
+    <target name="run-applet" depends="init,compile-single">
+        <fail unless="applet.url">Must select one file in the IDE or set 
applet.url</fail>
+        <j2seproject:java 
xmlns:j2seproject="http://www.netbeans.org/ns/j2se-project/1"; 
classname="sun.applet.AppletViewer">
+            <customize>
+                <arg value="${applet.url}"/>
+            </customize>
+        </j2seproject:java>
+    </target>
+    <!--
+    =========================
+    APPLET DEBUGGING  SECTION
+    =========================
+    -->
+    <target name="-debug-start-debuggee-applet" if="netbeans.home" 
depends="init,compile-single">
+        <fail unless="applet.url">Must select one file in the IDE or set 
applet.url</fail>
+        <j2seproject:debug 
xmlns:j2seproject="http://www.netbeans.org/ns/j2se-project/1"; 
args="&quot;${applet.url}&quot;" classname="sun.applet.AppletViewer"/>
+    </target>
+    <target name="debug-applet" if="netbeans.home" 
depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-applet"/>
+    <!--
+    ===============
+    CLEANUP SECTION
+    ===============
+    -->
+    <target name="deps-clean" depends="init" unless="no.deps"/>
+    <target name="-do-clean" depends="init">
+        <delete dir="${build.dir}"/>
+        <delete dir="${dist.dir}"/>
+    </target>
+    <target name="-post-clean">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target name="clean" depends="init,deps-clean,-do-clean,-post-clean" 
description="Clean build products."/>
+</project>


Property changes on: trunk/clients/javer/nbproject/build-impl.xml
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/clients/javer/nbproject/genfiles.properties
===================================================================
--- trunk/clients/javer/nbproject/genfiles.properties   2005-04-12 02:39:42 UTC 
(rev 670)
+++ trunk/clients/javer/nbproject/genfiles.properties   2005-04-25 00:49:04 UTC 
(rev 671)
@@ -0,0 +1,6 @@
+build.xml.data.CRC32=6ef497b2
+build.xml.script.CRC32=e8133476
+build.xml.stylesheet.CRC32=ba5d3624
+nbproject/build-impl.xml.data.CRC32=6ef497b2
+nbproject/build-impl.xml.script.CRC32=e20b63b8
+nbproject/build-impl.xml.stylesheet.CRC32=1cf0b40c


Property changes on: trunk/clients/javer/nbproject/genfiles.properties
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/clients/javer/nbproject/project.properties
===================================================================
--- trunk/clients/javer/nbproject/project.properties    2005-04-12 02:39:42 UTC 
(rev 670)
+++ trunk/clients/javer/nbproject/project.properties    2005-04-25 00:49:04 UTC 
(rev 671)
@@ -0,0 +1,54 @@
+application.args=
+build.classes.dir=${build.dir}/classes
+build.classes.excludes=**/*.java,**/*.form
+# This directory is removed when the project is cleaned:
+build.dir=build
+# Only compile against the classpath explicitly listed here:
+build.sysclasspath=ignore
+build.test.classes.dir=${build.dir}/test/classes
+build.test.results.dir=${build.dir}/test/results
+debug.classpath=\
+    ${run.classpath}
+debug.test.classpath=\
+    ${run.test.classpath}
+# This directory is removed when the project is cleaned:
+dist.dir=dist
+dist.jar=${dist.dir}/javer.jar
+dist.javadoc.dir=${dist.dir}/javadoc
+jar.compress=false
+javac.classpath=\
+
+# Space-separated list of extra javac options
+javac.compilerargs=
+javac.deprecation=false
+javac.source=${default.javac.source}
+javac.target=${default.javac.target}
+javac.test.classpath=\
+    ${javac.classpath}:\
+    ${build.classes.dir}:\
+    ${libs.junit.classpath}
+javadoc.author=false
+javadoc.encoding=
+javadoc.noindex=false
+javadoc.nonavbar=false
+javadoc.notree=false
+javadoc.private=false
+javadoc.splitindex=true
+javadoc.use=true
+javadoc.version=false
+javadoc.windowtitle=
+main.class=javer.JaverUI
+manifest.file=manifest.mf
+platform.active=default_platform
+run.classpath=\
+    ${javac.classpath}:\
+    ${build.classes.dir}
+# Space-separated list of JVM arguments used when running the project
+# (you may also define separate properties like run-sys-prop.name=value 
instead of -Dname=value
+# or test-sys-prop.name=value to set system properties for unit tests):
+run.jvmargs=
+run.test.classpath=\
+    ${javac.test.classpath}:\
+    ${build.test.classes.dir}
+src.dir=src
+test.src.dir=test


Property changes on: trunk/clients/javer/nbproject/project.properties
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/clients/javer/nbproject/project.xml
===================================================================
--- trunk/clients/javer/nbproject/project.xml   2005-04-12 02:39:42 UTC (rev 
670)
+++ trunk/clients/javer/nbproject/project.xml   2005-04-25 00:49:04 UTC (rev 
671)
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://www.netbeans.org/ns/project/1";>
+    <type>org.netbeans.modules.java.j2seproject</type>
+    <configuration>
+        <data xmlns="http://www.netbeans.org/ns/j2se-project/1";>
+            <name>javer</name>
+            <minimum-ant-version>1.6</minimum-ant-version>
+        </data>
+    </configuration>
+</project>


Property changes on: trunk/clients/javer/nbproject/project.xml
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/clients/javer/src/javer/CMod.java
===================================================================
--- trunk/clients/javer/src/javer/CMod.java     2005-04-12 02:39:42 UTC (rev 
670)
+++ trunk/clients/javer/src/javer/CMod.java     2005-04-25 00:49:04 UTC (rev 
671)
@@ -0,0 +1,177 @@
+/*
+ * CMod.java
+ *
+ * Created on January 14, 2005, 7:03 PM
+ */
+
+package javer;
+import java.util.*;
+import java.io.*;
+import java.math.*;
+
+/**
+ *
+ * @author bdonlan
+ */
+public class CMod extends GameMod {
+    
+    boolean conspiracyExists = false;
+    boolean polling = false;
+    String innocent = null;
+    Map pollresults = null;
+    String homechannel;
+    Object pollTimer = null;
+    
+    /** Creates a new instance of CMod */
+    public CMod(String homechannel) {
+        super();
+        this.homechannel = homechannel;
+    }
+
+    protected void eventPrivateNormalMessage(String who, String arg) throws 
java.io.IOException {
+        if (polling) {
+            String val = arg.toLowerCase();
+            boolean choice;
+            if (val.equals("yes"))
+                choice = true;
+            else if (val.equals("no"))
+                choice = false;
+            else {
+                sendPrivateNormalMessage(who, "Huh?");
+                super.eventPrivateNormalMessage(who, arg);
+                return;
+            }
+            if (pollresults.containsKey(who)) {
+                sendPrivateNormalMessage(who, "You cannot change your 
choice.");
+            } else {
+                Boolean value = new Boolean(choice);
+                pollresults.put(who, value);
+                sendPrivateNormalMessage(who, "Noted.");
+                if (pollresults.size() == players.size()) {
+                    tallyResults();
+                }
+            }
+        }
+        super.eventPrivateNormalMessage(who, arg);
+    }
+
+    protected void eventIdentAccepted() throws java.io.IOException {
+        super.eventIdentAccepted();
+        join(homechannel);
+    }
+
+    public void endGame() throws java.io.IOException {
+        polling = false;
+        if (pollTimer != null) {
+            TimedInvoker.unschedule(pollTimer);
+        }
+        pollresults = null;
+        innocent = null;
+        pollTimer = null;
+        super.endGame();
+    }
+
+    public void beginGame() throws java.io.IOException {
+        Random r = new Random();
+        conspiracyExists = r.nextBoolean();
+        if (conspiracyExists) {
+            Object[] playerarray = players.toArray();
+            innocent = (String)playerarray[r.nextInt(playerarray.length)];
+        }
+        Iterator pi = players.iterator();
+        while (pi.hasNext()) {
+            String uid = (String)pi.next();
+            if (uid.equals(innocent) || !conspiracyExists) {
+                sendPrivateNormalMessage(uid, "You are an innocent in this 
game.");
+            } else {
+                sendPrivateNormalMessage(uid, "You are a conspirator, and the 
innocent is " + innocent);
+            }
+        }
+        sendNormalMessage(homechannel, "A game of Conspiracy has begun! You 
have 10 minutes before polling phase begins.");
+        pollTimer = TimedInvoker.invokeAfter(10 * 60 * 1000, new Runnable() {
+            public void run() {
+                try {
+                    beginPolling();
+                } catch (IOException e) {
+                    eventIOException(e);
+                }
+            }
+        });
+        super.beginGame();
+    }
+    
+    protected void beginPolling() throws IOException {
+        if (!playing)
+            return;
+        sendNormalMessage(homechannel, "Time's up! Please /msg me with 'yes'" +
+                " if you think there is a conspiracy, or 'no' if you believe" +
+                " there is no conspiracy.");
+        pollresults = new HashMap(players.size());
+        polling = true;
+    }
+    
+    protected void tallyResults() throws IOException {
+        Set winners;
+        if (conspiracyExists) {
+            boolean innocentWins;
+            innocentWins = ((Boolean)pollresults.get(innocent)).booleanValue();
+            if (innocentWins)
+                winners = Collections.singleton(innocent);
+            else {
+                winners = new HashSet(players);
+                winners.remove(innocent);
+            }
+        } else {
+            Iterator it = players.iterator();
+            winners = new HashSet();
+            while (it.hasNext()) {
+                String uid = (String)it.next();
+                Boolean result = (Boolean)pollresults.get(uid);
+                if (!result.booleanValue())
+                    winners.add(uid);
+            }
+        }
+        Iterator it = players.iterator();
+        sendNormalMessage(homechannel, 
+                "All polls are in. The results are as follows:");
+        /* field lengths: nick 15, poll 3, win 3 */
+        sendNormalMessage(homechannel, 
+                "NICK            RES WIN");
+        sendNormalMessage(homechannel,
+                "=======================");
+        while (it.hasNext()) {
+            String uid = (String)it.next();
+            String nick = (String)channelMembers.get(uid);
+            boolean won = winners.contains(uid);
+            boolean vote = ((Boolean)pollresults.get(uid)).booleanValue();
+            while(nick.length() < 15) {
+                nick = nick + " ";
+            }
+            String msg = nick;
+            if (vote)
+                msg = msg + "  Y ";
+            else
+                msg = msg + "  N ";
+            if (won)
+                msg = msg + "  Y ";
+            else
+                msg = msg + "  N ";
+            sendNormalMessage(homechannel, msg);
+        }
+        sendNormalMessage(homechannel,
+                "=======================");
+        sendNormalMessage(homechannel,
+                "Game over. Thanks for playing!");
+        endGame();
+    }
+    
+    public static void main(String[] args) throws Exception {
+        CMod mod = new CMod(args[3]);
+        mod.connect(args[0], args[1], Integer.decode(args[2]).intValue());
+    }
+
+    protected void eventDebugMessage(String s) throws IOException {
+        //log("DEBUG", s);
+        super.eventDebugMessage(s);
+    }
+}


Property changes on: trunk/clients/javer/src/javer/CMod.java
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/clients/javer/src/javer/ChannelTab.form
===================================================================
--- trunk/clients/javer/src/javer/ChannelTab.form       2005-04-12 02:39:42 UTC 
(rev 670)
+++ trunk/clients/javer/src/javer/ChannelTab.form       2005-04-25 00:49:04 UTC 
(rev 671)
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.0" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
+
+  <Layout 
class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
+  <SubComponents>
+    <Container class="javax.swing.JSplitPane" name="jSplitPane1">
+      <Constraints>
+        <Constraint 
layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" 
value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+          <BorderConstraints direction="Center"/>
+        </Constraint>
+      </Constraints>
+
+      <Layout 
class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
+      <SubComponents>
+        <Container class="javax.swing.JScrollPane" name="jScrollPane1">
+          <Constraints>
+            <Constraint 
layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"
 
value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
+              <JSplitPaneConstraints position="left"/>
+            </Constraint>
+          </Constraints>
+
+          <Layout 
class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+          <SubComponents>
+            <Component class="javax.swing.JTextArea" name="chatArea">
+              <Properties>
+                <Property name="editable" type="boolean" value="false"/>
+                <Property name="lineWrap" type="boolean" value="true"/>
+              </Properties>
+              <AuxValues>
+                <AuxValue name="JavaCodeGenerator_VariableModifier" 
type="java.lang.Integer" value="0"/>
+              </AuxValues>
+            </Component>
+          </SubComponents>
+        </Container>
+        <Container class="javax.swing.JScrollPane" name="jScrollPane2">
+          <Constraints>
+            <Constraint 
layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"
 
value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
+              <JSplitPaneConstraints position="right"/>
+            </Constraint>
+          </Constraints>
+
+          <Layout 
class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+          <SubComponents>
+            <Component class="javax.swing.JList" name="userList">
+              <Events>
+                <EventHandler event="mouseClicked" 
listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" 
handler="userClicked"/>
+              </Events>
+              <AuxValues>
+                <AuxValue name="JavaCodeGenerator_VariableModifier" 
type="java.lang.Integer" value="0"/>
+              </AuxValues>
+            </Component>
+          </SubComponents>
+        </Container>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>

Added: trunk/clients/javer/src/javer/ChannelTab.java
===================================================================
--- trunk/clients/javer/src/javer/ChannelTab.java       2005-04-12 02:39:42 UTC 
(rev 670)
+++ trunk/clients/javer/src/javer/ChannelTab.java       2005-04-25 00:49:04 UTC 
(rev 671)
@@ -0,0 +1,142 @@
+/*
+ * ChannelTab.java
+ *
+ * Created on January 5, 2005, 11:50 PM
+ */
+
+package javer;
+import java.io.*;
+import java.util.*;
+import java.awt.*;
+
+/**
+ *
+ * @author  bdonlan
+ */
+public class ChannelTab extends javax.swing.JPanel implements QueryTab {
+    
+    JaverUIPanel panel;
+    HaverClient cli;
+    String channel;
+    Set users;
+    boolean positioned = false;
+    
+    /** Creates new form ChannelTab */
+    public ChannelTab(JaverUIPanel panel, HaverClient cli, String channel) {
+        this.panel = panel;
+        this.cli = cli;
+        this.channel = channel;
+        users = new java.util.TreeSet();
+        initComponents();
+    }
+    
+    public String getChannel() {
+        return channel;
+    }
+    
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    private void initComponents() {//GEN-BEGIN:initComponents
+        jSplitPane1 = new javax.swing.JSplitPane();
+        jScrollPane1 = new javax.swing.JScrollPane();
+        chatArea = new javax.swing.JTextArea();
+        jScrollPane2 = new javax.swing.JScrollPane();
+        userList = new javax.swing.JList();
+
+        setLayout(new java.awt.BorderLayout());
+
+        chatArea.setEditable(false);
+        chatArea.setLineWrap(true);
+        jScrollPane1.setViewportView(chatArea);
+
+        jSplitPane1.setLeftComponent(jScrollPane1);
+
+        userList.addMouseListener(new java.awt.event.MouseAdapter() {
+            public void mouseClicked(java.awt.event.MouseEvent evt) {
+                userClicked(evt);
+            }
+        });
+
+        jScrollPane2.setViewportView(userList);
+
+        jSplitPane1.setRightComponent(jScrollPane2);
+
+        add(jSplitPane1, java.awt.BorderLayout.CENTER);
+
+    }//GEN-END:initComponents
+
+    private void userClicked(java.awt.event.MouseEvent evt) 
{//GEN-FIRST:event_userClicked
+        String item = (String) userList.getSelectedValue();
+        panel.activateQuery(item);
+    }//GEN-LAST:event_userClicked
+    
+    public void sendText(String s) throws java.io.IOException {
+        cli.sendNormalMessage(channel, s);
+    }
+    
+    public void sendAction(String s) throws java.io.IOException {
+        cli.sendAction(channel, s);
+    }
+
+    public void putText(String s) {
+        /* XXX: this is a bit of a hack */
+        if (!positioned) {
+            jSplitPane1.setDividerLocation(0.8);
+            positioned = true;
+        }
+        chatArea.append(s + "\n");
+        chatArea.setCaretPosition(chatArea.getText().length());
+    }
+    
+    public void updateUsers() {
+        userList.setListData(users.toArray());
+    }
+    
+    public void setUsers(Set m) {
+        try {
+            users = (SortedSet) m;
+        } catch (ClassCastException e) {
+            users = new TreeSet(m);
+        }
+        updateUsers();
+        updateSizes();
+    }
+    
+    public void addUser(String who) {
+        users.add(who);
+        updateUsers();
+    }
+    
+    public void delUser(String who) {
+        users.remove(who);
+        updateUsers();
+    }
+    
+    public boolean hasUser(String who) {
+        return users.contains(who);
+    }
+    
+    public void updateSizes() {
+        Dimension listsize = jScrollPane2.getPreferredSize();
+        Dimension windowsize = this.getSize();
+        int dividerSize = jSplitPane1.getDividerSize();
+        int pos = windowsize.width - dividerSize - listsize.width - 10;
+        if (pos < (windowsize.width * 8) / 10) {
+            jSplitPane1.setDividerLocation(0.8);
+            return;
+        }
+        jSplitPane1.setDividerLocation(pos);
+    }
+    
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    javax.swing.JTextArea chatArea;
+    private javax.swing.JScrollPane jScrollPane1;
+    private javax.swing.JScrollPane jScrollPane2;
+    private javax.swing.JSplitPane jSplitPane1;
+    javax.swing.JList userList;
+    // End of variables declaration//GEN-END:variables
+    
+}


Property changes on: trunk/clients/javer/src/javer/ChannelTab.java
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/clients/javer/src/javer/GameMod.java
===================================================================
--- trunk/clients/javer/src/javer/GameMod.java  2005-04-12 02:39:42 UTC (rev 
670)
+++ trunk/clients/javer/src/javer/GameMod.java  2005-04-25 00:49:04 UTC (rev 
671)
@@ -0,0 +1,154 @@
+/*
+ * GameMod.java
+ *
+ * Created on January 14, 2005, 6:16 PM
+ */
+
+package javer;
+import java.util.*;
+import java.io.*;
+
+/**
+ *
+ * @author bdonlan
+ */
+public abstract class GameMod extends HaverClient {
+        
+    protected boolean connected = false;
+    protected boolean joined = false;
+    protected boolean playing = false;
+    protected boolean starting = false;
+    protected String channel = null;
+    protected Map channelMembers = null; /* UID -> nick */
+    protected Set players = null; /* UID */
+    protected Object joinTimer = null;
+    
+    /** Creates a new instance of GameMod */
+    protected GameMod() {
+    }
+
+    protected void log(String level, String message) {
+        System.err.println(level + ": " + message);
+    }
+    
+    public void dropPlayer(String requestor, String dropee) {
+        /* TODO */
+    }
+    
+    protected void eventChannelPart(String where) throws IOException {
+        joined = false;
+        endGame();
+        channelMembers = null;
+        channel = null;
+        super.eventChannelPart(where);
+    }
+
+    protected void eventChannelJoin(String where) throws IOException {
+        if (joined) {
+            log("CRITICAL", "Joined an extra channel: " + where);
+            return;
+        }
+        joined = true;
+        channel = where;
+        listChannel(where);
+        super.eventChannelJoin(where);
+    }
+
+    protected boolean eventIOException(IOException e) {
+
+        boolean retValue;
+        
+        retValue = super.eventIOException(e);
+        return retValue;
+    }
+
+    protected void eventIdentFailed(String why, String[] args) throws 
IOException {
+
+        super.eventIdentFailed(why, args);
+    }
+
+    protected void eventChannelList(String where, Set names) throws 
IOException {
+        Iterator it = names.iterator();
+        if (!where.equals(channel))
+            return;
+        channelMembers = new HashMap();
+        while (it.hasNext()) {
+            Object o = it.next();
+            channelMembers.put(o,o);
+        }
+        super.eventChannelList(where, names);
+    }
+
+    protected void eventNormalMessage(String where, String who, String arg) 
throws IOException {
+        if (arg.equals("!join") && starting) {
+            if (players.contains(who)) {
+                sendPrivateNormalMessage(who, "You are already registered.");
+            } else {
+                players.add(who);
+                sendPrivateNormalMessage(who, "You are now registered.");
+            }
+        } else if (arg.equals("!abort") && (starting || playing)) {
+            abortGame();
+        } else if (arg.indexOf("!drop") == 0 && (starting || playing)) {
+            if (arg.length() == 0) {
+                dropPlayer(who, who);
+            } else {
+                if (arg.indexOf("!drop ") == 0) {
+                    int i = "!drop ".length();
+                    for (; i < arg.length(); i++) {
+                        if (arg.charAt(i) != ' ')
+                            break;
+                    }
+                    if (i != arg.length()) {
+                        dropPlayer(who, arg.substring(i));
+                    }
+                }
+            }
+        } else if (arg.equals("!start") && !(playing || starting)) {
+            starting = true;
+            players = new HashSet();
+            sendNormalMessage(where, "A new game has begun. Type !join in the 
next 30 seconds to join.");
+            joinTimer = TimedInvoker.invokeAfter(30 * 1000, new Runnable() {
+                public void run () {
+                    try {
+                        beginGame();
+                    } catch (IOException e) {
+                        eventIOException(e);
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                    }
+                    joinTimer = null;
+                }
+            });
+        }
+        super.eventNormalMessage(where, who, arg);
+    }
+
+    protected void eventDisconnected() throws IOException {
+        endGame();
+        super.eventDisconnected();
+    }
+
+    protected void eventIdentAccepted() throws IOException {
+        connected = true;
+        super.eventIdentAccepted();
+    }
+    
+    public void endGame() throws IOException {
+        playing = starting = false;
+        players = null;
+        if (joinTimer != null) {
+            TimedInvoker.unschedule(joinTimer);
+            joinTimer = null;
+        }
+    }
+    
+    public void abortGame() throws IOException {
+        endGame();
+        sendNormalMessage(channel, "Game aborted");
+    }
+    
+    public void beginGame() throws IOException {
+        playing = true;
+    }
+}


Property changes on: trunk/clients/javer/src/javer/GameMod.java
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/clients/javer/src/javer/HaverClient.java
===================================================================
--- trunk/clients/javer/src/javer/HaverClient.java      2005-04-12 02:39:42 UTC 
(rev 670)
+++ trunk/clients/javer/src/javer/HaverClient.java      2005-04-25 00:49:04 UTC 
(rev 671)
@@ -0,0 +1,711 @@
+/*
+ * HaverClient.java
+ *
+ * Created on January 5, 2005, 8:14 PM
+ */
+
+package javer;
+import java.util.*;
+import java.io.*;
+
+/**
+ *
+ * @author  bdonlan
+ */
+public class HaverClient extends Thread {
+    
+    protected java.lang.String versionString = "Javer/0.1";
+    protected java.net.Socket sock = null;
+    protected java.io.PrintWriter writer = null;
+    protected java.io.BufferedReader reader = null;
+    protected java.util.Map wants = new java.util.HashMap();
+    protected java.util.Map serverevents = new java.util.HashMap();
+    protected java.util.Map fails = new java.util.HashMap();
+    protected String uid = null;
+    protected Integer lock = new Integer(0);
+    protected Pinger pingDaemon = null;
+    protected List lagEvents = null;
+    
+    protected void pushLagEvent() {
+        lagEvents.add(new Long(System.currentTimeMillis()));
+        if (pingDaemon != null)
+            pingDaemon.serverPoked();
+    }
+    
+    protected void popLagEvent() {
+        try {
+            Long then = (Long)lagEvents.remove(0);
+            long delta = System.currentTimeMillis() - then.longValue();
+            eventLagMeasured(delta);
+        } catch (IOException e) {
+            eventIOException(e);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+    
+    protected void send(String s) throws java.io.IOException {
+        synchronized (lock) {
+            if (sock == null) {
+                throw new IllegalStateException("Not connected to server");
+            }
+            writer.print(s + "\r\n");
+            writer.flush();
+            eventDebugMessage(">>> " + s);
+        }
+    }
+    
+    protected void send(String[] s) throws java.io.IOException {
+        String tmp = "";
+        int i;
+        for (i = 0; i < s.length; i++) {
+            if (i != 0) {
+                tmp += "\t";
+            }
+            tmp += s[i];
+        }
+        send(tmp);
+    }
+    
+    /** Creates a new instance of HaverClient */
+    public HaverClient() {
+        initFails();
+        initWants();
+        initServerEvents();
+    }
+
+    public void connect(String uid, java.net.Socket socket) throws 
java.io.IOException {
+        this.sock = socket;
+        this.uid = uid;
+        NonblockingOutputStream s;
+        writer = new java.io.PrintWriter(
+                new java.io.OutputStreamWriter(
+                    s = new NonblockingOutputStream(
+                        new java.io.BufferedOutputStream(
+                            sock.getOutputStream()
+                        )
+                    )
+            ));
+        s.setAutoFlush(true);
+        reader = new java.io.BufferedReader(
+            new java.io.InputStreamReader(
+                sock.getInputStream()
+            ));
+        send("HAVER\t" + versionString);
+        start();
+        lagEvents = Collections.synchronizedList(new java.util.LinkedList());
+    }
+    
+    public String getUID() {
+        return uid;
+    }
+    
+    public void connect(String uid, String hostname) throws 
java.io.IOException {
+        connect(uid, hostname, 7070);
+    }
+    
+    public void connect(String uid, String hostname, int port) throws 
java.io.IOException {
+        java.net.Socket sock = new java.net.Socket(hostname, port);
+        connect(uid, sock);
+    }
+
+    public void run() {
+        while (sock.isConnected()) {
+            try {
+                String s = reader.readLine();
+                eventDebugMessage("<<< " + s);
+                synchronized (lock) {
+                    if (reader == null)
+                        return;
+                    if (pingDaemon != null)
+                        pingDaemon.serverResponse();
+                    try {
+                        dispatchCommand(s);
+                    } catch (IOException e) {
+                        throw e;
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                        // Dazed and confused, but trying to continue...
+                    }
+                }
+            } catch (java.io.IOException e) {
+                if (!eventIOException(e)) {
+                    disconnect();
+                    return;
+                }
+            }
+        }
+    }
+
+    protected abstract class FailHandler {
+        public FailHandler() {}
+        public abstract void failure(String why, String[] args)
+            throws java.io.IOException;
+    }
+    
+    protected abstract class ServerHandler {
+        public ServerHandler() {}
+        public abstract void trigger(String[] line) throws java.io.IOException;
+    }
+
+    protected abstract class WantHandler {
+        public WantHandler() {}
+        public abstract void trigger(String[] args) throws java.io.IOException;
+    }
+
+    protected void initFails() {
+        fails.put("IDENT", new FailHandler() {
+            public void failure(String why, String[] args) throws 
java.io.IOException {
+                disconnect();
+                eventIdentFailed(why, args);
+            }
+        });
+        fails.put("PMSG", new FailHandler() {
+            public void failure(String why, String[] args) throws 
java.io.IOException {
+                eventPrivateFailed(why, args);
+            }
+        });
+        fails.put("MSG", new FailHandler() {
+            public void failure(String why, String[] args) throws 
java.io.IOException {
+                eventPublicFailed(why, args);
+                popLagEvent();
+            }
+        });
+        fails.put("LIST", new FailHandler() {
+            public void failure(String why, String[] args) throws 
java.io.IOException {
+                /* XXX report to client */
+                popLagEvent();
+            }
+        });
+        fails.put("PART", new FailHandler() {
+            public void failure(String why, String[] args) throws 
java.io.IOException {
+                /* XXX report to client */
+                popLagEvent();
+            }
+        });
+        
+    }
+    
+    protected void initWants() {
+        wants.put("IDENT", new WantHandler() {
+            public void trigger(String[] args) throws java.io.IOException {
+                eventIdenting();
+                send("IDENT\t" + uid);
+            }
+        });
+    }
+    
+    protected void initServerEvents() {
+        serverevents.put("WANT", new ServerHandler() {
+            public void trigger(String[] args) throws java.io.IOException {
+                WantHandler h = (WantHandler) wants.get(args[1]);
+                if (h == null) {
+                    send("CANT\t" + args[1]);
+                    return;
+                }
+                h.trigger(args);
+            }
+        });
+        serverevents.put("ACCEPT", new ServerHandler() {
+            public void trigger(String[] args) throws java.io.IOException {
+                eventIdentAccepted();
+            }
+        });
+        serverevents.put("MSG", new ServerHandler() {
+            public void trigger(String[] args) throws java.io.IOException {
+                String[] msgArgs = subStringArray(args, 4, args.length - 1);
+                eventMessage(args[1], args[2], args[3], msgArgs);
+                if (args[2].equals(uid))
+                    popLagEvent();
+            }
+        });
+        serverevents.put("PMSG", new ServerHandler() {
+            public void trigger(String[] args) throws java.io.IOException {
+                String[] msgArgs = subStringArray(args, 3, args.length - 1);
+                eventPrivateMessage(args[1], args[2], msgArgs);
+            }
+        });
+        serverevents.put("JOIN", new ServerHandler() {
+            public void trigger(String[] args) throws java.io.IOException {
+                if (args[2].equals(uid)) {
+                    eventChannelJoin(args[1]);
+                } else {
+                    eventChannelJoin(args[1], args[2]);
+                }
+            }
+        });
+        serverevents.put("PART", new ServerHandler() {
+            public void trigger(String[] args) throws java.io.IOException {
+                if (args[2].equals(uid)) {
+                    eventChannelPart(args[1]);
+                    popLagEvent();
+                } else {
+                    eventChannelPart(args[1], args[2]);
+                }
+            }
+        });
+        serverevents.put("QUIT", new ServerHandler() {
+            public void trigger(String[] args) throws java.io.IOException {
+                eventQuit(args[1], args[2]);
+            }
+        });
+        serverevents.put("LIST", new ServerHandler() {
+            public void trigger(String[] args) throws java.io.IOException {
+                Set s = new HashSet();
+                if (!args[2].equals("user")) {
+                    /* we only know how to list for users right now */
+                    return;
+                }
+                for (int i = 3; i < args.length; i++) {
+                    s.add(args[i]);
+                }
+                eventChannelList(args[1], s);
+                popLagEvent();
+            }
+        });
+        serverevents.put("FAIL", new ServerHandler() {
+            public void trigger(String[] args) throws java.io.IOException {
+                String cmd = args[1];
+                String why = args[2];
+                args = subStringArray(args, 3, args.length - 1);
+                eventCmdFailure(cmd, why, args);
+            }
+        });
+        serverevents.put("PING", new ServerHandler() {
+            public void trigger(String[] args) throws java.io.IOException {
+                args = (String[]) args.clone();
+                args[0] = "PONG";
+                send(args);
+            }
+        });
+        serverevents.put("OUCH", new ServerHandler() {
+            public void trigger(String[] args) throws java.io.IOException {
+                long pingtime = Long.decode(args[2]).longValue();
+                long lag = System.currentTimeMillis() - pingtime;
+                eventLagMeasured(lag);
+            }
+        });
+    }
+
+    protected void dispatchCommand(String s) throws java.io.IOException {
+        String[] parts = s.split("\t");
+        ServerHandler h = (ServerHandler) serverevents.get(parts[0]);
+        if (h != null) {
+            h.trigger(parts);
+        }
+    }
+    
+    public void join(String channel) throws java.io.IOException {
+        send("JOIN\t" + channel);
+    }
+
+    public void part(String channel) throws java.io.IOException {
+        pushLagEvent();
+        send("PART\t" + channel);
+    }
+    
+    protected void eventIdentAccepted() throws java.io.IOException {
+        /* STUB */
+    }
+
+    protected void eventDebugMessage(String s) throws java.io.IOException {
+        /* STUB */
+    }
+
+    protected void eventDisconnected() throws java.io.IOException {
+        /* STUB */
+    }
+    
+    protected void eventChannelJoin(String where) throws java.io.IOException {
+        /* STUB */
+    }
+
+    protected void eventChannelJoin(String where, String who) throws 
java.io.IOException {
+        /* STUB */
+    }
+    
+    protected void eventChannelPart(String where) throws java.io.IOException {
+        /* STUB */
+    }
+    
+    protected void eventChannelPart(String where, String who) throws 
java.io.IOException {
+        /* STUB */
+    }
+    
+    protected void eventQuit(String who, String why) throws 
java.io.IOException {
+        /* STUB */
+    }
+
+    protected void eventMessage(String where, String who, String type, 
String[] args) throws java.io.IOException {
+        if (type.equals("\"")) {
+            eventNormalMessage(where, who, args[0]);
+        } else if (type.equals(":")) {
+            eventAction(where, who, args[0]);
+        } else if (type.equals("PING?")) {
+            sendPrivateMessage(who, "PING", args);
+        }
+    }
+    
+    protected void eventNormalMessage(String where, String who, String arg) 
throws java.io.IOException {
+        /* STUB */
+    }
+    protected void eventAction(String where, String who, String arg) throws 
java.io.IOException {
+        /* STUB */
+    }
+    
+    protected void eventPrivateMessage(String who, String type, String[] args) 
throws java.io.IOException {
+        if (type.equals("\"")) {
+            eventPrivateNormalMessage(who, args[0]);
+        } else if (type.equals(":")) {
+            eventPrivateAction(who, args[0]);
+        } else if (type.equals("PING?")) {
+            sendPrivateMessage(who, "PING", args);
+        }
+    }
+
+    protected void eventPrivateNormalMessage(String who, String arg) throws 
java.io.IOException {
+        /* STUB */
+    }
+    protected void eventPrivateAction(String who, String arg) throws 
java.io.IOException {
+        /* STUB */
+    }
+    
+    protected void eventChannelList(String where, Set names) throws 
java.io.IOException {
+        /* STUB */
+    }
+    
+    protected boolean eventCmdFailure(String cmd, String why, String[] args) 
throws java.io.IOException {
+        if (fails.containsKey(cmd)) {
+            FailHandler h = (FailHandler) fails.get(cmd);
+            h.failure(why, args);
+            return true;
+        } else {
+            return false;
+        }
+    }
+    
+    protected void eventIdentFailed(String why, String[] args) throws 
java.io.IOException {
+        /* STUB */
+    }
+    
+    protected void eventPrivateFailed(String why, String[] args) throws 
java.io.IOException {
+        /* STUB */
+    }
+    
+    protected void eventPublicFailed(String why, String[] args) throws 
java.io.IOException {
+        /* STUB */
+    }
+    public static final String[] subStringArray(String[] array, int start, int 
end) {
+        if (start > end) {
+            return new String[0];
+        }
+        String[] newarray = new String[end - start + 1];
+        for (int i = 0; i <= end - start; i++) {
+            newarray[i] = array[start + i];
+        }
+        return newarray;
+    }
+
+    public void sendMessage(String where, String type, String message) throws 
IOException {
+        pushLagEvent();
+        send("MSG\t" + where + "\t" + type + "\t" + message);
+    }
+    
+    public void sendMessage(String where, String type, String[] message) 
throws IOException {
+        String s = "MSG\t" + where + "\t" + type + "\t";
+        for (int i = 0; i < message.length; i++) {
+            s = s + message[i];
+        }
+        send(s);
+    }
+    
+    public void sendNormalMessage(String where, String message) throws 
IOException {
+        sendMessage(where, "\"", message);
+    }
+    
+    public void sendAction(String where, String message) throws IOException {
+        sendMessage(where, ":", message);
+    }
+    
+    public void sendPrivateMessage(String target, String type, String message) 
throws IOException {
+        send("PMSG\t" + target + "\t" + type + "\t" + message);
+    }
+    
+    public void sendPrivateMessage(String target, String type, String[] 
message) throws IOException {
+        String s = "PMSG\t" + target + "\t" + type + "\t";
+        for (int i = 0; i < message.length; i++) {
+            s = s + message[i];
+        }
+        send(s);
+    }
+    
+    public void sendPrivateNormalMessage(String target, String message) throws 
IOException {
+        sendPrivateMessage(target, "\"", message);
+    }
+    
+    public void sendPrivateAction(String target, String message) throws 
IOException {
+        sendPrivateMessage(target, ":", message);
+    }
+    
+    protected void eventIdenting() throws java.io.IOException {
+        /* STUB */
+    }
+
+    public void listChannel(String channel) throws IOException {
+        pushLagEvent();
+        send("LIST\t" + channel + "\tuser");
+    }
+
+    public void disconnect() {
+        if (sock == null)
+            return;
+        synchronized (lock) {
+            try {
+                sock.close();
+            } catch(Exception e) {}
+            sock = null;
+            reader = null;
+            writer = null;
+            uid = null;
+            try {
+                eventDisconnected();
+            } catch(IOException e) {}
+        }
+    }
+    
+    public void pokeServer() throws IOException {
+        send("POKE\t" + System.currentTimeMillis());
+        if (pingDaemon != null)
+            pingDaemon.serverPoked();
+    }
+    
+    /**
+     * Called when an I/O exception is detected internally, or caught from
+     * within an event handler. 
+     *
+     *
+     * @param e 
+     * @return true to remain connected; false to disconnect
+     */
+    protected boolean eventIOException(IOException e) {
+        return false;
+    }
+
+    protected class Pinger extends Thread {
+
+        /**
+         * Holds value of property pingInterval.
+         */
+        private int pingInterval;
+
+        /**
+         * Holds value of property deadInterval.
+         */
+        private int deadInterval;
+
+        /**
+         * Holds value of property lastPing.
+         */
+        private long lastPing;
+        
+        private boolean halting = false;
+        
+        private long lastPong;
+        
+        public void run() {
+            while (true) {
+                long delta = 0;
+                this.interrupted(); /* we don't care if we're interrupted
+                                     * but we need the flag cleared
+                                     */
+                if (halting)
+                    return;
+                long nextPing = Long.MAX_VALUE;
+                long nextDead = Long.MAX_VALUE;
+                long nextEvt;
+                long now = System.currentTimeMillis();
+                if (pingInterval > 0)
+                    nextPing = lastPing + pingInterval;
+                else {
+                    halting = true;
+                    return;
+                }                        
+                if (deadInterval > 0)
+                    nextDead = lastPong + deadInterval;
+                
+                if (nextPing < nextDead)
+                    nextEvt = nextPing;
+                else
+                    nextEvt = nextDead;
+                /*System.out.println("lastPing=" + lastPing + " lastPong=" + 
lastPong);
+                System.out.println("nextPing = " + nextPing + " nextDead = " + 
nextDead + " nextEvt=" + nextEvt);
+                System.out.println("Now = " + now);
+                System.out.println("p="+nextPing+"\nn="+now);*/
+                if (now >= nextPing) {
+                    try {
+                        pokeServer();
+                    } catch (IOException e) {
+                        eventIOException(e);
+                    }
+                    nextPing = now + pingInterval;
+                    continue;
+                }
+                if (now >= nextDead) {
+                    try {
+                        eventServerDead();
+                    } catch (IOException e) {
+                        eventIOException(e);
+                    }
+                    lastPong = now + deadInterval;
+                    continue;
+                }
+                delta = nextEvt - now;
+                try {
+                    //System.out.println("Sleeping for " + delta +"ms");
+                    this.sleep(delta);
+                } catch(InterruptedException e) {}
+            }
+        }
+
+        /**
+         * Getter for property pingInterval.
+         * @return Value of property pingInterval.
+         */
+        public int getPingInterval() {
+
+            return this.pingInterval;
+        }
+
+        /**
+         * Setter for property pingInterval.
+         * @param pingInterval New value of property pingInterval.
+         */
+        public void setPingInterval(int pingInterval) {
+            if (pingInterval < 0)
+                throw new IllegalArgumentException("pingInterval must not be 
negative");
+            if (deadInterval > pingInterval)
+                throw new IllegalArgumentException("pingInterval should be 
greater than deadInterval");
+            synchronized (this) {
+                this.pingInterval = pingInterval;
+                if (pingInterval != 0) {
+                    this.start();
+                    this.interrupt();
+                } else {
+                    this.halt();
+                }
+            }
+        }
+
+        /**
+         * Getter for property deadInterval.
+         * @return Value of property deadInterval.
+         */
+        public int getDeadInterval() {
+
+            return this.deadInterval;
+        }
+
+        /**
+         * Setter for property deadInterval.
+         * @param deadInterval New value of property deadInterval.
+         */
+        public void setDeadInterval(int deadInterval) {
+            if (deadInterval < 0)
+                throw new IllegalArgumentException("deadInterval must not be 
negative");
+            if (deadInterval < pingInterval)
+                throw new IllegalArgumentException("pingInterval should be 
greater than deadInterval");
+            synchronized (this) {
+                this.deadInterval = deadInterval;
+                if (pingInterval != 0) {
+                    this.start();
+                    this.interrupt();
+                } else {
+                    this.halt();
+                }
+            }
+        }
+
+        /**
+         * Getter for property lastPing.
+         * @return Value of property lastPing.
+         */
+        public long getLastPing() {
+
+            return this.lastPing;
+        }
+
+        public Pinger(int pingInterval, int deadInterval) {
+            lastPing = lastPong = System.currentTimeMillis();
+            setPingInterval(pingInterval);
+            setDeadInterval(deadInterval);
+        }
+
+        public void halt() {
+            synchronized (this) {
+                halting = true;
+                if (this == Thread.currentThread())
+                    return;
+                if (!this.isAlive())
+                    return;
+                this.interrupt();
+                try {
+                    this.join();
+                } catch (InterruptedException e) {
+                    /* XXX */
+                }
+            }
+        }
+       
+        public void serverResponse() {
+            synchronized (this) {
+                lastPong = System.currentTimeMillis();
+            }
+        }
+        
+        public void serverPoked() {
+            synchronized (this) {
+                lastPing = System.currentTimeMillis();
+            }
+        }
+
+        public void start() {
+            if (this == Thread.currentThread())
+                return;
+            synchronized (this) {
+                if (this.isAlive()) {
+                    if (halting) {
+                        try {
+                            this.join();
+                        } catch (InterruptedException e) {
+                            /* XXX */
+                        }
+                    }
+                    else return;
+                }
+                super.start();
+            }
+        }
+    }
+
+    protected void eventServerDead() throws IOException {
+        /* STUB */
+    }
+    
+    protected void eventLagMeasured(long lag) throws IOException {
+        /* STUB */
+    }
+    
+    public void setPingTimers(int pingInterval, int deadInterval) {
+        if (pingDaemon == null) {
+            pingDaemon = new Pinger(pingInterval * 1000, deadInterval * 1000);
+            return;
+        }
+        pingDaemon.setDeadInterval(0); /* XXX: prevent exception when new
+                                        * deadInterval > old pingInterval
+                                        * needs to be cleaner
+                                        */
+        pingDaemon.setPingInterval(pingInterval * 1000);
+        pingDaemon.setDeadInterval(deadInterval * 1000);
+    }
+
+}


Property changes on: trunk/clients/javer/src/javer/HaverClient.java
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/clients/javer/src/javer/JaverApplet.java
===================================================================
--- trunk/clients/javer/src/javer/JaverApplet.java      2005-04-12 02:39:42 UTC 
(rev 670)
+++ trunk/clients/javer/src/javer/JaverApplet.java      2005-04-25 00:49:04 UTC 
(rev 671)
@@ -0,0 +1,157 @@
+/*
+ * JaverApplet.java
+ *
+ * Created on January 6, 2005, 11:22 PM
+ */
+
+package javer;
+
+/**
+ *
+ * @author bdonlan
+ */
+public class JaverApplet extends javax.swing.JApplet {
+    
+    Panel panel = null;
+    String[] autojoin = null;
+    
+    /** Creates a new instance of JaverApplet */
+    public JaverApplet() {
+        super();
+    }
+
+    /**
+     * Called by the browser or applet viewer to inform
+     * this applet that it should stop its execution. It is called when
+     * the Web page that contains this applet has been replaced by
+     * another page, and also just before the applet is to be destroyed.
+     * <p>
+     * A subclass of <code>Applet</code> should override this method if
+     * it has any operation that it wants to perform each time the Web
+     * page containing it is no longer visible. For example, an applet
+     * with animation might want to use the <code>start</code> method to
+     * resume animation, and the <code>stop</code> method to suspend the
+     * animation.
+     * <p>
+     * The implementation of this method provided by the
+     * <code>Applet</code> class does nothing.
+     * 
+     * @see     java.applet.Applet#destroy()
+     * @see     java.applet.Applet#init()
+     */
+    public void stop() {
+        /* appletviewer calls this when we switch desktops.
+         * appletviewer sucks.
+         */
+        panel.do_disconnect();
+        super.stop();
+    }
+
+    /**
+     * Called by the browser or applet viewer to inform
+     * this applet that it has been loaded into the system. It is always
+     * called before the first time that the <code>start</code> method is
+     * called.
+     * <p>
+     * A subclass of <code>Applet</code> should override this method if
+     * it has initialization to perform. For example, an applet with
+     * threads would use the <code>init</code> method to create the
+     * threads and the <code>destroy</code> method to kill them.
+     * <p>
+     * The implementation of this method provided by the
+     * <code>Applet</code> class does nothing.
+     * 
+     * @see     java.applet.Applet#destroy()
+     * @see     java.applet.Applet#start()
+     * @see     java.applet.Applet#stop()
+     */
+    public void init() {
+        String host;
+        int port;
+        String autojoin_str;
+        super.init();
+        System.out.println("init");
+        host = this.getParameter("hostname");
+        port = Integer.decode(this.getParameter("port")).intValue();
+        autojoin_str = this.getParameter("autojoin");
+        System.out.println("autojoin = " + autojoin_str);
+        if (autojoin_str != null) {
+            autojoin = autojoin_str.split("[, ]+");
+            System.out.println("count = " + autojoin.length);
+        } else {
+            autojoin = null;
+        }
+        panel = new Panel(this, host, port);
+        getContentPane().setLayout(new java.awt.GridLayout(1,0));
+        getContentPane().add(panel);
+    }
+
+    /**
+     * Called by the browser or applet viewer to inform
+     * this applet that it is being reclaimed and that it should destroy
+     * any resources that it has allocated. The <code>stop</code> method
+     * will always be called before <code>destroy</code>.
+     * <p>
+     * A subclass of <code>Applet</code> should override this method if
+     * it has any operation that it wants to perform before it is
+     * destroyed. For example, an applet with threads would use the
+     * <code>init</code> method to create the threads and the
+     * <code>destroy</code> method to kill them.
+     * <p>
+     * The implementation of this method provided by the
+     * <code>Applet</code> class does nothing.
+     * 
+     * @see     java.applet.Applet#init()
+     * @see     java.applet.Applet#start()
+     * @see     java.applet.Applet#stop()
+     */
+    public void destroy() {
+        panel.do_disconnect();
+        super.destroy();
+    }
+
+    protected final class Panel extends JaverUIPanel {
+        JaverApplet applet;
+        public Panel(
+                JaverApplet a,
+                String hostname,
+                int port) {
+            super(hostname, port);
+            System.out.println("subclass panel init");
+            this.applet = a;
+        }
+
+        public boolean processLine(String query) {
+
+            boolean retValue;
+
+            retValue = super.processLine(query);
+            return retValue;
+        }
+
+        protected Client spawnClient() {
+            return new SubClient(this);
+        }
+
+        protected final class SubClient extends javer.JaverUIPanel.Client {
+            public SubClient(JaverUIPanel panel) {
+                super(panel);
+            }
+            
+            protected void eventIdentAccepted() throws java.io.IOException {
+                super.eventIdentAccepted();
+                System.out.println("check autojoin");
+                if (autojoin != null) {
+                    int i;
+                    for (i = 0; i < autojoin.length; i++) {
+                        putServer("Auto-joining " + autojoin[i]);
+                        cli.join(autojoin[i]);
+                    }
+                }
+            }
+        }
+
+    }
+
+    
+}


Property changes on: trunk/clients/javer/src/javer/JaverApplet.java
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/clients/javer/src/javer/JaverUI.form
===================================================================
--- trunk/clients/javer/src/javer/JaverUI.form  2005-04-12 02:39:42 UTC (rev 
670)
+++ trunk/clients/javer/src/javer/JaverUI.form  2005-04-25 00:49:04 UTC (rev 
671)
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.0" type="org.netbeans.modules.form.forminfo.FrameFormInfo">
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+  </SyntheticProperties>
+  <Events>
+    <EventHandler event="windowClosing" 
listener="java.awt.event.WindowListener" 
parameters="java.awt.event.WindowEvent" handler="exitForm"/>
+  </Events>
+
+  <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout"/>
+</Form>

Added: trunk/clients/javer/src/javer/JaverUI.java
===================================================================
--- trunk/clients/javer/src/javer/JaverUI.java  2005-04-12 02:39:42 UTC (rev 
670)
+++ trunk/clients/javer/src/javer/JaverUI.java  2005-04-25 00:49:04 UTC (rev 
671)
@@ -0,0 +1,85 @@
+/*
+ * JaverUI.java
+ *
+ * Created on January 5, 2005, 9:27 PM
+ */
+
+package javer;
+
+/**
+ *
+ * @author  bdonlan
+ */
+public class JaverUI extends java.awt.Frame {
+    
+    /** Creates new form JaverUI */
+    public JaverUI() {
+        addWindowListener(new CloseListener());
+        add(new JaverUIPanel("odin.haverdev.org", 7070));
+        pack();
+    }
+    
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    private void initComponents() {//GEN-BEGIN:initComponents
+
+        setLayout(new javax.swing.BoxLayout(this, 
javax.swing.BoxLayout.X_AXIS));
+
+        addWindowListener(new java.awt.event.WindowAdapter() {
+            public void windowClosing(java.awt.event.WindowEvent evt) {
+                exitForm(evt);
+            }
+        });
+
+        pack();
+    }//GEN-END:initComponents
+    
+    /** Exit the Application */
+    private void exitForm(java.awt.event.WindowEvent evt) 
{//GEN-FIRST:event_exitForm
+        System.exit(0);
+    }//GEN-LAST:event_exitForm
+    
+    /**
+     * @param args the command line arguments
+     */
+    public static void main(String args[]) {
+        java.awt.EventQueue.invokeLater(new Runnable() {
+            public void run() {
+                new JaverUI().setVisible(true);
+            }
+        });
+    }
+
+    private final class CloseListener implements java.awt.event.WindowListener 
{
+        public void windowOpened(java.awt.event.WindowEvent e) {
+        }
+
+        public void windowIconified(java.awt.event.WindowEvent e) {
+        }
+
+        public void windowDeiconified(java.awt.event.WindowEvent e) {
+        }
+
+        public void windowDeactivated(java.awt.event.WindowEvent e) {
+        }
+
+        public void windowClosing(java.awt.event.WindowEvent e) {
+            System.exit(0);
+        }
+
+        public void windowClosed(java.awt.event.WindowEvent e) {
+        }
+
+        public void windowActivated(java.awt.event.WindowEvent e) {
+        }
+    }
+
+    
+    
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    // End of variables declaration//GEN-END:variables
+    
+}


Property changes on: trunk/clients/javer/src/javer/JaverUI.java
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/clients/javer/src/javer/JaverUIPanel.form
===================================================================
--- trunk/clients/javer/src/javer/JaverUIPanel.form     2005-04-12 02:39:42 UTC 
(rev 670)
+++ trunk/clients/javer/src/javer/JaverUIPanel.form     2005-04-25 00:49:04 UTC 
(rev 671)
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.0" type="org.netbeans.modules.form.forminfo.PanelFormInfo">
+
+  <Layout 
class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
+  <SubComponents>
+    <Container class="javax.swing.JTabbedPane" name="jTabbedPane1">
+      <Properties>
+        <Property name="tabLayoutPolicy" type="int" value="1"/>
+        <Property name="tabPlacement" type="int" value="3"/>
+      </Properties>
+      <Constraints>
+        <Constraint 
layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" 
value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+          <BorderConstraints direction="Center"/>
+        </Constraint>
+      </Constraints>
+
+      <Layout 
class="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout"/>
+    </Container>
+    <Container class="javax.swing.JPanel" name="jPanel2">
+      <AuxValues>
+        <AuxValue name="JavaCodeGenerator_VariableModifier" 
type="java.lang.Integer" value="0"/>
+        <AuxValue name="JavaCodeGenerator_VariableLocal" 
type="java.lang.Boolean" value="true"/>
+      </AuxValues>
+      <Constraints>
+        <Constraint 
layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" 
value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+          <BorderConstraints direction="South"/>
+        </Constraint>
+      </Constraints>
+
+      <Layout 
class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout">
+        <Property name="axis" type="int" value="1"/>
+      </Layout>
+      <SubComponents>
+        <Component class="javax.swing.JTextField" name="input">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="jTextField1"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" 
listener="java.awt.event.ActionListener" 
parameters="java.awt.event.ActionEvent" handler="inputActionPerformed"/>
+            <EventHandler event="keyTyped" 
listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" 
handler="inputKeyTyped"/>
+          </Events>
+        </Component>
+        <Container class="javax.swing.JPanel" name="jPanel1">
+          <AuxValues>
+            <AuxValue name="JavaCodeGenerator_VariableModifier" 
type="java.lang.Integer" value="0"/>
+            <AuxValue name="JavaCodeGenerator_VariableLocal" 
type="java.lang.Boolean" value="true"/>
+          </AuxValues>
+
+          <Layout 
class="org.netbeans.modules.form.compat2.layouts.DesignGridLayout">
+            <Property name="columns" type="int" value="2"/>
+            <Property name="rows" type="int" value="1"/>
+          </Layout>
+          <SubComponents>
+            <Component class="javax.swing.JLabel" name="status">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="NOT 
CONNECTED"/>
+                <Property name="minimumSize" type="java.awt.Dimension" 
editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[300, 300]"/>
+                </Property>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="lagLabel">
+              <Properties>
+                <Property name="horizontalAlignment" type="int" value="4"/>
+              </Properties>
+            </Component>
+          </SubComponents>
+        </Container>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>

Added: trunk/clients/javer/src/javer/JaverUIPanel.java
===================================================================
--- trunk/clients/javer/src/javer/JaverUIPanel.java     2005-04-12 02:39:42 UTC 
(rev 670)
+++ trunk/clients/javer/src/javer/JaverUIPanel.java     2005-04-25 00:49:04 UTC 
(rev 671)
@@ -0,0 +1,587 @@
+/*
+ * JaverUIPanel.java
+ *
+ * Created on January 5, 2005, 9:31 PM
+ */
+
+package javer;
+import java.io.*;
+import java.util.*;
+
+/**
+ *
+ * @author  bdonlan
+ */
+public class JaverUIPanel extends java.awt.Panel {
+    
+    protected Client cli = null;
+    protected String host = null;
+    protected String uid = null;
+    protected int port = 7070;
+    protected Map commands = new HashMap();
+    protected Map tabs = new HashMap();
+    protected Map channelTabs = new HashMap();
+    protected Map userTabs = new HashMap();
+    protected Map tabToPair = new HashMap();
+    protected TabPair serverTabPair = new TabPair();
+    protected SimpleTextTab serverTab = new SimpleTextTab();
+    
+    protected Client spawnClient() {
+        return new Client(this);
+    }
+    
+    /** Creates new form JaverUIPanel */
+    public JaverUIPanel(String hostname, int port) {
+        this.host = hostname;
+        this.port = port;
+        initCommands();
+        initComponents();
+        serverTabPair.tab = serverTab;
+        serverTabPair.title = "Server";
+        addTab(serverTabPair);
+        do_disconnect();
+    }
+
+    protected abstract class CommandHandler {
+        public CommandHandler () {}
+        abstract boolean trigger(String arg) throws IOException;
+    }
+    
+    public final class TabPair {
+        java.awt.Component tab;
+        int index;
+        String title;
+    }
+    
+    protected void addTab(TabPair p) {
+        p.index = jTabbedPane1.getTabCount();
+        jTabbedPane1.addTab(p.title, p.tab);
+        jTabbedPane1.setSelectedIndex(p.index);
+        tabs.put(p.title, p);
+        tabToPair.put(p.tab, p);
+    }
+    
+    protected TabPair findTab(String tag) {
+        TabPair t = (TabPair) tabs.get(tag);
+        return t;
+    }
+    
+    protected void killTab(TabPair p) {
+        Iterator it;
+        if (p == null || !tabs.containsValue(p))
+            return;
+        jTabbedPane1.removeTabAt(p.index);
+        tabs.remove(p.title);
+        it = tabs.values().iterator();
+        while (it.hasNext()) {
+            TabPair x = (TabPair) it.next();
+            if (x.index > p.index) {
+                x.index--;
+            }
+        }
+        try {
+            channelTabs.remove(((ChannelTab)p.tab).getChannel());
+        } catch (ClassCastException e) {}
+        try {
+            userTabs.remove(((UserQueryTab)p.tab).getUID());
+        } catch (ClassCastException e) {}   
+        tabToPair.remove(p.tab);
+    }
+    
+    protected void killTab(java.awt.Component t) {
+        TabPair p = (TabPair)tabToPair.get(t);
+        if (p.index == 0)
+            return;
+        killTab(p);
+    }
+    
+    protected UserQueryTab getQuery(String who) {
+        TabPair p = (TabPair)userTabs.get(who);
+        if (p != null)
+            return (UserQueryTab)p.tab;
+        p = new TabPair();
+        p.title = "Query: " + who;
+        p.tab = new UserQueryTab(cli, who);
+        addTab(p);
+        userTabs.put(who, p);
+        return (UserQueryTab)p.tab;
+    }
+    
+    public class Client extends HaverClient {
+        JaverUIPanel panel;
+        
+        public Client(JaverUIPanel panel) {
+            this.panel = panel;
+        }
+        
+        protected void eventDebugMessage(String s) throws java.io.IOException {
+            System.out.println(s);
+            super.eventDebugMessage(s);
+        }
+
+        protected void eventIdentAccepted() throws java.io.IOException {
+            putServer("Logged in successfully.");
+            status.setText("Connected.");
+            super.eventIdentAccepted();
+            setPingTimers(60, 180);
+            pokeServer();
+        }
+
+        protected void eventIdenting() throws java.io.IOException {
+            putServer("Logging in...");
+            super.eventIdenting();
+        }
+
+        protected void eventChannelPart(String where) throws 
java.io.IOException {
+            killTab((TabPair)channelTabs.get(where));
+            channelTabs.remove(where);
+            super.eventChannelPart(where);
+        }
+
+        protected void eventChannelJoin(String where) throws 
java.io.IOException {
+            TabPair t = (TabPair) channelTabs.get(where);
+            if (t == null) {
+                t = new TabPair();
+                t.tab = new ChannelTab(panel, cli, where);
+                t.title = "Channel: " + where;
+                addTab(t);
+                channelTabs.put(where, t);
+            }
+            QueryTab qt = (QueryTab) t.tab;
+            qt.putText("--- Joined " + where);
+            cli.listChannel(where);
+            super.eventChannelJoin(where);
+        }
+
+        protected void eventMessage(String where, String who, String type, 
String[] args) throws java.io.IOException {
+
+            super.eventMessage(where, who, type, args);
+        }
+
+        protected void eventChannelList(String where, Set names) throws 
java.io.IOException {
+            ChannelTab tab;
+            TabPair t = (TabPair) channelTabs.get(where);
+            if (t == null)
+                return;
+            tab = (ChannelTab) t.tab;
+            tab.setUsers(names);
+            super.eventChannelList(where, names);
+        }
+
+        protected void eventQuit(String who, String why) throws 
java.io.IOException {
+            Iterator it = tabs.values().iterator();
+            while (it.hasNext()) {
+                ChannelTab tab;
+                try {
+                    tab = (ChannelTab) ((TabPair)it.next()).tab;
+                } catch (ClassCastException e) {
+                    continue;
+                }
+                if (!tab.hasUser(who))
+                    continue;
+                tab.putText("--- " + who + " has quit (" + why + ")");
+                tab.delUser(who);
+            }
+            super.eventQuit(who, why);
+        }
+
+        protected void eventNormalMessage(String where, String who, String 
arg) throws java.io.IOException {
+            TextTab tab;
+            TabPair t = (TabPair) channelTabs.get(where);
+            if (t == null)
+                return;
+            tab = (TextTab) t.tab;
+            tab.putText("<" + who + "> " + arg);
+            super.eventNormalMessage(where, who, arg);
+        }
+
+        protected void eventChannelPart(String where, String who) throws 
java.io.IOException {
+            ChannelTab tab;
+            TabPair t = (TabPair) channelTabs.get(where);
+            if (t == null)
+                return;
+            tab = (ChannelTab) t.tab;
+            tab.delUser(who);
+            tab.putText("--- " + who + " has left.");
+            super.eventChannelPart(where, who);
+        }
+
+        protected void eventChannelJoin(String where, String who) throws 
java.io.IOException {
+            ChannelTab tab;
+            TabPair t = (TabPair) channelTabs.get(where);
+            if (t == null)
+                return;
+            tab = (ChannelTab) t.tab;
+            tab.addUser(who);
+            tab.putText("--- " + who + " has joined.");
+            super.eventChannelJoin(where, who);
+        }
+
+        protected void eventAction(String where, String who, String arg) 
throws java.io.IOException {
+            TextTab tab;
+            TabPair t = (TabPair) channelTabs.get(where);
+            if (t == null)
+                return;
+            tab = (TextTab) t.tab;
+            tab.putText("* " + who + " " + arg);
+            super.eventAction(where, who, arg);
+        }
+
+        protected void eventPrivateMessage(String who, String type, String[] 
args) throws java.io.IOException {
+
+            super.eventPrivateMessage(who, type, args);
+        }
+
+        protected void eventPrivateNormalMessage(String who, String arg) 
throws java.io.IOException {
+            getQuery(who).putText("<" + who + "> " + arg);
+            super.eventPrivateNormalMessage(who, arg);
+        }
+
+        protected void eventPrivateAction(String who, String arg) throws 
java.io.IOException {
+            getQuery(who).putText("* " + who + " " + arg);
+            super.eventPrivateAction(who, arg);
+        }
+
+        protected boolean eventIOException(IOException e) {
+            putServer("I/O exception: " + e.getLocalizedMessage());
+            return false;
+        }
+
+        protected void eventPublicFailed(String why, String[] args) throws 
IOException {
+            TextTab tab;
+            if (channelTabs.containsKey(args[0])) {
+                TabPair p = (TabPair) channelTabs.get(args[0]);
+                tab = (TextTab) p.tab;
+            } else {
+                tab = serverTab;
+            }
+            tab.putText("Public message failed: " + why + ", args: " + args);
+            super.eventPublicFailed(why, args);
+        }
+
+        protected void eventPrivateFailed(String why, String[] args) throws 
IOException {
+            TextTab tab;
+            if (userTabs.containsKey(args[0])) {
+                tab = getQuery(args[0]);
+            } else {
+                tab = serverTab;
+            }
+            tab.putText("Private message failed: " + why + ", args: " + args);
+            super.eventPrivateFailed(why, args);
+        }
+
+        protected void eventIdentFailed(String why, String[] args) throws 
IOException {
+            putServer("Login failed: " + why + ", args: " + args);
+            super.eventIdentFailed(why, args);
+            disconnect();
+        }
+
+        protected boolean eventCmdFailure(String cmd, String why, String[] 
args) throws IOException {
+
+            boolean retValue;
+            
+            retValue = super.eventCmdFailure(cmd, why, args);
+            if (retValue)
+                return retValue;
+            
+            putServer("Unknown failure event. Command: " + cmd +
+                      ", reason: " + why + ", args: " + args);
+            
+            return false;
+        }
+
+        protected void eventDisconnected() throws IOException {
+            do_disconnect();
+            super.eventDisconnected();
+        }
+
+        protected void eventServerDead() throws IOException {
+            putServer("Server seems to be dead, killing connection.");
+            do_disconnect();
+            super.eventServerDead();
+        }
+
+        protected void eventLagMeasured(long lag) throws IOException {
+            double dlag = lag / 1000.0;
+            lagLabel.setText("Current lag: " + dlag);
+            super.eventLagMeasured(lag);
+        }
+
+    }
+
+
+    public void activateQuery(String who) {
+        UserQueryTab t = getQuery(who);
+        jTabbedPane1.setSelectedComponent(t);
+    }
+    
+    public void do_disconnect() {
+        /* XXX: split this into disconnect-performing and after-disconnect
+         * functions
+         */
+        Set pairs = new java.util.HashSet(tabs.values());
+        Iterator it = pairs.iterator();
+        while (it.hasNext()) {
+            TabPair p = (TabPair) it.next();
+            if (p != serverTabPair) {
+                killTab(p);
+            }
+        }
+        if (cli != null) {
+            cli.disconnect();
+            cli = null;
+        }
+        serverTab.putText(
+        "Welcome to haver!\n\n" +
+        "Enter your UID to begin."
+        );
+        status.setText("NOT CONNECTED");
+        lagLabel.setText("");
+    }
+    
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    private void initComponents() {//GEN-BEGIN:initComponents
+        javax.swing.JPanel jPanel1;
+        javax.swing.JPanel jPanel2;
+
+        jTabbedPane1 = new javax.swing.JTabbedPane();
+        jPanel2 = new javax.swing.JPanel();
+        input = new javax.swing.JTextField();
+        jPanel1 = new javax.swing.JPanel();
+        status = new javax.swing.JLabel();
+        lagLabel = new javax.swing.JLabel();
+
+        setLayout(new java.awt.BorderLayout());
+
+        
jTabbedPane1.setTabLayoutPolicy(javax.swing.JTabbedPane.SCROLL_TAB_LAYOUT);
+        jTabbedPane1.setTabPlacement(javax.swing.JTabbedPane.BOTTOM);
+        add(jTabbedPane1, java.awt.BorderLayout.CENTER);
+
+        jPanel2.setLayout(new javax.swing.BoxLayout(jPanel2, 
javax.swing.BoxLayout.Y_AXIS));
+
+        input.setText("jTextField1");
+        input.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                inputActionPerformed(evt);
+            }
+        });
+        input.addKeyListener(new java.awt.event.KeyAdapter() {
+            public void keyTyped(java.awt.event.KeyEvent evt) {
+                inputKeyTyped(evt);
+            }
+        });
+
+        jPanel2.add(input);
+
+        jPanel1.setLayout(new java.awt.GridLayout(1, 2));
+
+        status.setText("NOT CONNECTED");
+        status.setMinimumSize(new java.awt.Dimension(300, 300));
+        jPanel1.add(status);
+
+        lagLabel.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
+        jPanel1.add(lagLabel);
+
+        jPanel2.add(jPanel1);
+
+        add(jPanel2, java.awt.BorderLayout.SOUTH);
+
+    }//GEN-END:initComponents
+
+    private void inputKeyTyped(java.awt.event.KeyEvent evt) 
{//GEN-FIRST:event_inputKeyTyped
+        if (evt.getKeyChar() != '\n')
+            return;
+        if (cli == null) {
+            putServer("Connecting...");
+            status.setText("Connecting...");
+            cli = spawnClient();
+            try {
+                cli.connect(uid = input.getText(), host, port);
+                input.setText("");
+                putServer("Connected...");
+                return;
+            } catch (IOException e) {
+                putServer("Failed: " + e.getLocalizedMessage());
+                status.setText("NOT CONNECTED");
+                return;
+            }
+        }
+        String query = input.getText();
+        input.setText("");
+        if (!processLine(query)) {
+            try {
+                TextTab tab = (TextTab) jTabbedPane1.getSelectedComponent();
+                tab.putText("--- Erroneous command: " + query);
+            } catch (ClassCastException e) {
+                putServer("--- Erroneous command: " + query);
+            }
+        }
+    }//GEN-LAST:event_inputKeyTyped
+
+    private void inputActionPerformed(java.awt.event.ActionEvent evt) 
{//GEN-FIRST:event_inputActionPerformed
+        // TODO add your handling code here:
+    }//GEN-LAST:event_inputActionPerformed
+    
+    protected void putServer(String s) {
+        serverTab.putText(s);
+    }
+    
+    protected void initCommands() {
+        commands.put("me", new CommandHandler() {
+            boolean trigger(String arg) throws IOException {
+                try {
+                    QueryTab q = (QueryTab) 
jTabbedPane1.getSelectedComponent();
+                    q.sendAction(arg);
+                    return true;
+                } catch(ClassCastException e) {
+                    return false;
+                }
+            }
+        });
+        commands.put("join", new CommandHandler() {
+            boolean trigger(String arg) throws IOException {
+                if (channelTabs.containsKey(arg))
+                    return true;
+                cli.join(arg);
+                return true;
+            }
+        });
+        commands.put("part", new CommandHandler() {
+            boolean trigger(String arg) throws IOException {
+                if (arg == "") {
+                    try {
+                        ChannelTab t;
+                        t = (ChannelTab) jTabbedPane1.getSelectedComponent();
+                        arg = t.getChannel();
+                    } catch (ClassCastException e) {
+                        return false;
+                    }
+                }
+                if (!channelTabs.containsKey(arg))
+                    return true;
+                cli.part(arg);
+                return true;
+            }
+        });
+        commands.put("quit", new CommandHandler() {
+            boolean trigger(String arg) {
+                System.exit(0);
+                return false;
+            }
+        });
+        commands.put("query", new CommandHandler() {
+            boolean trigger(String arg) {
+                UserQueryTab tab = getQuery(arg);
+                jTabbedPane1.setSelectedComponent(tab);
+                return true;
+            }
+        });
+        commands.put("msg", new CommandHandler() {
+            boolean trigger(String arg) throws IOException {
+                UserQueryTab tab;
+                String who, what;
+                int space = arg.indexOf(' ');
+                if (space == -1)
+                    return false;
+                who = arg.substring(0, space);
+                what = arg.substring(space + 1);
+                
+                tab = getQuery(who);
+                tab.sendText(what);
+                return true;
+            }
+        });
+        commands.put("say", new CommandHandler() {
+            boolean trigger(String arg) throws IOException {
+                try {
+                    QueryTab q = (QueryTab) 
jTabbedPane1.getSelectedComponent();
+                    q.sendText(arg);
+                    return true;
+                } catch(ClassCastException e) {
+                    return false;
+                }
+            }
+        });
+        commands.put("", commands.get("say"));
+        commands.put("act", new CommandHandler() {
+            boolean trigger(String arg) throws IOException {
+                UserQueryTab tab;
+                String who, what;
+                int space = arg.indexOf(' ');
+                if (space == -1)
+                    return false;
+                who = arg.substring(0, space);
+                what = arg.substring(space + 1);
+                
+                tab = getQuery(who);
+                tab.sendAction(what);
+                return true;
+            }
+        });
+        commands.put("close", new CommandHandler() {
+            boolean trigger(String arg) throws IOException {
+                try {
+                    ChannelTab q = (ChannelTab) 
jTabbedPane1.getSelectedComponent();
+                    cli.part(q.getChannel());
+                    return true;
+                } catch (ClassCastException e) {}
+                killTab(jTabbedPane1.getSelectedComponent());
+                return true;
+            }
+        });
+    }
+    
+    public boolean processLine(String query) {
+        try {
+            if (query.charAt(0) == '/' || query.charAt(0) == '.') {
+                String command, arg;
+                int endcommand = query.indexOf(' ');
+                if (endcommand == -1) {
+                    command = query.substring(1);
+                    arg = "";
+                } else {
+                    command = query.substring(1, endcommand);
+                    arg = query.substring(endcommand + 1);
+                }
+                System.out.println("COMMAND: " + command + " ARG: " + arg);
+                if (!commands.containsKey(command.toLowerCase()))
+                    return false;
+                System.out.println("triggering\n");
+                return ((CommandHandler)commands.get(command)).trigger(arg);
+            }
+            try {
+                QueryTab tab = (QueryTab) jTabbedPane1.getSelectedComponent();
+                int i;
+                if (query.indexOf(';') != 0) {
+                    tab.sendText(query);
+                    return true;
+                }
+                for (i = 1; i < query.length(); i++) {
+                    if (query.charAt(i) != ' ')
+                        break;
+                }
+                query = query.substring(i);
+                tab.sendAction(query);
+                return true;
+            } catch (java.lang.ClassCastException ex) {
+                return true;
+            }
+        } catch (IOException e) {
+            cli.eventIOException(e);
+            do_disconnect();
+        }
+        return false;
+    }
+    
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JTextField input;
+    private javax.swing.JTabbedPane jTabbedPane1;
+    private javax.swing.JLabel lagLabel;
+    private javax.swing.JLabel status;
+    // End of variables declaration//GEN-END:variables
+    
+}


Property changes on: trunk/clients/javer/src/javer/JaverUIPanel.java
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/clients/javer/src/javer/NonblockingOutputStream.java
===================================================================
--- trunk/clients/javer/src/javer/NonblockingOutputStream.java  2005-04-12 
02:39:42 UTC (rev 670)
+++ trunk/clients/javer/src/javer/NonblockingOutputStream.java  2005-04-25 
00:49:04 UTC (rev 671)
@@ -0,0 +1,201 @@
+/*
+ * NonblockingOutputStream.java
+ *
+ * Created on January 10, 2005, 1:53 PM
+ */
+
+package javer;
+import java.io.*;
+import java.util.*;
+
+/**
+ *
+ * @author bdonlan
+ */
+public class NonblockingOutputStream extends java.io.FilterOutputStream
+    implements Runnable {
+    
+    protected Vector preflush, pending;
+    protected long active_len;
+    protected long pending_len;
+    protected long preflush_len;
+    protected boolean flushing, closing, autoflush;
+    protected IOException pending_exception = null;
+    protected Thread th;
+    protected OutputStream out;
+    
+    public NonblockingOutputStream(OutputStream out) {
+        super(out);
+        this.out = out;
+        flushing = closing = autoflush = false;
+        preflush = null;
+        pending = new Vector();
+        active_len = pending_len = preflush_len = 0;
+        th = new Thread(this);
+        th.start();
+    }
+    
+    public void run() {
+        if (Thread.currentThread() != th)
+            throw new IllegalStateException("run() must be executed from 
within " +
+                    "NonblockingOutputStream.th");
+        try {
+            while (true) {
+                Vector work;
+                boolean flushafter = false;
+                synchronized (th) {
+                    active_len = 0;
+                    if (flushing) {
+                        flushafter = true;
+                        flushing = false;
+
+                    }
+                    work = pending;
+                    pending = new Vector();
+                    active_len = pending_len;
+                    pending_len = 0;
+                    if (flushing) {
+                        flushafter = true;
+                        flushing = false;
+                        pending = preflush;
+                        pending_len = preflush_len;
+                        preflush_len = 0;
+                        preflush = null;
+                    } else if (active_len == 0) {
+                        //System.out.println("active_len == 0, blocking");
+                        if (autoflush) {
+                            out.flush();
+                        }
+                        if (closing) {
+                            out.close();
+                            return;
+                        }
+                        try {
+                            th.wait();
+                        } catch (InterruptedException e) {}
+                        //System.out.println("done blocking");
+                        continue;
+                    }
+                }
+                Iterator it;
+                //System.out.println("writing, active_len = " + active_len);
+                it = work.iterator();
+                while (it.hasNext()) {
+                    byte[] b = (byte[]) it.next();
+                    out.write(b);
+                }
+                if (flushafter)
+                    out.flush();
+            }
+        } catch (IOException e) {
+            synchronized(th) {
+                pending_exception = e;
+            }
+        }
+    }
+
+    public void write(byte[] b) throws IOException {
+        if (b.length == 0)
+            return;
+        //System.out.println("write called");
+        synchronized(th) {
+            if (pending_exception != null)
+                throw pending_exception;
+            if (flushing) {
+                preflush.add(b);
+                preflush_len += b.length;
+            } else {
+                pending.add(b);
+                pending_len += b.length;
+                th.notifyAll();
+            }
+            dump();
+        }
+    }
+
+    public void close() throws IOException {
+        synchronized(th) {
+            if (pending_exception != null)
+                throw pending_exception;
+            closing = true;
+            th.notifyAll();
+            dump();
+        }
+    }
+
+    public void flush() throws IOException {
+        synchronized(th) {
+            if (pending_exception != null)
+                throw pending_exception;
+            /* if we'return autoflushing, eventually a buffer will fill 
somewhere
+             * and cause a flush, or else autoFlush will kick in. So the manual
+             * flush() is redundant
+             */
+            if (autoflush)
+                return;
+            flushing = true;
+            preflush = new Vector();
+            preflush_len = 0;
+            th.notifyAll();
+            dump();
+        }
+    }
+    
+    /**
+     * Getter for property autoFlush.
+     * @return Value of property autoFlush.
+     */
+    public boolean isAutoFlush() {
+        return autoflush;
+    }
+
+    /**
+     * Setter for property autoFlush.
+     * @param autoFlush New value of property autoFlush.
+     */
+    public void setAutoFlush(boolean autoFlush) {
+        synchronized (th) {
+            autoflush = true;
+            th.notify();
+        }
+    }
+    
+    protected void dump() {
+        /*
+        System.out.println("=== NonblockingOutputStream status:");
+        synchronized(th) {
+            System.out.println("Flags: flushing="+flushing+" 
closing="+closing+" autoflush="+autoflush);
+            System.out.println("Buffer levels: preflush_len=" + preflush_len + 
" pending_len="+pending_len);
+            System.out.print("Vector element counts: ");
+            if (preflush == null) {
+                System.out.print("preflush={null}" );
+            } else {
+                System.out.print("preflush=" + preflush.size());
+            }
+            System.out.println("pending=" + pending.size());
+        }
+        System.out.println("Stack trace:");
+        new Exception().printStackTrace();
+         */
+    }
+
+    public void write(int b) throws IOException {
+        byte[] a = new byte[1];
+        a[0] = (byte) b;
+        write(a);
+    }
+
+    public void write(byte[] b, int off, int len) throws IOException {
+        if (len == 0)
+            return;
+        if (len < 0)
+            throw new IllegalArgumentException("len must not be negative");
+        if (off + len > b.length)
+            throw new IllegalArgumentException("off + len > b.length");
+        byte[] buffer = new byte[len];
+        int i;
+        for (i = 0; i < len; i++)
+            buffer[i] = b[off + i];
+        write(buffer);
+    }
+}


Property changes on: trunk/clients/javer/src/javer/NonblockingOutputStream.java
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/clients/javer/src/javer/QueryTab.java
===================================================================
--- trunk/clients/javer/src/javer/QueryTab.java 2005-04-12 02:39:42 UTC (rev 
670)
+++ trunk/clients/javer/src/javer/QueryTab.java 2005-04-25 00:49:04 UTC (rev 
671)
@@ -0,0 +1,16 @@
+/*
+ * QueryTab.java
+ *
+ * Created on January 6, 2005, 12:43 AM
+ */
+
+package javer;
+
+/**
+ *
+ * @author  bdonlan
+ */
+public interface QueryTab extends TextTab {
+    public void sendText(String s) throws java.io.IOException;
+    public void sendAction(String s) throws java.io.IOException;
+}


Property changes on: trunk/clients/javer/src/javer/QueryTab.java
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/clients/javer/src/javer/SimpleTextTab.form
===================================================================
--- trunk/clients/javer/src/javer/SimpleTextTab.form    2005-04-12 02:39:42 UTC 
(rev 670)
+++ trunk/clients/javer/src/javer/SimpleTextTab.form    2005-04-25 00:49:04 UTC 
(rev 671)
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.0" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
+
+  <Layout 
class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
+  <SubComponents>
+    <Container class="javax.swing.JScrollPane" name="jScrollPane1">
+      <Constraints>
+        <Constraint 
layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" 
value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+          <BorderConstraints direction="Center"/>
+        </Constraint>
+      </Constraints>
+
+      <Layout 
class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+      <SubComponents>
+        <Component class="javax.swing.JTextArea" name="textField">
+          <Properties>
+            <Property name="editable" type="boolean" value="false"/>
+            <Property name="lineWrap" type="boolean" value="true"/>
+          </Properties>
+        </Component>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>

Added: trunk/clients/javer/src/javer/SimpleTextTab.java
===================================================================
--- trunk/clients/javer/src/javer/SimpleTextTab.java    2005-04-12 02:39:42 UTC 
(rev 670)
+++ trunk/clients/javer/src/javer/SimpleTextTab.java    2005-04-25 00:49:04 UTC 
(rev 671)
@@ -0,0 +1,54 @@
+/*
+ * SimpleTextTab.java
+ *
+ * Created on January 6, 2005, 2:26 PM
+ */
+
+package javer;
+
+/**
+ *
+ * @author  bdonlan
+ */
+public class SimpleTextTab extends javax.swing.JPanel implements TextTab {
+    
+    /** Creates new form SimpleTextTab */
+    protected SimpleTextTab() {
+        initComponents();
+    }
+    
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    private void initComponents() {//GEN-BEGIN:initComponents
+        jScrollPane1 = new javax.swing.JScrollPane();
+        textField = new javax.swing.JTextArea();
+
+        setLayout(new java.awt.BorderLayout());
+
+        textField.setEditable(false);
+        textField.setLineWrap(true);
+        jScrollPane1.setViewportView(textField);
+
+        add(jScrollPane1, java.awt.BorderLayout.CENTER);
+
+    }//GEN-END:initComponents
+    
+    public void putText(String s) {
+        textField.append(s + "\n");
+        textField.setCaretPosition(textField.getText().length() - 1);
+    }
+    
+    public void setText(String s) {
+        textField.setText(s);
+        textField.setCaretPosition(textField.getText().length() - 1);
+    }
+    
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JScrollPane jScrollPane1;
+    private javax.swing.JTextArea textField;
+    // End of variables declaration//GEN-END:variables
+    
+}


Property changes on: trunk/clients/javer/src/javer/SimpleTextTab.java
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/clients/javer/src/javer/TextFormatter.java
===================================================================
--- trunk/clients/javer/src/javer/TextFormatter.java    2005-04-12 02:39:42 UTC 
(rev 670)
+++ trunk/clients/javer/src/javer/TextFormatter.java    2005-04-25 00:49:04 UTC 
(rev 671)
@@ -0,0 +1,139 @@
+/*
+ * TextFormatter.java
+ *
+ * Created on January 8, 2005, 9:45 PM
+ */
+
+package javer;
+import java.util.*;
+import java.util.regex.*;
+
+/**
+ *
+ * @author bdonlan
+ */
+public class TextFormatter implements java.io.Serializable, Cloneable {
+    
+    protected static Pattern parsepattern = Pattern.compile("%[^%]*%");
+    protected Vector format;
+    protected String formatstr;
+    protected Set expectedKeys;
+    
+    /** Creates a new instance of TextFormatter */
+    public TextFormatter(String formatstr) {
+        this(formatstr, null);
+    }
+    
+    public TextFormatter(String formatstr, Set expectedKeys) {
+        this.formatstr = formatstr;
+        this.expectedKeys = new HashSet(expectedKeys);
+        parse(formatstr);
+    }
+    
+    protected void parse(String formatStr) {
+        Matcher m = parsepattern.matcher(formatStr);
+        int lastEnd = 0;
+        Vector format = new Vector();
+        Iterator it;
+        while (m.find()) {
+            if (m.start() != lastEnd) {
+                /* grab the literal text between the last replace and now */
+                String literal = formatStr.substring(lastEnd, m.start());
+                LiteralChunk c = new LiteralChunk(formatStr, lastEnd, literal);
+                format.add(c);
+            }
+            Chunk c;
+            String key = formatStr.substring(m.start() + 1, m.end() - 1);
+            lastEnd = m.end();
+            if (key.equals("")) {
+                c = new LiteralChunk(formatStr, m.start(), "%");
+                format.add(c);
+                continue;
+            }
+            if (expectedKeys != null) {
+                if (!expectedKeys.contains(key)) {
+                    throw new FormatException(formatStr, m.start(),
+                            "Unexpected replacement key: " + key);
+                }
+            }
+            c = new ReplaceChunk(formatStr, m.start(), key);
+            format.add(c);
+        }
+        /* grab any literal data left */
+        String remain = formatStr.substring(lastEnd);
+        if (remain.length() != 0) {
+            format.add(new LiteralChunk(formatStr, lastEnd, remain));
+        }
+        format.trimToSize();
+        this.format = format;
+    }
+
+    public String format(Map replacements) {
+        StringBuffer b = new StringBuffer();
+        Iterator it = format.iterator();
+        while(it.hasNext()) {
+            Chunk c = (Chunk) it.next();
+            b.append(c.generate(replacements));
+        }
+        return b.toString();
+    }
+    
+    protected interface Chunk extends java.io.Serializable, Cloneable {
+        public String generate(Map replacements);
+    }
+
+    protected final class LiteralChunk implements Chunk {
+        String literal;
+        public String generate(Map replacements) {
+            return literal;
+        }
+        
+        public LiteralChunk(String formatStr, int pos, String literal) {
+            this.literal = literal;
+        }
+    }
+
+    protected final class ReplaceChunk implements Chunk {
+        String key, formatStr;
+        int pos;
+        
+        public String generate(Map replacements) {
+            String value = (String) replacements.get(key);
+            if (value == null) {
+                throw new FormatException(formatStr, pos, "Key not found: " + 
key);
+            }
+            return value;
+        }
+        
+        public ReplaceChunk(String formatStr, int pos, String key) {
+            this.key = key;
+            this.formatStr = formatStr;
+            this.pos = pos;
+        }
+    }
+    
+    public class FormatException extends RuntimeException {
+        public FormatException(String formatstr, int pos, String errorDesc) {
+            super(errorDesc);
+        }
+    }
+    
+    public static void main(String[] args) throws Throwable {
+        String format;
+        HashMap repl = new HashMap(args.length - 1);
+        java.io.BufferedReader pr = new java.io.BufferedReader(
+                new java.io.InputStreamReader(System.in));
+        int i;
+        
+        for (i = 0; i * 2 + 1 < args.length; i++) {
+            repl.put(args[i * 2], args[i * 2 + 1]);
+        }
+        while (true) {
+            TextFormatter f;
+            format = pr.readLine();
+            f = new TextFormatter(format, repl.keySet());
+            System.out.println(f.format(repl));
+        }
+    }
+
+}


Property changes on: trunk/clients/javer/src/javer/TextFormatter.java
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/clients/javer/src/javer/TextTab.java
===================================================================
--- trunk/clients/javer/src/javer/TextTab.java  2005-04-12 02:39:42 UTC (rev 
670)
+++ trunk/clients/javer/src/javer/TextTab.java  2005-04-25 00:49:04 UTC (rev 
671)
@@ -0,0 +1,15 @@
+/*
+ * TextTab.java
+ *
+ * Created on January 6, 2005, 12:44 AM
+ */
+
+package javer;
+
+/**
+ *
+ * @author  bdonlan
+ */
+public interface TextTab {
+    public void putText(String s);
+}


Property changes on: trunk/clients/javer/src/javer/TextTab.java
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/clients/javer/src/javer/ThreadRendezvous.java
===================================================================
--- trunk/clients/javer/src/javer/ThreadRendezvous.java 2005-04-12 02:39:42 UTC 
(rev 670)
+++ trunk/clients/javer/src/javer/ThreadRendezvous.java 2005-04-25 00:49:04 UTC 
(rev 671)
@@ -0,0 +1,50 @@
+/*
+ * ThreadRendezvous.java
+ *
+ * Created on January 10, 2005, 1:42 PM
+ */
+
+package javer;
+
+/**
+ *
+ * @author bdonlan
+ */
+public class ThreadRendezvous {
+    
+    Object value = null;
+    boolean completed = false;
+    
+    /** Creates a new instance of ThreadRendezvous */
+    public ThreadRendezvous() {
+    }
+    
+    public synchronized void complete(Object o) {
+        if (completed) {
+            throw new IllegalStateException("Cannot complete a rendezvous 
twice");
+        }
+        value = o;
+        completed = true;
+        notifyAll();
+    }
+    
+    public synchronized boolean isComplete() {
+        return completed;
+    }
+    
+    public synchronized Object block() throws InterruptedException {
+        return block(0, 0);
+    }
+    
+    public synchronized Object block(long timeout) throws InterruptedException 
{
+        return block(timeout, 0);
+    }
+    
+    public synchronized Object block(long timeout, int nanos) throws 
InterruptedException {
+        if (completed)
+            return value;
+        this.wait(timeout, nanos);
+        return value;
+    }
+    
+}


Property changes on: trunk/clients/javer/src/javer/ThreadRendezvous.java
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/clients/javer/src/javer/TimedInvoker.java
===================================================================
--- trunk/clients/javer/src/javer/TimedInvoker.java     2005-04-12 02:39:42 UTC 
(rev 670)
+++ trunk/clients/javer/src/javer/TimedInvoker.java     2005-04-25 00:49:04 UTC 
(rev 671)
@@ -0,0 +1,37 @@
+/*
+ * TimedInvoker.java
+ *
+ * Created on January 14, 2005, 7:40PM
+ */
+
+package javer;
+import java.util.*;
+import java.io.*;
+import java.math.*;
+
+/**
+ *
+ * @author bdonlan
+ */
+final class TimedInvoker {
+    
+    static TimerThread tt = new TimerThread();
+    
+    private TimedInvoker() {
+        throw new IllegalStateException("Cannot instantiate a singleton 
class");
+    }
+    
+    public static Object invokeAt(long absoluteTimeMillis, Runnable invokee) {
+        return tt.addTimer(absoluteTimeMillis, invokee);
+    }
+    
+    public static Object invokeAfter(long deltaMillis, Runnable invokee) {
+        return tt.addTimer(System.currentTimeMillis() + deltaMillis,
+                invokee);
+    }
+    
+    public static boolean unschedule(Object tag) {
+        return tt.cancelTimer(tag);
+    }
+    
+}
\ No newline at end of file


Property changes on: trunk/clients/javer/src/javer/TimedInvoker.java
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/clients/javer/src/javer/TimerThread.java
===================================================================
--- trunk/clients/javer/src/javer/TimerThread.java      2005-04-12 02:39:42 UTC 
(rev 670)
+++ trunk/clients/javer/src/javer/TimerThread.java      2005-04-25 00:49:04 UTC 
(rev 671)
@@ -0,0 +1,118 @@
+/*
+ * TimerThread.java
+ *
+ * Created on January 14, 2005, 7:47 PM
+ */
+
+package javer;
+import java.util.*;
+
+/**
+ *
+ * @author bdonlan
+ */
+class TimerThread implements Runnable {
+
+    class Timer {
+        Runnable evt;
+        long when;
+    }
+
+    Thread thread = null;
+    SortedMap queue = new TreeMap();
+
+    protected void notifyThread() {
+        synchronized (queue) {
+            if (thread == null || !thread.isAlive()) {
+                thread = new Thread(this);
+                //System.out.println("TT: spawning");
+                thread.start();
+                return;
+            }
+            //System.out.println("TT: interrupting");
+            thread.interrupt();
+        }
+    }
+
+    protected synchronized Object addTimer(long when, Runnable event) {
+        Set slot;
+        Timer te = new Timer();
+        Long oWhen = new Long(when);
+        te.evt = event;
+        te.when = when;
+        synchronized (queue) {
+            slot = (Set)queue.get(oWhen);
+            if (slot == null) {
+                slot = new LinkedHashSet();
+            }
+            slot.add(te);
+            queue.put(oWhen, slot);
+            //System.out.println("TT: add queuelen=" + queue.size());
+            //System.out.println("TT: add slotlen=" + slot.size());
+            notifyThread();
+        }
+        return te;
+    }
+
+    protected synchronized boolean cancelTimer(Object tag) {
+        Timer te = (Timer) tag;
+        Long when = new Long(te.when);
+        synchronized (queue) {
+            Set slot = (Set)queue.get(when);
+            if (slot == null)
+                return false;
+            slot.remove(te);
+            if (slot.isEmpty())
+                queue.remove(when);
+            /* We don't need to notify the thread; if this slot is next then
+             * the thread will just go back to sleep or die once it discovers
+             * the first slot time has changed.
+             */
+            return true;
+        }
+    }
+
+    public void run() {
+        if (Thread.currentThread() != thread)
+            return;
+        while (true) {
+            long nextSlot, delta, now;
+            Set slot = null;
+            now = System.currentTimeMillis();
+            synchronized (queue) {
+                Long firstkey;
+                if (queue.size() == 0) {
+                    /* No work? We die. */
+                    //System.out.println("TT: no work, killing thread");
+                    thread = null;
+                    return;
+                }
+                firstkey = (Long)queue.firstKey();
+                nextSlot = firstkey.longValue();
+                //System.out.println("TT: nxS=" + nextSlot + "\nTT: now=" + 
now);
+                if (nextSlot <= now) {
+                    //System.out.println("TT: pop=" + nextSlot);
+                    slot = (Set) queue.remove(firstkey);
+                }
+            }
+            if (slot != null) {
+                Iterator it = slot.iterator();
+                //System.out.println("TT: slotsize=" + slot.size());
+                while (it.hasNext()) {
+                    Timer te = (Timer)it.next();
+                    //System.out.println("TT: invokeLater("+te.evt+")");
+                    java.awt.EventQueue.invokeLater(te.evt);
+                }
+                continue;
+            }
+            delta = nextSlot - now;
+            try {
+                thread.sleep(delta);
+            } catch (InterruptedException e) {}
+        }
+    }
+
+    TimerThread() {
+    }
+}
+


Property changes on: trunk/clients/javer/src/javer/TimerThread.java
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/clients/javer/src/javer/UserQueryTab.java
===================================================================
--- trunk/clients/javer/src/javer/UserQueryTab.java     2005-04-12 02:39:42 UTC 
(rev 670)
+++ trunk/clients/javer/src/javer/UserQueryTab.java     2005-04-25 00:49:04 UTC 
(rev 671)
@@ -0,0 +1,40 @@
+/*
+ * UserQueryTab.java
+ *
+ * Created on January 6, 2005, 10:39 PM
+ */
+
+package javer;
+
+/**
+ *
+ * @author bdonlan
+ */
+public class UserQueryTab extends SimpleTextTab implements QueryTab {
+    
+    String who;
+    HaverClient cli;
+    
+    /** Creates a new instance of UserQueryTab */
+    public UserQueryTab(HaverClient cli, String who) {
+        super();
+        this.cli = cli;
+        this.who = who;
+        putText("--- Opening query with: " + who);
+    }
+
+    public String getUID() {
+        return who;
+    }
+    
+    public void sendAction(String s) throws java.io.IOException {
+        putText("* " + cli.getUID() + " " + s);
+        cli.sendPrivateAction(who, s);
+    }
+
+    public void sendText(String s) throws java.io.IOException {
+        putText("<" + cli.getUID() + "> " + s);
+        cli.sendPrivateNormalMessage(who, s);
+    }
+    
+}


Property changes on: trunk/clients/javer/src/javer/UserQueryTab.java
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: trunk/main/server/lib/Haver/Server/Base.pm
===================================================================
--- trunk/main/server/lib/Haver/Server/Base.pm  2005-04-12 02:39:42 UTC (rev 
670)
+++ trunk/main/server/lib/Haver/Server/Base.pm  2005-04-25 00:49:04 UTC (rev 
671)
@@ -1,12 +1,10 @@
-# vim: set ts=4 sw=4 expandtab si ai sta tw=100:
+# vim: set ts=4 sw=4 si ai sta tw=100:
 # This module is copyrighted, see end of file for details.
 package Haver::Server::Base;
 use Spiffy qw( -Base );
-use Spiffy qw( -XXX -dumper );
 use Carp;
 
-our @EXPORT = qw( croak carp confess );
-our @EXPORT_BASE = qw( field );
+our @EXPORT_BASE = qw( field croak carp confess );
 
 
 {

Modified: trunk/main/server/lib/Haver/Server/Listener.pm
===================================================================
--- trunk/main/server/lib/Haver/Server/Listener.pm      2005-04-12 02:39:42 UTC 
(rev 670)
+++ trunk/main/server/lib/Haver/Server/Listener.pm      2005-04-25 00:49:04 UTC 
(rev 671)
@@ -1,54 +1,30 @@
-# Haver::Server::POE::Listener,
-# this creates a session that listens for connections,
-# and when something connects, it spawns
-# a Haver::Server::Connection session.
-# 
-# Copyright (C) 2003 Dylan William Hardison.
-#
-# This module 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 module 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 module; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-# TODO, write POD. Soon.
 package Haver::Server::Listener;
-use strict;
-use warnings;
-use Carp;
-use POE qw(
-       Wheel::SocketFactory
-);
+use Haver::Server::Base '-Base';
 
-use Haver::Preprocessor;
+use POE;
+use POE::Wheel::SocketFactory;
 use Haver::Server::Speaker;
 
 sub create {
        my $class = shift;
-       # ASSERT: (@_ == 1 and ref($_[0]) eq 'HASH') or ((@_ % 2) == 0);
-       my $opts = @_ == 1 ? $_[0] : { @_ };
+       my %opts = @_;
+       unless (exists $opt{acceptor}) {
+               croak "Require parameter acceptor missing";
+       }
 
        POE::Session->create(
-               package_states => 
-               [
+               package_states => [
                        $class => [qw(
                                _start
                                _stop
                                socket_birth
                                socket_fail
                                listen
+                               unlisten
                                shutdown
                        )],
                ],
-               heap => $opts,
+               heap => {},
        );
 }
 
@@ -56,36 +32,34 @@
        my ($kernel, $heap) = @_[KERNEL, HEAP];
        
 
-       # DEBUG(session): "Listener starts.";
-       $heap->{wheels} = {};
-       $heap->{info}   = {};
-       $heap->{kids}   = {};
+       $heap->{listeners}  = {};
+       $heap->{children}   = {};
+       $heap->{names}      = {};
        $kernel->alias_set('Listener');
 }
 
 sub _stop {
     my ($kernel, $heap) = @_[KERNEL,HEAP];
-       # DEBUG(session): "Listener stops.";
 }
 
 sub _child {
        my ($kernel, $heap, $type, $kid) = @_[KERNEL, HEAP, ARG0, ARG1];
 
        if ($type eq 'create' or $type eq 'gain') {
-               $heap->{kids}{$kid->ID} = 1;
+               $heap->{children}{$kid->ID} = 1;
        } elsif ($type eq 'lose') {
-               delete $heap->{kids}{$kid->ID};
+               delete $heap->{children}{$kid->ID};
        } else {
                die "I don't know how I got here!\n";
        }
 }
 
-# iface = {
-#    host   => string # to $bindto . ':' . $port or $port if $bindto is undef.
-#    bindto => domain_name  | IPv4_addr
-#    port   => service_name | port_number
-# }
 
+# $iface = {
+#      name => 'example.com',
+#      port => 7070,
+#      addr => "IP address of interface bind to",
+# }
 sub listen {
        my ($kernel, $heap, $iface) = @_[KERNEL, HEAP, ARG0, ARG1];
 
@@ -93,47 +67,56 @@
 
        my $wheel = POE::Wheel::SocketFactory->new(
                BindPort     => $iface->{port},
+               BindAddress  => $iface->{addr},
                Reuse        => 1,
                SuccessEvent => 'socket_birth',
                FailureEvent => 'socket_fail',
        );
-       $heap->{wheels}{$wheel->ID} = $wheel;
-       $heap->{info}{$wheel->ID}   = $iface;
+       $heap->{listeners}{$wheel->ID} = {
+               wheel => $wheel,
+               iface => $iface,
+       };
+       $heap->{names}{ $iface->{name} } = $wheel->ID;
 }
 
 sub unlisten {
-    my ($kernel, $heap, $iface
+    my ($kernel, $heap, $name) = @_[KERNEL, HEAP, ARG0];
+    my $wid = delete $heap->{names}{ $iface->{name} }
+    unless ($wid) {
+       warn "$name is not a valid listener name.";
+    }
+    
+    delete $heap->{listeners}{$wid}
+       or warn "Unable to delete wheel with id $wid (name: $name)";
 }
 
 sub socket_birth {
     my ($kernel, $heap, $socket, $address, $port, $wid) =
        @_[KERNEL, HEAP, ARG0, ARG1, ARG2, ARG3];
-       my $info = $heap->{info}{$wid};
-       
-       create Haver::Server::Speaker {
+       my $info = $heap->{listeners}{$wid}{iface};
+
+       $heap->{acceptor}->(
                sock    => $socket,
                address => Socket::inet_ntoa($address),
                port    => $port,
                iface   => $info,
-       };
+       );
+
 }
 
 sub socket_fail {
        my ($kernel, $heap, $operation, $errnum, $errstr, $wheel_id) = 
@_[KERNEL, HEAP, ARG0..ARG3];
-       delete $heap->{info}{$wheel_id};
-       delete $heap->{wheels}{$wheel_id};
+       delete $heap->{listeners}{$wheel_id}{wheel};
 
-       $kernel->post('Logger', 'error', "Operation '$operation' failed: 
$errstr ($errnum)");
+       warn "Operation '$operation' failed: $errstr ($errnum)";
 }
 
 sub shutdown {
        my ($kernel, $heap) = @_[KERNEL, HEAP];
        $kernel->alias_remove('Listener');
        
-       foreach my $kid (keys %{ $heap->{kids} }) {
+       foreach my $kid (keys %{ $heap->{children} }) {
                $kernel->post($kid, 'shutdown');
        }
        %$heap = ();
 }
-
-1;


Reply via email to