Index: trunk/code/projects/colonet/ColonetGUI/colonetstyle.css
===================================================================
--- trunk/code/projects/colonet/ColonetGUI/colonetstyle.css	(revision 475)
+++ trunk/code/projects/colonet/ColonetGUI/colonetstyle.css	(nonexistent)
@@ -1,45 +0,0 @@
-/* Colonet Applet Stylesheet */
-/* Gregory Tress */
-
-div
-{
-	background-color: #A00016;
-	color: white;
-	font-family: verdana, arial, helvetica, sans-serif;
-	padding: 2px 2px 2px 2px;
-}
-
-/* Top bar */
-div.top
-{
-	font-size: 14pt;
-}
-div.top img
-{
-	position: absolute;
-	top: 10px;
-	right: 10px;
-}
-
-/* The Applet */
-div.app
-{
-	background-color: white;
-	color: black;
-}
-
-object.applet
-{
-    
-}
-
-/* Bottom bar */
-div.bottom
-{
-	font-size: 12pt;
-}
-div.bottom a
-{
-	color: #DDFFFF;
-}
-
Index: trunk/code/projects/colonet/ColonetGUI/ColonetServerInterface.java
===================================================================
--- trunk/code/projects/colonet/ColonetGUI/ColonetServerInterface.java	(revision 475)
+++ trunk/code/projects/colonet/ColonetGUI/ColonetServerInterface.java	(nonexistent)
@@ -1,538 +0,0 @@
-/*
-*	ColonetServerInterface.java
-*	Gregory Tress
-*/
-
-import java.net.*;
-import java.io.*;
-import javax.swing.JOptionPane;
-import javax.swing.JTextArea;
-
-/**
-* The Colonet server interface class. This class handles direct communication with the Colonet server. The general
-* contract is that this class will encapsulate the process of sending commands and requests to the server and 
-* receiving responses. This class should provide methods to send specific commands and requests so that the 
-* Colonet can easily communicate with the server. When data is received from the server, the ColonetServerInterface 
-* decides how to handle it and in many cases this means simply passing it to the Colonet. 
-* <p>
-* The motivation is that any number of Colonet-type classes could be designed for different purposes if needed, with
-* this class being used by each one for communication. 
-* For instance, if an application is designed which only monitors sensor data, or that only has access to
-* the task queue, etc., the application could easily plug in to this interface.
-* The Colonet should generally not contain communication-specific code or Strings of command and request data. 
-* If additional commands and requests are needed for permanent implementation, it is suggested that convenience
-* classes be created in the ColonetServerInterface and called from the Colonet.
-*
-* @author Gregory Tress 
-*/
-public class ColonetServerInterface 
-{
-
-	/* STATIC FIELDS
-	 * Eugene Marinelli, Fan
-	 * 10/27/06
-	 *
-	 * Colonet Definitions - common definitions and structs used in all colonet 
-	 * applications
-	
-	Old packet structure:
-
-    COMMAND PACKET STRUCTURE
-	1:  SEND_TO_ROBOT
-	2:  # of robot, or GLOBAL_DEST
-	3:  COLONET_COMMMAND
-	4:  message code (i.e. ORB_SET)
-	5:  any data, as many that fit in the packet
-	
-	REQUEST PACKET STRUCTURE
-	1:  REQUEST_FROM_SERVER
-	2:  # of robot
-	3:  COLONET_REQUEST
-	4:  ???
-  
-  9/12/07 New server interface structure
-    Client will no longer send full robot packets to the server.
-    Commands will be defined as necessary.
-	*/
-	
-	//General Colonet Interface
-	public static final String SEND_TO_ROBOT = "0";
-	public static final String REQUEST_FROM_SERVER = "1";
-	public static final String RESPONSE_TO_CLIENT_REQUEST = "2";
-	public static final String REQUEST_BOM_MATRIX = "144";
-	public static final String REQUEST_XBEE_IDS = "145";
-	
-	public static final String COLONET_COMMAND = "13"; //0x0D
-	public static final String COLONET_REQUEST = "14"; //0x0E
-	public static final String CORONET_RESPONSE = "15"; //0x0F
-	public static final String GLOBAL_DEST = "200";
-	public static final String CLIENT_REQUEST_ROBOT_POSITIONS = "86";
-	public static final String CLIENT_ASSIGN_ROBOT_ID = "87";
-	public static final String MOVE_TO_ABSOLUTE_POSITION = "83"; //0x53
-	
-	//Queue instructions
-	public static final String COLONET_QUEUE = "100";
-	public static final String QUEUE_UPDATE = "101"; 
-	public static final String QUEUE_ADD = "102";
-	public static final String QUEUE_REMOVE = "103";
-	public static final String QUEUE_REORDER = "104";
-	
-	//Use BATTERY to request battery level
-	public static final String BATTERY = "56"; //0x38
-	
-	//MOTORS
-	public static final String MOTORS_INIT = "23"; //0x17
-	public static final String MOTOR1_SET = "24"; //0x18
-	public static final String MOTOR2_SET = "25"; //0x19
-	public static final String MOTORS_OFF = "26"; //0x1A
-	public static final String MOVE = "27"; //0x1B
-	public static final String MOVE_AVOID = "28"; //0x1C
-	
-	//BUZZER
-	public static final String BUZZER_INIT = "0"; //0x00
-	public static final String BUZZER_SET_VAL = "1"; //0x01
-	public static final String BUZZER_SET_FREQ = "2"; //0x02
-	public static final String BUZZER_CHIRP = "3"; //0x03
-	public static final String BUZZER_OFF = "4"; //0x04
-
-	//ORB
-	public static final String ORB_INIT = "12"; //0x0C
-	public static final String ORB_SET = "13"; //0x0D
-	public static final String ORB_SET_COLOR = "14"; //0x0E
-	public static final String ORB_DISABLE = "15"; //0x0F
-	public static final String ORB_ENABLE = "16"; //0x10
-	public static final String ORB_SET_DIO = "17"; //0x11
-	public static final String LED_INIT = "18"; //0x12
-	public static final String LED_USER = "19"; //0x13
-	public static final String ORB_SET_NUM_NS = "20"; //0x14
-	public static final String ORB_SET_NUM = "21"; //0x15
-	public static final String ORB_SEND = "22"; //0x16
-
-		
-	Colonet colonet;  //save reference to the entire applet locally
-	Socket socket;
-	OutputStreamWriter out;
-	BufferedReader reader;
-	DataListener dataListener;
-	JTextArea log, txtMatrix;
-	
-	
-	/*
-	*	FUNCTION IMPLEMENTATIONS
-	*/
-
-	/**
-	* Constructs a new ColonetServerInterface. When constructing a ColonetServerInterface, a valid Colonet object
-	* reference must be provided to ensure that data is routed correctly. 
-	*
-	* @param colonet The Colonet object to save locally. This reference cannot be changed once the 
-	*		ColonetSreverInterface has been contsructed.
-	* @throws NullPointerException if colonet is null
-	*
-	*/
-	public ColonetServerInterface (Colonet colonet) {
-		this.colonet = colonet;
-		this.log = colonet.getLog();
-		this.txtMatrix = colonet.getMatrixInput();
-		dataListener = new DataListener();
-	}
-
-	public Socket getSocket () {
-		return socket;
-	}
-	
-	public OutputStreamWriter getOutputStreamWriter () {
-		return out;
-	}
-	
-	public BufferedReader getBufferedReader () {
-		return reader;
-	}
-	
-	public boolean isReady () {
-		if (socket == null || out == null || reader == null)
-			return false;
-		if (!socket.isConnected() || socket.isClosed() || socket.isInputShutdown() || socket.isOutputShutdown())
-			return false;
-		return true;
-	}
-	
-	public boolean isInputReady () {
-		try {
-			if (reader.ready()) return true;
-		} catch (Exception e) {
-			return false;
-		}
-		return false;
-	}
-	
-	public String getLine () throws IOException {
-		return reader.readLine();
-	}
-  
-	/**
-	 * Create socket connection to Colonet server.
-	 * If successful, start thread for listening for incoming data.
-	 */
-	public void connect (String strHost, String strPort) {
-		//make sure hostname and port are valid
-		if (strHost.equals("") || strPort.equals("")) {
-			err("Please enter a hostname and port.");
-			return;
-		}
-		int port = 0;
-		try {
-			port = Integer.parseInt(strPort);
-		} catch (Exception e) {
-			err("Invalid port");
-			return;
-		}
-		
-		//make sure we aren't already connected.
-		if (socket != null && socket.isConnected()) {
-			return;
-		}
-		
-		try {
-			socket = new Socket(strHost, port);
-			socket.setKeepAlive(true);
-		} catch (UnknownHostException e) {
-			log.append("Unknown host exception.\n");
-			err("Unknown Host Exception");
-			return;
-		} catch (IOException e) {
-			log.append("IO Exception.\n");
-			err("Could not create socket to " + strHost + ".\n" + e);
-			return;
-		} catch (java.security.AccessControlException e) {
-			log.append("Access Control Exception.\n");
-			err("Permission denied by java.security.AccessControlException.\n\n"
-				+"You may only connect to the server from which this applet was loaded.");
-			return;
-		}
-		if (socket == null || !socket.isConnected()) {
-			log.append("Connection is not ready. Try connecting again.\n");
-			return;
-		}
-		try {
-			out = new OutputStreamWriter(socket.getOutputStream());
-			reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
-		} catch (IOException e) {
-			warn("Could not get transfer streams from socket connection.");
-		}
-		dataListener.start();
-	
-	}
-	
-	public void disconnect () {
-	    
-	}
-	
-	/*
-	*	sendString - only this method should actually write data to the output stream
-	*/
-	private void sendString (String s) {
-		//make sure we can send
-		if (!this.isReady()) {
-			log.append("Could not send data.\n");
-			return;
-		}
-		//send packet
-		try {
-			Thread.sleep(50);  //pause to be safe
-			out.write(s);
-			out.flush();
-			//log.append("Sent: " + s + "\n");
-		} catch (IOException e) {
-			log.setText("Could not send data.\n");
-		} catch (InterruptedException e) {
-			log.setText("Thread InterruptedException in sendData\n");
-		}
-	}
-	
-	/**
-	* General send-to-server method. This method is used by other command methods, which are usually convenience
-	* methods that simply specify arguments to this method. A command consists of a String which holds integers 
-	* separated by spaces. This method should not be used directly unless you know the format of the particular 
-	* command you are sending. If implementing a particular command for permanent use, it is recommended that 
-	* you create a new wrapper method specific to that command in the ColonetServerInterface file.
-	*
-	* Note that no checking is performed in this method to ensure the correct formatting of the String arguments.
-	* If malformed commands or robot numbers are specified, the behavior of the request at the server will be
-	* undefined and could result in server failure. 
-	*
-	* @param s The command String in its correct format. The format of a command String is ultimately specified
-	* by the Colonet server application and may change. 
-	* @param robotNumber The number of the robot that is the subject of the command, if any. The robot number 
-	* is specified as a single integer in a String. If the command does not have a single robot subject, this 
-	* argument can be null or an empty String, whichever is convenient. 
-	*/
-	public void sendData (String s, String robotNumber) { 
-		//create packet
-		String packet = "";
-		packet += ColonetServerInterface.SEND_TO_ROBOT;
-		if (robotNumber != null)
-			packet += " " + 7;  //robotNumber;
-		packet += " " + ColonetServerInterface.COLONET_COMMAND;
-		packet += " " + s;  //add  the command code here
-		packet += "\n";
-		sendString(packet);
-		txtMatrix.append("S:" + packet);
-	}
-	
-	/**
-	* General request-from-server method. This method is used by other request methods, which are usually convenience
-	* methods that simply specify arguments to this method. A request consists of a String which holds integers 
-	* separated by spaces. This method should not be used directly unless you know the format of the particular 
-	* request you are making. If implementing a particular request, it is recommended that you create a new method
-	* specific to that request in the ColonetServerInterface file.
-	*
-	*/
-	private void sendRequest (String s, String robotNumber) {
-		//create packet
-		String packet = "";
-		packet += ColonetServerInterface.REQUEST_FROM_SERVER;
-		packet += " " + robotNumber;
-		packet += " " + s;  //add  the command code here
-		packet += "\n";
-		sendString(packet);
-	}
-	
-	/** 
-	* Sends a request to the server to report the entire BOM sensor matrix. The server will reply at its convenience. 
-	* No guarantee is made (end-to-end or otherwise) that the server will respond in a timely manner or at all
-	* to any individual request.
-	*/
-	public void sendSensorDataRequest () {
-		sendRequest(ColonetServerInterface.REQUEST_BOM_MATRIX, "");
-	}
-	
-	/**
-	* Sends a request to the server to report a list of XBee IDs. The server will reply at its convenience. 
-	* The purpose of having this list is to ensure that robots are properly identified for control purposes.
-	* This keeps robot identification consistent between sessions and prevents arbitrary assignment. 
-	* No guarantee is made (end-to-end or otherwise) that the server will respond in a timely manner or at all
-	* to any individual request.
-	*
-	* @see Colonet#parseXBeeIDs(String)
-	*/
-	public void sendXBeeIDRequest () {
-		sendRequest(ColonetServerInterface.REQUEST_XBEE_IDS, "");
-	}
-	
-	/**
-	* Sends a battery request for a specific robot to the server. The server will reply at its convenience. 
-	* Behavior is undefined if an invalid robot number is specified. The server will probably not respond in 
-	* this case.
-	* No guarantee is made (end-to-end or otherwise) that the server will respond in a timely manner or at all
-	* to any individual request.
-	*
-	* @param robotNum The number of the robot for which we are requesting the battery. Note that this value
-	* is sent as-is to the server. No mapping to or from XBee IDs is performed. The contract for this is
-	* currently undefined.
-	* @see Colonet#parseBattery(String)
-	*/
-	public void sendBatteryRequest (int robotNum) {
-		//create packet
-		String packet = "";
-		packet += ColonetServerInterface.SEND_TO_ROBOT;
-		packet += " " + robotNum;
-		packet += " " + ColonetServerInterface.COLONET_REQUEST;
-		packet += " " + ColonetServerInterface.BATTERY;  //add  the command code here
-		packet += "\n";
-		sendString(packet);
-	}
-	
-	/**
-	* Requests a list of all robot positions and correspondind robot IDs.
-	*/
-	public void sendPositionRequest () {
-		sendRequest(ColonetServerInterface.CLIENT_REQUEST_ROBOT_POSITIONS, "");
-	}
-	
-	/**
-	* Send a robot ID assignment update to store on the server.
-	*/
-	public void sendIDAssignment (int oldID, int newID) {
-		String packet = "";
-		packet += ColonetServerInterface.REQUEST_FROM_SERVER;
-		packet += " " + oldID + " " + newID;
-		packet += "\n";
-		sendString(packet);
-		txtMatrix.append("ID " + oldID + " => " + newID + "\n");
-	}
-	
-	/** 
-	* Order a robot to move to an absolute coordinate point.
-	*/
-	public void sendAbsoluteMove (int id, int x, int y) {
-	    sendData(MOVE_TO_ABSOLUTE_POSITION + " " + x + " " + y, "" + id);
-	}
-	
-	/*
-	*	Queue management
-	*/
-	private void sendQueueInstruction (String inst) {
-		String packet = "";
-		packet += ColonetServerInterface.COLONET_QUEUE;
-		packet += " " + inst;
-		packet += "\n";
-		sendString(packet);
-	}
-	
-	/**
-	* Notifies the Colonet server to add a task to the current task queue. The Colonet server holds the canonical 
-	* task queue. Any applet can send tasks to add to the queue. Local copies of the queue in the applet are for
-	* display purposes only, and are not authoritative when adding tasks. All clients send additions asynchronously,
-	* and as a result no guarantee is made that a task will be added in the specificed location in the queue or at 
-	* all. If an invalid position is specified, the task will probably not be added to the queue and may cause
-	* server failure. Due to the asynchronous nature of the queue, we cannot easily account for concurrent
-	* modification failures on the client side.
-	*
-	* @param pos The position in the queue at which we would like the task to be placed. Note that this is not 
-	* guaranteed. Invalid positions may cause the task to be discarded at the server.
-	* @param data The String containing the command code(s) for the task and any arguments necessary to fully 
-	* define the behavior of the task. This format is currently not specified. In the future, the canonical format
-	* of the data String will ultimately be defined by the Colonet server.
-	* @param description A String that contains a description of the task. This will be the message displayed to
-	* the user when information about the task is requested. 
-	*/
-	public void sendQueueAdd (int pos, String data, String description) {
-		String packet = "";
-		packet += ColonetServerInterface.QUEUE_ADD;
-		packet += " " + pos;
-		packet += " " + data;
-		packet += " [" + description + "]";
-		packet += "\n";
-		sendQueueInstruction(packet);
-	}
-	
-	/**
-	* Notifies the Colonet server to remove a task from the current task queue. The Colonet server holds the canonical 
-	* task queue. Any applet can remove a task from the queue. Local copies of the queue in the applet are for
-	* display purposes only, and are not authoritative when removing tasks. All clients remove tasks asynchronously,
-	* and as a result no guarantee is made that the correct task will actually be removed. 
-	* If an invalid position is specified, the state of the queue is undefined and server failure may result.
-	* Due to the asynchronous nature of the queue, we cannot easily account for concurrent
-	* modification failures on the client side.
-	*
-	* @param pos The position in the queue at which we would like the task to be removed. Note that this is not 
-	* guaranteed. Invalid positions may result in a corrupted queue.
-	*/
-	public void sendQueueRemove (int pos) {
-		String packet = "";
-		packet += ColonetServerInterface.QUEUE_REMOVE;
-		packet += " " + pos;
-		packet += "\n";
-		sendQueueInstruction(packet);
-	}
-
-	/**
-	* Notifies the Colonet server to reorder tasks in the current task queue. The Colonet server holds the canonical 
-	* task queue. Any applet can reorder tasks in the queue. Local copies of the queue in the applet are for
-	* display purposes only, and are not authoritative when reordering tasks. All clients reorder tasks asynchronously,
-	* and as a result no guarantee is made that the correct tasks will actually be reordered. 
-	* If an invalid position is specified, the state of the queue is undefined and server failure may result.
-	* Due to the asynchronous nature of the queue, we cannot easily account for concurrent
-	* modification failures on the client side.
-	*
-	* @param pos1 The queue position of a task which we would like to reorder.
-	* @param pos2 The queue position of a task which we would like to reorder.
-	*/
-	public void sendQueueReorder (int pos1, int pos2) {
-		String packet = "";
-		packet += ColonetServerInterface.QUEUE_REORDER;
-		packet += " " + pos1;
-		packet += " " + pos2;
-		packet += "\n";
-		sendQueueInstruction(packet);
-	}
-
-	public void sendQueueUpdate () {
-		sendQueueInstruction(ColonetServerInterface.QUEUE_UPDATE);
-	}
-	
-	/**
-	 * Display informational message box on the screen. Used for casual communicaton to the user.
-	 * @param text Text to display
-	 */
-	public void msg (String text) {
-		JOptionPane.showMessageDialog(colonet, text, "Colonet", JOptionPane.INFORMATION_MESSAGE);
-	}
-	
-	/**
-	 * Display warning message box on the screen. Used for minor alerts or exceptions.
-	 * @param text Text to display
-	 */
-	public void warn (String text) {
-		JOptionPane.showMessageDialog(colonet, text, "Colonet", JOptionPane.WARNING_MESSAGE);
-	}
-	
-	/**
-	 * Display error message box on the screen. Used for major errors or exceptions in the program.
-	 * @param text Text to display
-	 */
-	public void err (String text) {
-		JOptionPane.showMessageDialog(colonet, text, "Colonet", JOptionPane.ERROR_MESSAGE);
-	}
-	
-		
-	/*
-	*	DataListener thread.
-	*
-	*/
-	class DataListener extends Thread {
-		final int DATALISTENER_DELAY = 222;
-		
-		public DataListener () {
-			super("Colonet DataListener");
-		}
-		
-		public void run () {
-			String line;
-			while (true) { 
-				try {
-					line = reader.readLine();
-					if (line == null)
-					    throw new IOException();
-					parseData(line);
-					Thread.sleep(DATALISTENER_DELAY);
-				} catch (InterruptedException e) {
-					return;
-				} catch (IOException e) {
-			        disconnect();
-				    colonet.disconnect();
-				    return;
-				}
-			}
-		}
-		
-		public void parseData (String line) {
-			// Sensor Matrix
-			if (line.startsWith(ColonetServerInterface.RESPONSE_TO_CLIENT_REQUEST + " " +
-				ColonetServerInterface.REQUEST_BOM_MATRIX))
-				colonet.parseMatrix(line);
-			// Task Queue
-			else if (line.startsWith(ColonetServerInterface.COLONET_QUEUE))
-				colonet.parseQueue(line);
-			// XBee IDs
-			else if (line.startsWith(ColonetServerInterface.RESPONSE_TO_CLIENT_REQUEST + " " +
-				ColonetServerInterface.REQUEST_XBEE_IDS))
-				colonet.parseXBeeIDs(line);
-			// Battery
-			else if (line.startsWith(ColonetServerInterface.RESPONSE_TO_CLIENT_REQUEST + " " +
-				ColonetServerInterface.BATTERY))
-				colonet.parseBattery(line);
-			// Robot Positions
-			else if (line.startsWith(ColonetServerInterface.RESPONSE_TO_CLIENT_REQUEST + " " +
-				ColonetServerInterface.CLIENT_REQUEST_ROBOT_POSITIONS))
-				colonet.parsePositions(line);
-			// Unknown type
-			else
-				txtMatrix.setText("Got unknown data: " + line + "\n");
-				
-		}
-
-	}
-
-}
Index: trunk/code/projects/colonet/ColonetGUI/Makefile
===================================================================
--- trunk/code/projects/colonet/ColonetGUI/Makefile	(revision 475)
+++ trunk/code/projects/colonet/ColonetGUI/Makefile	(nonexistent)
@@ -1,45 +0,0 @@
-# Colonet GUI Makefile
-# Gregory Tress
-#
-# DIR is the name of the output directory
-# JCFLAGS are the compiler options
-# JCWARN specifies which warnings should be displayed
-#
-# Complier Flags
-#  -g            Generate all debugging info
-#  -d <dir>      Specify where to place generated class files
-#  -target <vm>  Generate class files for a specific VM release (i.e. 1.6)
-#  -Xlint        Enable warnings
-
-JC = javac
-DIR = build
-JCFLAGS = -g -d $(DIR) -target 1.5
-JCWARN = -Xlint:deprecation,unchecked,fallthrough,path,finally
-
-# Java file compilation instructions
-
-default: $(DIR)/Colonet.class $(DIR)/ColonetServerInterface.class $(DIR)/Colonet.jar
-
-$(DIR)/Colonet.jar: $(DIR)/Colonet.class $(DIR)/ColonetServerInterface.class
-	@echo --- Creating archive file ---
-	cd $(DIR); jar cf Colonet.jar *.class; jarsigner -keystore colonetkey -storepass colonet Colonet.jar colonet
-	@echo --- Done ---
-
-$(DIR)/Colonet.class: Colonet.java
-	@echo --- Compiling ---
-	$(JC) $(JCWARN) $(JCFLAGS) Colonet.java
-
-$(DIR)/ColonetServerInterface.class: ColonetServerInterface.java
-	$(JC) $(JCWARN) $(JCFLAGS) ColonetServerInterface.java
-
-install:
-	@echo --- Copying files to /var/www/colonet ---
-	rm -rf /var/www/colonet/
-	mkdir /var/www/colonet/
-	cp $(DIR)/Colonet.jar /var/www/colonet/Colonet.jar
-	cp index.xhtml /var/www/colonet/index.xhtml
-	cp colonetstyle.css /var/www/colonet/colonetstyle.css
-
-clean:
-	$(RM) $(DIR)/*.class
-	$(RM) $(DIR)/*.jar
Index: trunk/code/projects/colonet/ColonetGUI/build/colonetkey
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: trunk/code/projects/colonet/ColonetGUI/build/colonetkey
===================================================================
--- trunk/code/projects/colonet/ColonetGUI/build/colonetkey	(revision 475)
+++ trunk/code/projects/colonet/ColonetGUI/build/colonetkey	(nonexistent)

Property changes on: trunk/code/projects/colonet/ColonetGUI/build/colonetkey
___________________________________________________________________
Deleted: svn:mime-type
## -1 +0,0 ##
-application/octet-stream
\ No newline at end of property
Index: trunk/code/projects/colonet/ColonetGUI/index.xhtml
===================================================================
--- trunk/code/projects/colonet/ColonetGUI/index.xhtml	(revision 475)
+++ trunk/code/projects/colonet/ColonetGUI/index.xhtml	(nonexistent)
@@ -1,57 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" 
-  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
-
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
-  <head>
-    <title>Colony Control Applet - Carnegie Mellon Robotics Club</title>
-    <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
-    <link rel="stylesheet" type="text/css" href="colonetstyle.css" />
-  </head>
-
-  <body>
-
-    <div class="top">
-      <h3>Colonet</h3>
-      <img src="http://roboclub8.frc.ri.cmu.edu/mainwiki/roboclublogo.png" alt="RoboClub Logo" />
-    </div>
-
-    <div class="app">
-      <p>
-	<object class = "applet"
-	   archive = "Colonet.jar"
-	   type = "application/x-java-applet"
-	   width = "950"
-	   height = "550"
-	   codebase = "."
-	   codetype = "application/x-java-applet"
-	   name = "Colonet"
-	   title = "Colonet" >
-	  <param name="type" value="application/x-java-applet" /> 
-	  <param name = "code" value = "Colonet.class" />
-	  <param name = "cache_option" value = "No" />
-	</object>
-	<br />
-	Requires Java 5.
-	<br />
-      </p>
-    </div>
-
-    <div class="bottom">
-      <p><b>Colony Project Home page:</b>&nbsp;<a href="http://www.robotcolony.org/">www.robotcolony.org</a></p>
-
-      <p><b>Validator:</b><br />
-	<a href="http://validator.w3.org/check?uri=referer">
-	  <img src="http://www.w3.org/Icons/valid-xhtml11-blue"
-	       alt="Valid XHTML 1.0 Transitional"
-	       height="31"
-	       width="88"
-	       />
-	</a>
-	<br />
-      </p>
-
-    </div>
-
-  </body>
-</html>
Index: trunk/code/projects/colonet/ColonetGUI/Colonet.java
===================================================================
--- trunk/code/projects/colonet/ColonetGUI/Colonet.java	(revision 475)
+++ trunk/code/projects/colonet/ColonetGUI/Colonet.java	(nonexistent)
@@ -1,1523 +0,0 @@
-//
-//  Colonet.java
-//
-
-import javax.swing.*;
-import javax.swing.event.*;
-import javax.imageio.*;
-import java.awt.*;
-import java.awt.image.*;
-import java.awt.event.*;
-import java.net.*;
-import java.io.*;
-import java.util.*;
-
-
-/**
-*	The Colonet Graphical User Interface Applet for use locally and over an internet connection.
-*	@author Gregory Tress
-*	
-*	To generate javadoc on this file or other java files, use javadoc *.java -d doc, where doc
-*	is the name of the folder into which the files should be written.
-*/
-public class Colonet extends JApplet implements ActionListener, MouseInputListener, KeyListener, Runnable {
-
-	// Used for images
-	final int CANVAS_SIZE = 500;  //the applet may be slow if the canvas gets too large
-	final int BUFFER = 50;
-	final int RADIUS = 30;
-	
-	//Used for the robot controller
-	final int VECTOR_CONTROLLER_HEIGHT = 220;
-	final int VECTOR_CONTROLLER_WIDTH = 350;
-	
-
-	// Connection
-	JTextField txtHost;				
-	JTextField txtPort;				
-	JButton btnConnect;	
-	JButton btnGetXBeeIDs;
-	JLabel lblConnectionStatus;
-	JTextArea txtMatrix;
-	JTextArea txtInfo; 
-	JPanel panelConnect;
-	JPanel panelServerInterface;
-	Socket socket;					
-	OutputStreamWriter out;
-	DataUpdater dataUpdater;  
-	
-	// South
-	JPanel panelSouth;
-	JTextArea log;
-	JScrollPane spLog;
-	
-	// Control
-	JPanel panelControl;
-	JTabbedPane tabPaneControl;
-	JPanel panelRobotControl;
-	JPanel panelRobotDirection;
-	JPanel panelRobotDirectionButtons;
-	JPanel panelRobotCommands;
-	JButton btnF, btnB, btnL, btnR, btnActivate;
-	JComboBox cmbRobotNum;
-	JLabel lblBattery;
-	JLabel lblSelected;
-	BatteryIcon batteryIcon;
-	JPanel panelBattery;
-	VectorController vectorController;
-	BufferedImage imageVectorControl;
-	JButton btnAssignID;
-	boolean setWaypoint;
-	int setWaypointID;
-	JButton btnCommand_MoveTo;
-	JButton btnCommand_MoveAll;
-	JButton btnCommand_StopTask;
-	JButton btnCommand_ResumeTask;
-	JButton btnCommand_ChargeNow;
-	JButton btnCommand_StopCharging;
-	
-	// Task Manager
-	JPanel panelTaskManager;
-	JScrollPane spTaskManager;
-	JPanel panelTaskManagerControls;
-	JPanel panelTaskManagerControlsPriority;
-	DefaultListModel taskListModel;
-	JList taskList;
-	JButton btnAddTask;
-	JButton btnRemoveTask;
-	JButton btnMoveTaskUp;
-	JButton btnMoveTaskDown;
-	JButton btnUpdateTasks;
-	TaskAddWindow taskAddWindow;
-	
-	//Webcam
-	WebcamPanel panelWebcam;
-	GraphicsPanel panelGraph;
-	GraphicsConfiguration gc;
-	volatile BufferedImage image;
-	volatile Graphics2D canvas;
-	int cx, cy;
-	JTabbedPane tabPaneMain;
-	
-	Font botFont;
-	volatile int numBots;
-	volatile int selectedBot;  //the user has selected this bot graphically
-	volatile java.util.List <RobotIcon> robotIcons;  //contains boundary shapes around bots for click detection
-	volatile int[] xbeeID;
-	
-	Thread paintThread;
-	SelectionIndicator indicator;
-	WebcamLoader webcamLoader;
-	ColonetServerInterface csi;
-
-	
-	public void init () {
-		// Set the default look and feel - choose one
-        //String laf = UIManager.getSystemLookAndFeelClassName();
-		String laf = UIManager.getCrossPlatformLookAndFeelClassName();
-		//String laf = "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
-        try {
-            UIManager.setLookAndFeel(laf);
-        } catch (UnsupportedLookAndFeelException exc) {
-            System.err.println ("Warning: UnsupportedLookAndFeel: " + laf);
-        } catch (Exception exc) {
-            System.err.println ("Error loading " + laf + ": " + exc);
-        }
-		// We should invoke and wait to avoid browser display difficulties
-		Runnable r = new Runnable() {
-			public void run() {
-				createAndShowGUI();
-			}
-		};
-		try {
-			SwingUtilities.invokeAndWait(r);
-		} catch (InterruptedException e) {
-			//Not really sure why we would be in this situation
-			System.out.println("InterruptedException in init: " + e);
-		} catch (java.lang.reflect.InvocationTargetException e) {
-			//This could happen for various reasons if there is a problem in createAndShowGUI
-			e.printStackTrace();
-		}
-	}
-	
-	public void destroy () {
-		try { paintThread.interrupt(); } catch (Exception e) { }
-		try { indicator.interrupt(); } catch (Exception e) { }
-	}
-
-	private synchronized void createAndShowGUI () {
-		// init graphical elements
-		// Get the graphics configuration of the screen to create a buffer
-		gc = GraphicsEnvironment.getLocalGraphicsEnvironment()
-			.getDefaultScreenDevice().getDefaultConfiguration();
-		image = gc.createCompatibleImage(CANVAS_SIZE,CANVAS_SIZE);
-		canvas = image.createGraphics();
-		canvas.setStroke(new BasicStroke(2));  //set pen width
-		panelGraph = new GraphicsPanel(image, false);  //set automatic double-buffering to false. we are doing it manually.
-		panelWebcam = new WebcamPanel();
-		tabPaneMain = new JTabbedPane();
-		tabPaneMain.add(panelWebcam, "Webcam");
-		//tabPaneMain.add(panelGraph, "Graph");
-		
-		// Calculate center of canvas
-		cx = image.getWidth() / 2;
-		cy = image.getHeight() / 2;
-		
-		// Set up robots
-		botFont = new Font("Arial", Font.PLAIN, 14);
-		numBots = 0;
-		selectedBot = -1;
-		robotIcons = new ArrayList <RobotIcon> ();
-		
-		// Connection area
-		txtMatrix = new JTextArea();
-		txtMatrix.setBorder(BorderFactory.createTitledBorder("Input Matrix"));
-		txtInfo = new JTextArea();
-		txtInfo.setBorder(BorderFactory.createTitledBorder("Info"));
-		txtInfo.setEditable(false);
-		txtHost = new JTextField(this.getDocumentBase().getHost());
-		txtHost.setBorder(BorderFactory.createTitledBorder("Host"));
-		txtPort = new JTextField("10123");
-		txtPort.setBorder(BorderFactory.createTitledBorder("Port"));
-		btnConnect = new JButton("Connect");
-		btnGetXBeeIDs = new JButton("Get XBee IDs");
-		getRootPane().setDefaultButton(btnConnect);
-		lblConnectionStatus = new JLabel("Status: Offline");
-		panelConnect = new JPanel();
-		panelConnect.setLayout(new GridLayout(6,1));
-		panelConnect.add(lblConnectionStatus);
-		panelConnect.add(txtHost);
-		panelConnect.add(txtPort);
-		panelConnect.add(btnConnect);
-		//panelConnect.add(btnGetXBeeIDs);
-		panelServerInterface = new JPanel();
-		panelServerInterface.setLayout(new GridLayout(2,1));
-		panelServerInterface.add(panelConnect);
-		panelServerInterface.add(txtMatrix);
-	
-		// Robot direction panel
-		panelRobotDirection = new JPanel();
-		panelRobotDirectionButtons = new JPanel();
-		btnF = new JButton("^");
-		btnB = new JButton("v");
-		btnL = new JButton("<");
-		btnR = new JButton(">");
-		btnActivate = new JButton("o");
-		panelRobotDirectionButtons.setLayout(new GridLayout(1,5));
-		panelRobotDirectionButtons.add(btnActivate);
-		panelRobotDirectionButtons.add(btnF);
-		panelRobotDirectionButtons.add(btnB);
-		panelRobotDirectionButtons.add(btnL);
-		panelRobotDirectionButtons.add(btnR);
-		
-		imageVectorControl = gc.createCompatibleImage(VECTOR_CONTROLLER_WIDTH, VECTOR_CONTROLLER_HEIGHT);
-		vectorController = new VectorController(imageVectorControl);
-		panelRobotDirection.setLayout(new BorderLayout());
-		panelRobotDirection.add(vectorController, BorderLayout.CENTER);
-		panelRobotDirection.add(panelRobotDirectionButtons, BorderLayout.SOUTH);
-		
-		// Robot Control and Commands
-		panelRobotCommands = new JPanel();
-		panelRobotCommands.setLayout(new GridLayout(5,2));
-		cmbRobotNum = new JComboBox();
-		// Battery subset
-		batteryIcon = new BatteryIcon(25);
-		lblBattery = new JLabel(batteryIcon);
-		lblSelected = new JLabel("None");
-		// Command subset
-		setWaypoint = false;
-		setWaypointID = -1;
-		btnAssignID = new JButton("Assign ID");
-		btnCommand_MoveTo = new JButton("Move to ...");
-		btnCommand_MoveAll = new JButton("Move all ...");
-		btnCommand_StopTask = new JButton("Stop Current Task");
-		btnCommand_ResumeTask = new JButton("Resume Current Task");
-		btnCommand_ChargeNow = new JButton("Recharge Now");
-		btnCommand_StopCharging = new JButton("Stop Recharging");
-		panelRobotCommands.add(new JLabel("Select Robot to Control: "));
-		panelRobotCommands.add(cmbRobotNum);
-		panelRobotCommands.add(new JLabel("Battery Level: "));
-		panelRobotCommands.add(lblBattery);
-		panelRobotCommands.add(new JLabel("Selected Icon: "));
-		panelRobotCommands.add(lblSelected);
-		panelRobotCommands.add(btnAssignID);
-		panelRobotCommands.add(new JLabel(""));
-		panelRobotCommands.add(btnCommand_MoveTo);
-		panelRobotCommands.add(btnCommand_MoveAll);
-		//panelRobotCommands.add(btnCommand_StopTask);
-		//panelRobotCommands.add(btnCommand_ResumeTask);
-		//panelRobotCommands.add(btnCommand_ChargeNow);
-		//panelRobotCommands.add(btnCommand_StopCharging);
-		panelRobotControl = new JPanel();
-		panelRobotControl.setLayout(new GridLayout(2,1));
-		panelRobotControl.add(panelRobotDirection);
-		panelRobotControl.add(panelRobotCommands);
-		
-		
-		// Task Manager
-		panelTaskManager = new JPanel();
-		panelTaskManager.setLayout(new BorderLayout());
-		taskListModel = new DefaultListModel();
-		taskList = new JList(taskListModel);
-		taskList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-		taskList.setSelectedIndex(0);
-		spTaskManager = new JScrollPane(taskList);
-		panelTaskManagerControls = new JPanel();
-		panelTaskManagerControls.setLayout(new GridLayout(1,4));
-		panelTaskManagerControlsPriority = new JPanel();
-		panelTaskManagerControlsPriority.setLayout(new GridLayout(1,2));
-		btnAddTask = new JButton("Add...");
-		btnRemoveTask = new JButton("Remove");
-		btnMoveTaskUp = new JButton("^");
-		btnMoveTaskDown = new JButton("v");
-		btnUpdateTasks = new JButton("Update");
-		panelTaskManagerControlsPriority.add(btnMoveTaskUp);
-		panelTaskManagerControlsPriority.add(btnMoveTaskDown);
-		panelTaskManagerControls.add(btnAddTask);
-		panelTaskManagerControls.add(btnRemoveTask);
-		panelTaskManagerControls.add(btnUpdateTasks);
-		panelTaskManagerControls.add(panelTaskManagerControlsPriority);
-		panelTaskManager.add(spTaskManager, BorderLayout.CENTER);
-		panelTaskManager.add(panelTaskManagerControls, BorderLayout.SOUTH);
-		panelTaskManager.add(new JLabel("Current Task Queue"), BorderLayout.NORTH);
-		taskAddWindow = new TaskAddWindow();
-		
-		// Message log
-		log = new JTextArea();
-		spLog = new JScrollPane(log,
-			ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, 
-			ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
-		spLog.setBorder(BorderFactory.createTitledBorder("Log"));
-		spLog.setPreferredSize(new Dimension(0, 120));
-		log.setEditable(false);
-		
-		// Main control mechanism
-		panelControl = new JPanel();
-		panelControl.setLayout(new GridLayout(1,1));
-		tabPaneControl = new JTabbedPane(JTabbedPane.TOP);
-		tabPaneControl.setPreferredSize(new Dimension(VECTOR_CONTROLLER_WIDTH, 0));
-		tabPaneControl.addTab("Connection", panelServerInterface);
-		tabPaneControl.addTab("Robots", panelRobotControl);
-		tabPaneControl.addTab("Tasks", panelTaskManager);
-		panelControl.add(tabPaneControl);
-		
-		// Set up elements in the south
-		panelSouth = new JPanel();
-		panelSouth.setLayout(new GridLayout(1,2));
-		//panelSouth.add(spLog);
-
-		// Put all elements in the ContentPane
-		this.getContentPane().setLayout(new BorderLayout());
-		this.getContentPane().add(tabPaneMain, BorderLayout.CENTER);
-		this.getContentPane().add(panelSouth, BorderLayout.SOUTH);
-		this.getContentPane().add(panelControl, BorderLayout.EAST);
-		this.setVisible(true);
-		
-		/* Add all listeners here */
-		// Task Management
-		btnAddTask.addActionListener(this);
-		btnRemoveTask.addActionListener(this);
-		btnMoveTaskUp.addActionListener(this);
-		btnMoveTaskDown.addActionListener(this);
-		btnUpdateTasks.addActionListener(this);
-		// Robot Control
-		btnF.addActionListener(this);
-		btnB.addActionListener(this);
-		btnL.addActionListener(this);
-		btnR.addActionListener(this);
-		btnF.addKeyListener(this);
-		btnB.addKeyListener(this);
-		btnL.addKeyListener(this);
-		btnR.addKeyListener(this);
-		btnActivate.addActionListener(this);
-		btnActivate.addKeyListener(this);
-		cmbRobotNum.addKeyListener(this);
-		btnCommand_MoveTo.addActionListener(this);
-		btnCommand_MoveAll.addActionListener(this);
-		btnCommand_StopTask.addActionListener(this);
-		btnCommand_ResumeTask.addActionListener(this);
-		btnCommand_ChargeNow.addActionListener(this);
-		btnCommand_StopCharging.addActionListener(this);
-		// Other
-		btnConnect.addActionListener(this);
-		btnGetXBeeIDs.addActionListener(this);
-		btnAssignID.addActionListener(this);
-		panelWebcam.addMouseListener(this);	
-				
-		// Set up animation threads
-		indicator = new SelectionIndicator(canvas);
-		indicator.setRadius(RADIUS+3, 15);  //a tad more than the bot radius
-	
-	}
-	
-	public void run () {
-		while (true) {
-			repaint();
-			try { 
-				Thread.sleep(90);
-			} catch (InterruptedException e) {
-				return;
-			}
-		}
-	}
-	
-	public void paint (Graphics g) {
-	    super.paint(g);
-	}
-	
-	public void update (Graphics g) {
-	    paint(g);
-	}
-		
-	/** 
-	* Gets the JTextArea used for storing the activity log. This method returns a reference to the 
-	* JTextArea that stores the log. The log can contain any activity that is revelant to the use
-	* of the applet, and may optionally display debugging information.
-	*
-	* @return the JTextArea where BOM matrix information is stored.
-	*/ 
-	public JTextArea getLog () {
-		return log;
-	}
-	
-	/** 
-	* Gets the JTextArea used for storing the BOM matrix data. This method returns a reference to the 
-	* JTextArea that stores the BOM matrix. The values in the matrix are stored as integers separated 
-	* by spaces, and the lines should be separated by a newline.
-	* 
-	* @return the JTextArea where BOM matrix information is stored.
-	*/
-	public JTextArea getMatrixInput () {
-		return txtMatrix;
-	}
-	
-	/**
-	* Parses a String containing BOM matrix information.
-	* The ColonetServerInterface receives lines of the BOM matrix.  (For encoding 
-	* information, see the ColonetServerInterface documentation.)  The entire matrix is passed
-	* to the client when requested. This method takes a string of the form 
-	* "[command code] [command code] [number of robots] [data0] [data1] ..."
-	* with tokens separated by spaces and containing no brackets.  
-	* The [command code]s are predefined values identifying this String as a BOM data
-	* String, [number of robots] is an integer, and the values that follow are 
-	* the sensor readings of the robots in order, starting with robot 0.  Only [number of robots]^2
-	* data entries will be read.  The matrix values are saved locally until the next String is parsed.
-	* 
-	*
-	* @param line the String containing BOM matrix information.
-	* @throws ArrayIndexOutOfBoundsException if there are fewer than [number of robots]^2 data entries in the String
-	*/
-	public void parseMatrix (String line) {
-		txtMatrix.setText("");
-		String [] str = line.split(" ");
-		int num = Integer.parseInt(str[2]);
-		for (int i = 0; i < num; i++) {
-			for (int j = 0; j < num; j++) {
-				String next = str[3 + i*num + j];
-				if (next.equals("-1"))
-					txtMatrix.append("-");
-				else 
-					txtMatrix.append(next);
-				if (j < num - 1) 
-					txtMatrix.append(" ");
-			}
-			if (i < num - 1) 
-				txtMatrix.append("\n");
-		}
-		
-	}
-	
-	public void connect () {
-	    webcamLoader = new WebcamLoader(this);
-		dataUpdater = new DataUpdater();
-		paintThread = new Thread(this, "paintThread");
-		csi = new ColonetServerInterface(this);
-		csi.connect(txtHost.getText(), txtPort.getText());
-		if (!csi.isReady())
-			return;
-		btnConnect.setEnabled(false);
-		lblConnectionStatus.setText("Status: Connected");
-		//paintThread.start();
-		dataUpdater.start();
-		webcamLoader.start();
-	}
-	
-	public void disconnect () {
-	    btnConnect.setEnabled(true);
-	    lblConnectionStatus.setText("Status: Disconnected");
-	    try { paintThread.interrupt(); } catch (Exception e) { }
-		try { indicator.interrupt(); } catch (Exception e) { }
-		
-	}
-	
-	/**
-	* Parses a String containing a task queue update.
-	* Format is currently not specified.
-	* This method currently does nothing.
-	*
-	* @param line the String containing task queue update information.
-	*/
-	public void parseQueue (String line) {
-		log.append("Got queue update\n");
-		//TODO: display new queue data in tasks tab
-	}
-	
-	/**
-	* Parses a String containing XBee ID values.
-	* The ColonetServerInterface receives Strings of XBee information.  (For encoding 
-	* information, see the ColonetServerInterface documentation.)  This method takes
-	* a string of the form "[command code] [command code] [number of robots] [id0] [id1] ..."
-	* with tokens separated by spaces and containing no brackets.  
-	* The [command code]s are predefined values identifying this String as an XBee
-	* ID String, [number of robots] is an integer, and the values that follow are 
-	* the IDs of the robots in order, starting with robot 0.  Only [number of robots] 
-	* will be read.  The ID values are saved locally until the next String is parsed.
-	* The purpose of having this list is to ensure that robots are properly identified for control purposes.
-	* This keeps robot identification consistent between sessions and prevents arbitrary assignment. 
-	*
-	* @param line the String containing XBee ID information.
-	* @throws ArrayIndexOutOfBoundsException if there are fewer than [number of robots] IDs in the String
-	* @see ColonetServerInterface#sendXBeeIDRequest()
-	*/
-	public void parseXBeeIDs (String line) {
-	
-		String [] str = line.split(" ");
-		int num = Integer.parseInt(str[2]);
-		xbeeID = new int[num];
-		for (int i = 0; i < num; i++)
-			xbeeID[i] = Integer.parseInt(str[i+3]);
-		
-		//update the list of robots to control
-		//but save the old value first
-		Object oldSelection = cmbRobotNum.getSelectedItem();
-		cmbRobotNum.removeAllItems();
-		cmbRobotNum.addItem(new String("   All   "));
-		for (int i = 0; i < num; i++)
-			cmbRobotNum.addItem(new String("" + xbeeID[i]));
-		cmbRobotNum.setSelectedItem(oldSelection);
-	}
-	
-	/**
-	* Parses a String containing battery information.
-	* The ColonetServerInterface receives Strings of battery information.  (For encoding 
-	* information, see the ColonetServerInterface documentation.)  This method takes
-	* a string of the form "[command code] [command code] [robot ID] [value]"
-	* with tokens separated by spaces and containing no brackets.  
-	* The [command code]s are predefined values identifying this String as a battery
-	* information String, [robot ID] is an integer, and [value] is a battery measurement.
-	* This updates the batery information for a single robot.
-	* 
-	*
-	* @param line the String containing battery information.
-	* @see ColonetServerInterface#sendBatteryRequest(int)
-	*/
-	public void parseBattery (String line) {
-		String [] str = line.split(" ");
-		int botNum = Integer.parseInt(str[2]);
-		int level = Integer.parseInt(str[3]);
-		int selected = -1;
-		try { 
-		    selected = Integer.parseInt((String)cmbRobotNum.getSelectedItem());
-		} catch (Exception e) {
-		}
-		if (selected == botNum) {
-			batteryIcon.setLevel(level);
-		}
-	}
-	
-	/**
-	* Parses a String containing visual robot position information along with 
-	* canonical ID assignments.
-	*/
-	public void parsePositions (String line) {
-		String [] str = line.split(" ");
-		java.util.List <RobotIcon> newList = new ArrayList <RobotIcon> ();
-		
-		for (int i = 2; i < str.length; i+=3) {
-			int id = Integer.parseInt(str[i]);
-			int x = Integer.parseInt(str[i+1]);
-			int y = Integer.parseInt(str[i+2]);
-			RobotIcon newIcon = new RobotIcon(id, x, y);
-			newList.add(newIcon);
-		}
-		
-		robotIcons = newList;
-	
-	}
-	
-	
-	//
-	// MouseListener methods
-	//
-	public void mouseExited(MouseEvent e) {
-	}
-	public void mouseEntered(MouseEvent e) {
-	}
-	public void mouseReleased(MouseEvent e) {
-	}
-	public void mouseClicked(MouseEvent e) {
-	}
-	public void mousePressed(MouseEvent e) {
-	
-	    // If we are selecting a waypoint (destination) for a specific bot
-	    if (setWaypoint && setWaypointID  >= 0) {
-	        setWaypoint = false;
-	        panelWebcam.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
-	        if (selectedBot < 0)
-	            return;
-	        
-	        RobotIcon r = robotIcons.get(selectedBot);
-	        r.destx = e.getX();
-	        r.desty = e.getY();
-	        
-	        csi.sendAbsoluteMove(r.id, r.destx, r.desty);
-	        
-	        return;
-	    }
-	    
-	    // If we are setting all waypoints
-	    if (setWaypoint) {
-	        setWaypoint = false;
-	        panelWebcam.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
-	        for (int i = 0; i < robotIcons.size(); i++) {
-	            RobotIcon r = robotIcons.get(i);
-	            r.destx = e.getX();
-	            r.desty = e.getY();
-	        }
-	        return;
-	    }
-	    
-	    // Otherwise, we are selecting a bot, or doing nothing
-		for (int i = 0; i < robotIcons.size(); i++) {
-		    RobotIcon r = robotIcons.get(i);
-		    if (r.contains(e.getX(), e.getY())) {
-		        selectedBot = i;
-		        lblSelected.setText(" " + r.id);
-		    }
-		}
-		repaint();
-	}
-	public void mouseDragged(MouseEvent e) {
-	}
-	public void mouseMoved(MouseEvent e) {
-	}
-	
-	//
-	// KeyListener methods
-	//
-	public void keyPressed (KeyEvent e) {
-		int code = e.getKeyCode();
-		if (code == KeyEvent.VK_UP) {
-			vectorController.setMaxForward();
-			vectorController.sendToServer();
-		} else if (code == KeyEvent.VK_DOWN) {
-			vectorController.setMaxReverse();
-			vectorController.sendToServer();
-		} else if (code == KeyEvent.VK_LEFT) {
-			vectorController.setMaxLeft();
-			vectorController.sendToServer();
-		} else if (code == KeyEvent.VK_RIGHT) {
-			vectorController.setMaxRight();
-			vectorController.sendToServer();
-		} else if (code == KeyEvent.VK_S) {
-			vectorController.setZero();
-			vectorController.sendToServer();
-		}
-	}
-	public void keyReleased (KeyEvent e) {
-	}
-	public void keyTyped (KeyEvent e) {
-	}
-	
-	
-	//
-	// ActionListener method
-	//
-	public void actionPerformed (ActionEvent e) {
-		Object source = e.getSource();
-		
-		// General Actions
-		if (source == btnConnect) {
-			connect();
-		} else if (source == btnGetXBeeIDs) {
-			csi.sendXBeeIDRequest();
-		} else if (source == btnAssignID) {
-		    String message;
-		    if (selectedBot < 0)
-		        return;
-		    int curID = robotIcons.get(selectedBot).id;
-		    if (curID < 0)
-		        message = "That robot is unidentified. Please specify its ID.";
-		    else
-		        message = "That robot has ID " + curID + ". You may reassign it now.";
-		    String result = JOptionPane.showInputDialog(this, message, "Robot Identification", JOptionPane.QUESTION_MESSAGE);
-		    if (result == null)
-		        return;
-	        int newID = -1;
-		    try {
-		        newID = Integer.parseInt(result);
-		    } catch (Exception ex) {
-		        csi.warn("Invalid ID.");
-		        return;
-		    }
-		    // Assign new ID and update display  
-			csi.sendIDAssignment(curID, newID);
-		    robotIcons.get(selectedBot).id = newID;
-		    robotIcons.get(selectedBot).color = Color.GREEN;
-		    lblSelected.setText(" " + newID);
-		    
-			
-		}
-		
-		// Robot Movement Controls
-		else if (source == btnF) {
-			vectorController.setMaxForward();
-			vectorController.sendToServer();
-		} else if (source == btnB) {
-			vectorController.setMaxReverse();
-			vectorController.sendToServer();
-		} else if (source == btnL) {
-			vectorController.setMaxLeft();
-			vectorController.sendToServer();
-		} else if (source == btnR) {
-			vectorController.setMaxRight();
-			vectorController.sendToServer();
-		} else if (source == btnActivate) {
-			vectorController.setZero();
-			vectorController.sendToServer();
-		}
-		// Robot Commands (non-movement)
-		else if (source == btnCommand_MoveTo) {
-		    if (selectedBot < 0)
-		        return;
-		    panelWebcam.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
-		    setWaypoint = true;
-		    setWaypointID = selectedBot;
-		    		
-		} else if (source == btnCommand_MoveAll) {
-		    panelWebcam.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
-		    setWaypoint = true;
-		    setWaypointID = -1;
-		    		
-		} else if (source == btnCommand_StopTask) {
-		
-		} else if (source == btnCommand_ResumeTask) {
-		
-		} else if (source == btnCommand_ChargeNow) {
-		
-		} else if (source == btnCommand_StopCharging) {
-		
-		}
-			
-		// Queue Management
-		else if (source == btnAddTask) {
-			taskAddWindow.prompt();
-		} else if (source == btnRemoveTask) {
-			if (taskList.getSelectedIndex() >= 0);
-				csi.sendQueueRemove(taskList.getSelectedIndex());
-			csi.sendQueueUpdate();
-		} else if (source == btnMoveTaskUp) {
-			csi.sendQueueReorder(taskList.getSelectedIndex(), taskList.getSelectedIndex() - 1);
-			csi.sendQueueUpdate();
-		} else if (source == btnMoveTaskDown) {
-			csi.sendQueueReorder(taskList.getSelectedIndex(), taskList.getSelectedIndex() + 1);
-			csi.sendQueueUpdate();
-		} else if (source == btnUpdateTasks) {
-			csi.sendQueueUpdate();
-		}
-	}
-	
-	/*
-	*	SelectionIndicator thread.
-	*	Graphical representation of the selection marker
-	*
-	*	step() and draw() are synchronized methods. step() is private and 
-	*	used to update the position of the crosshairs. draw() is called 
-	*	externally and should only run if all calculations in step() have
-	*	been completed.
-	*/
-	private class SelectionIndicator extends Thread {
-	
-		final int INDICATOR_DELAY = 180;
-		final double DTHETA = 0.4;    //larger values make the marker rotate faster
-		Graphics2D g;   //canvas to draw on
-		boolean running;
-		
-		int sx, sy;		//center
-		int r, dr;		//radius and width of marker
-		double theta;   //current angle
-		
-		volatile Polygon poly1, poly2, poly3, poly4;
-		
-		int px1, py1;
-		int rx1, ry1;
-		int px2, py2;
-		int rx2, ry2;
-		int px3, py3;
-		int rx3, ry3;
-		int px4, py4;
-		int rx4, ry4;
-		
-		int steps;
-	
-		public SelectionIndicator (Graphics2D g) {
-			super("SelectionIndicator");
-			this.g = g;
-			running = false;
-			steps = 0;
-			
-			theta = 0;
-			rx1 = 0; ry1 = 0;
-			px1 = 0; py1 = 0;
-			rx2 = 0; ry2 = 0;
-			px2 = 0; py2 = 0;
-			rx3 = 0; ry3 = 0;
-			px3 = 0; py3 = 0;
-			rx4 = 0; ry4 = 0;
-			px4 = 0; py4 = 0;
-		}
-		
-		public synchronized void setCenter (int sx, int sy) {
-			if (sx == this.sx && sy == this.sy) return;
-			this.sx = sx;
-			this.sy = sy;
-			steps = 0;
-		}
-		
-		public synchronized void setRadius (int r, int dr) {
-			this.r = r;
-			this.dr = dr;
-			steps = 0;
-		}
-		
-		public void run () {
-			running = true;
-			while (running) {
-				step();
-				try { 
-					Thread.sleep(INDICATOR_DELAY);
-				} catch (InterruptedException e) {
-					running = false;
-					return;
-				}
-			}
-		}
-		
-		private synchronized void step () {
-			Polygon poly1_new = new Polygon();
-			Polygon poly2_new = new Polygon();
-			Polygon poly3_new = new Polygon();
-			Polygon poly4_new = new Polygon();
-		
-			//the step
-			theta = (theta + DTHETA/Math.PI) % (Math.PI);
-			
-			//the calculation
-			//let p be the point of the pointy thing toward the center
-			//let r be the point at the opposite side
-			
-			//recalculate radius, if it will look cool, lolz
-			int newr = r;
-			if (steps < 100)
-			newr = (int)( r + 200/(steps+1) );
-			
-			//precompute values for dx and dy
-			int dx_inner = (int)(newr * Math.cos(theta));
-			int dy_inner = (int)(newr * Math.sin(theta));
-			int dx_outer = (int)((newr+dr) * Math.cos(theta));
-			int dy_outer = (int)((newr+dr) * Math.sin(theta));
-			
-			//calculate polygon constants
-			int dy_poly = (int)(dr/2 * Math.cos(theta));
-			int dx_poly = (int)(dr/2 * Math.sin(theta));
-			
-			//determine critical points
-			//kansas city shuffle!
-			px1 = sx + dx_inner;
-			py1 = sy - dy_inner;
-			rx1 = sx + dx_outer;
-			ry1 = sy - dy_outer;
-			px2 = sx - dx_inner;
-			py2 = sy + dy_inner;
-			rx2 = sx - dx_outer;
-			ry2 = sy + dy_outer;
-			px3 = sx - dy_inner;
-			py3 = sy - dx_inner;
-			rx3 = sx - dy_outer;
-			ry3 = sy - dx_outer;
-			px4 = sx + dy_inner;
-			py4 = sy + dx_inner;
-			rx4 = sx + dy_outer;
-			ry4 = sy + dx_outer;
-			
-			//create polygons
-			poly1_new.addPoint(px1, py1);
-			poly1_new.addPoint(rx1+dx_poly, ry1+dy_poly);
-			poly1_new.addPoint(rx1-dx_poly, ry1-dy_poly);
-			poly2_new.addPoint(px2, py2);
-			poly2_new.addPoint(rx2+dx_poly, ry2+dy_poly);
-			poly2_new.addPoint(rx2-dx_poly, ry2-dy_poly);
-			poly3_new.addPoint(px3, py3);
-			poly3_new.addPoint(rx3-dy_poly, ry3+dx_poly);
-			poly3_new.addPoint(rx3+dy_poly, ry3-dx_poly);
-			poly4_new.addPoint(px4, py4);
-			poly4_new.addPoint(rx4-dy_poly, ry4+dx_poly);
-			poly4_new.addPoint(rx4+dy_poly, ry4-dx_poly);
-			
-			//reassign updated polygons
-			poly1 = poly1_new;
-			poly2 = poly2_new;
-			poly3 = poly3_new;
-			poly4 = poly4_new;
-		
-			if (steps < 300) steps++;
-		}
-		
-		public synchronized void draw () {
-			if (!running) return;
-			g.setColor(Color.GRAY);
-			//draw polygons
-			g.fillPolygon(poly1);
-			g.fillPolygon(poly2);
-			g.fillPolygon(poly3);
-			g.fillPolygon(poly4);
-		}
-	
-	}
-	
-	/*
-	*	DataUpdater thread.
-	*   The purpose of this thread is to request data from the server at regular intervals.
-	*
-	*/
-	class DataUpdater extends Thread {
-		final int DATAUPDATER_DELAY = 2200;
-		
-		public DataUpdater () {
-			super("Colonet DataUpdater");
-		}
-		
-		public void run () {
-			String line;
-			while (true) {
-				try {
-					//request more data
-					if (csi != null && csi.isReady()) {
-                        csi.sendPositionRequest();
-						csi.sendXBeeIDRequest();
-						if (cmbRobotNum.getSelectedIndex() > 0) {
-						    String sel = (String) cmbRobotNum.getSelectedItem();
-						    int num = Integer.parseInt(sel);
-							csi.sendBatteryRequest(num);
-						}
-					}
-					Thread.sleep(DATAUPDATER_DELAY);
-				} catch (InterruptedException e) {
-					return;
-				} 
-			}
-		}
-
-	}
-	
-	/*
-	*	GraphicsPanel class
-	*	An extension of JPanel, designed for holding an image that will be repainted regularly.
-	*/
-	class GraphicsPanel extends JPanel {
-		protected Image img;
-	
-		public GraphicsPanel (Image img) {
-			super();
-			this.img = img;
-		}
-		
-		public GraphicsPanel (Image img, boolean isDoubleBuffered) {
-			super(isDoubleBuffered);
-			this.img = img;
-		}
-		
-		public void paint (Graphics g) {
-			// Place the buffered image on the screen, inside the panel
-			g.drawImage(img, 0, 0, Color.WHITE, this);
-		}
-	
-	}
-	
-	/*
-	*	WebcamPanel class
-	*	Enables more efficient image handling in a component-controlled environment
-	*/
-	class WebcamPanel extends JPanel {
-		int BORDER = 16;  // this is arbitrary. it makes the image look nice inside a border.
-		int BOT_RADIUS = 40;
-		volatile BufferedImage img;
-	
-		public WebcamPanel () {
-			super();
-		}
-		
-		public void setImage (BufferedImage newimg) {
-			if (img != null) {
-				img.flush();
-			}
-			System.gc();
-			img = newimg;
-		}
-		
-				
-		public void paint (Graphics g) {
-			
-			if (img == null)
-				return;
-			// Place the image on the screen, inside the panel
-			
-			int maxWidth = getWidth() - 2*BORDER;
-			int maxHeight = getHeight() - 2*BORDER;
-			double widthRatio = 1.0 * maxWidth / img.getWidth();
-			double heightRatio = 1.0 * maxHeight / img.getHeight();
-			int newWidth = 0;
-			int newHeight = 0;
-			int x = 0;
-			int y = 0;
-			
-			if (widthRatio > heightRatio) {  //height is the limiting factor
-			    newHeight = maxHeight;
-			    newWidth = img.getWidth() * maxHeight / img.getHeight();
-			    y = BORDER;
-			    x = (maxWidth - newWidth) / 2 + BORDER;
-			} else {  //width is the limiting factor
-			    newWidth = maxWidth;
-			    newHeight = img.getHeight() * maxWidth / img.getWidth();
-			    x = BORDER;
-			    y = (maxHeight - newHeight) / 2 + BORDER;
-			}
-			
-			Image imgScaled = img.getScaledInstance(newWidth, newHeight, Image.SCALE_FAST);
-			g.drawImage(imgScaled, x, y, this);
-			
-						
-			// Draw Identifiers
-			if (robotIcons == null)
-				return;
-			
-			((Graphics2D)g).setStroke(new BasicStroke(2));
-			for (int i = 0; i < robotIcons.size(); i++) {
-				RobotIcon r = robotIcons.get(i);
-				g.setColor(r.color);
-				if (widthRatio > heightRatio) {
-				    
-				
-				} else {
-				    
-				}
-				g.drawOval(r.x-RADIUS, r.y-RADIUS, 2*r.RADIUS, 2*r.RADIUS);
-				// If the robot has a destination, draw the vector
-				if (r.destx >= 0) {
-				    g.drawLine(r.x, r.y, r.destx, r.desty);
-				}
-			}
-			
-			// Identify currently-selected robot
-			if (selectedBot == -1)
-			    return;
-			g.setColor(Color.YELLOW);
-			RobotIcon r = robotIcons.get(selectedBot);
-			g.drawOval(r.x-RADIUS-6, r.y-RADIUS-6, 2*r.RADIUS+12, 2*r.RADIUS+12);
-			
-		}
-	
-	}
-	
-	/*
-	*	WebcamLoader class
-	*	Handles the loading of the webcam image.
-	*/
-	class WebcamLoader extends Thread 
-	{
-		final int WEBCAMLOADER_DELAY = 300;
-		final String IMAGE_PATH = "http://roboclub9.frc.ri.cmu.edu/colonet.jpg";
-				
-		URL imagePath;
-		
-		MediaTracker mt;
-		BufferedImage image;
-		Random rand;
-		
-		public WebcamLoader (JApplet applet)
-		{
-			super("ColonetWebcamLoader");
-			mt = new MediaTracker(applet);
-			ImageIO.setUseCache(false);
-			rand = new Random();
-		}
-		
-		public void run ()
-		{
-			while (true) {
-				try {
-					Thread.sleep(WEBCAMLOADER_DELAY);
-					if (image != null) 
-						image.flush();
-					System.gc();
-					try {
-				        imagePath = new URL(IMAGE_PATH + "?rand=" + rand.nextInt(50000));
-			        } catch (MalformedURLException e) {
-				        System.out.println("Malformed URL: could not form URL from: [" + IMAGE_PATH + "]\n");
-			        }
-					image = ImageIO.read(imagePath);
-					// The MediaTracker waitForID pauses the thread until the image is loaded.
-					// We don't want to display a half-downloaded image.
-					mt.addImage(image, 1);
-					mt.waitForID(1);
-					mt.removeImage(image);
-					// Save
-					panelWebcam.setImage(image);
-				} catch (InterruptedException e) {
-					return;
-				} catch (java.security.AccessControlException e) {
-					csi.warn("Could not load webcam.\n" + e);
-					return;
-				} catch (IOException e) {
-					log.append("IOException while trying to load image.");
-				}
-			}
-		}
-		
-	}
-	
-	/*
-	*  RobotIcon class
-	*  Provides a means for graphically representing and keeping track of webcam bots.
-	*/
-	class RobotIcon {
-		public final int RADIUS = 30;
-		public final int CLOSE = 80;
-		
-		public int x, y;
-		public int destx, desty;
-		public int id;
-		public Color color;
-		
-		public RobotIcon (int id, int x, int y) {
-			this.color = Color.RED;
-			this.x = x;
-			this.y = y;
-			this.id = id;
-			this.destx = -1;
-			this.desty = -1;
-		}
-		
-		/**
-		*  Relocates this RobotIcon to a new coordinate point.
-		*
-		*/
-		public void move (int newX, int newY) {
-			this.x = newX;
-			this.y = newY;
-		}
-		
-		/**
-		*  Determines if a given point is within a reasonable range of the current location
-		*  to be considered the same robot when moving. The threshold is determined by the 
-		*  CLOSE value.
-		*
-		*  @returns Whether or not the given point is reasonably close to the current location.
-		*
-		*/
-		public boolean isClose (int nx, int ny) {
-			int dist = (int) Point.distance(this.x, this.y, nx, ny);
-			return (dist < CLOSE);
-		}
-		
-		/**
-		*  Determines whether a given point is within the rectangle that circumscribes the
-		*  robot's circlular icon. Used for clicking on robots in webcam view.
-        *
-        */
-		public boolean contains (int px, int py) {
-		    Rectangle rect = new Rectangle(x-RADIUS, y-RADIUS, 2*RADIUS, 2*RADIUS);
-		    return rect.contains(px, py);
-		}
-		
-		public String toString () {
-			String s = "RobotIcon at (" + x + "," + y + "), id " + id;
-			return s;
-		}
-		
-	}
-
-	
-	/*
-	*	VectorController class
-	*	Manages robot motion control graphically
-	*/
-	class VectorController extends GraphicsPanel implements MouseListener, MouseMotionListener {
-		int x, y, cx, cy;
-		int width, height;
-		int side;
-		
-		public VectorController (Image img) {
-			super (img);
-			width = img.getWidth(null);
-			height = img.getHeight(null);
-			cx = img.getWidth(null)/2;
-			cy = img.getHeight(null)/2;
-			x = cx;
-			y = cy;
-			if (width < height)
-				side = width;
-			else
-				side = height;
-			this.addMouseListener(this);
-			this.addMouseMotionListener(this);
-		}
-		
-		public void setPoint (int x, int y) {
-			if (!isValidPoint(x, y))
-				return;
-			this.x = x;
-			this.y = y;
-			repaint();
-		}
-		
-		public boolean isValidPoint (int x, int y) {
-			double xterm = Math.pow(1.0*(x - cx)/(side/2), 2);
-			double yterm = Math.pow(1.0*(y - cy)/(side/2), 2);
-			return (xterm + yterm <= 1);
-		}
-		
-		public void notifyMouseEvent (MouseEvent e, boolean send) {
-			if (!isValidPoint(e.getX(), e.getY()))
-				return;
-			vectorController.setPoint(e.getX(), e.getY());
-			vectorController.repaint();
-			if (send)
-				vectorController.sendToServer();
-		}
-		
-		public void mouseExited(MouseEvent e) {
-		}
-		public void mouseEntered(MouseEvent e) {
-		}
-		public void mouseReleased(MouseEvent e) {
-			this.notifyMouseEvent(e, true);
-		}
-		public void mouseClicked(MouseEvent e) {
-			this.notifyMouseEvent(e, false);
-		}
-		public void mousePressed(MouseEvent e) {
-		}
-		public void mouseDragged(MouseEvent e) {
-			vectorController.notifyMouseEvent(e, false);
-		}
-		public void mouseMoved(MouseEvent e) {
-		}
-		
-		public int getSpeed () {
-			int dx = x - cx;
-			int dy = y - cy;
-			int v = (int) Math.sqrt( Math.pow(dx, 2) + Math.pow(dy, 2) );
-			return v;
-		}
-		
-		/** 
-		* Returns the angle of the control vector in positive degrees west of north,
-		* or negative degrees east of north, whichever is less than or equal to
-		* 180 degrees total.
-		*/
-		public int getAngle () {
-			int dx = x - cx;
-			int dy = cy - y;
-			// find reference angle in radians
-			double theta = Math.atan2(Math.abs(dx), Math.abs(dy));
-			// transform to degrees
-			theta = theta * 180 / Math.PI;
-			// adjust for quadrant
-			if (dx < 0 && dy < 0)
-				theta = 90 + theta;
-			else if (dx < 0 && dy >= 0)
-				theta = 90 - theta;
-			else if (dx >= 0 && dy < 0)
-				theta = -90 - theta;
-			else
-				theta = -90 + theta;
-			return (int) theta;
-		}
-		
-		public void paint (Graphics g) {
-			g.setColor(Color.BLACK);
-			g.fillRect(0, 0, width, height);
-			((Graphics2D)g).setStroke(new BasicStroke(1));
-			g.setColor(Color.RED);
-			g.drawOval(cx-side/2, cy-side/2, side, side);
-			((Graphics2D)g).setStroke(new BasicStroke(2));
-			g.setColor(Color.GREEN);
-			g.drawLine(cx, cy, x, y);
-			g.fillOval(x-3, y-3, 6, 6);
-		}
-		
-		public void setMaxForward () {
-			setPoint(cx, cy - (side/2) + 1);
-		}
-		
-		public void setMaxReverse () {
-			setPoint(cx, cy + (side/2) - 1);
-		}
-		
-		public void setMaxLeft () {
-			setPoint(cx - (side/2) + 1, cy);
-		}
-		
-		public void setMaxRight () {
-			setPoint(cx + (side/2) - 1, cy);
-		}
-		
-		public void setZero () {
-			setPoint(cx, cy);
-		}
-		
-		public void sendToServer () {
-			System.out.println("Attempting to send angle = " + getAngle() + ", speed = " + getSpeed() + "");
-			String dest = ColonetServerInterface.GLOBAL_DEST;
-			if (cmbRobotNum != null && cmbRobotNum.getSelectedIndex() > 0) {
-				dest = (String)cmbRobotNum.getSelectedItem();
-			}
-			
-			if (csi != null) {
-				/*
-				csi.sendData(ColonetServerInterface.MOVE + " " + getSpeed() + " " + getAngle(), dest);
-				*/
-				
-				//Directional commands
-				if (x > cx && y == cy) {  //move right
-					csi.sendData(ColonetServerInterface.MOTOR2_SET + " 0 200", dest);
-					csi.sendData(ColonetServerInterface.MOTOR1_SET + " 1 200", dest);
-				} else if (x < cx && y == cy) {  //move left
-					csi.sendData(ColonetServerInterface.MOTOR2_SET + " 1 200", dest);
-					csi.sendData(ColonetServerInterface.MOTOR1_SET + " 0 200", dest);
-				} else if (x == cx && y > cy) {  //move forward
-					csi.sendData(ColonetServerInterface.MOTOR2_SET + " 0 225", dest);
-					csi.sendData(ColonetServerInterface.MOTOR1_SET + " 0 225", dest);
-				} else if (x == cx && y < cy) {  //move backward
-					csi.sendData(ColonetServerInterface.MOTOR2_SET + " 1 225", dest);
-					csi.sendData(ColonetServerInterface.MOTOR1_SET + " 1 225", dest);
-				} else if (x == cx && y == cy) {  //stop!
-					csi.sendData(ColonetServerInterface.MOTOR2_SET + " 1 0", dest);
-					csi.sendData(ColonetServerInterface.MOTOR1_SET + " 1 0", dest);
-				}
-			}
-		}
-	
-	}
-	
-	/*
-	*	TaskAddWindow class
-	*	A window that provides a simple way to add tasks to a task queue.
-	*/
-	class TaskAddWindow extends JFrame implements ActionListener, ListSelectionListener {
-		JPanel panelButtons;
-		JPanel panelParameters;
-		JPanel panelSouth;
-		JPanel panelSelection;
-		JButton btnSubmit;
-		JButton btnCancel;
-		DefaultListModel availableListModel;
-		JList availableList;
-		JScrollPane spAvailableTasks;
-		JTextArea txtDescription;
-		JTextField txtParameters;
-		
-		public TaskAddWindow () {
-			super("Add a Task");
-			super.setSize(500,500);
-			super.setLayout(new BorderLayout());
-			
-			// set up buttons
-			btnSubmit = new JButton("Submit");
-			btnCancel = new JButton("Cancel");
-			panelButtons = new JPanel();
-			panelButtons.setLayout(new FlowLayout());
-			panelButtons.add(btnSubmit);
-			panelButtons.add(btnCancel);
-			this.getRootPane().setDefaultButton(btnSubmit);
-			
-			// set up task list
-			availableListModel = new DefaultListModel();
-			availableListModel.addElement("Map the Environment");
-			availableListModel.addElement("Clean Up Chemical Spill");
-			availableListModel.addElement("Grow Plants");
-			availableListModel.addElement("Save the Cheerleader");
-			availableListModel.addElement("Save the World");
-			availableList = new JList(availableListModel);
-			availableList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-			availableList.setSelectedIndex(-1);
-			spAvailableTasks = new JScrollPane(availableList);
-			spAvailableTasks.setBorder(BorderFactory.createTitledBorder("Select A Task"));
-			txtDescription = new JTextArea();
-			txtDescription.setEditable(false);
-			txtDescription.setLineWrap(true);
-			txtDescription.setWrapStyleWord(true);
-			txtDescription.setBorder(BorderFactory.createTitledBorder("Description"));
-			
-			//set up parameter area
-			panelParameters = new JPanel();
-			panelParameters.setLayout(new BorderLayout());
-			txtParameters = new JTextField();
-			panelParameters.add(new JLabel("Optional parameters for this task: "), BorderLayout.WEST);
-			panelParameters.add(txtParameters);
-			
-			// assemble objects
-			panelSelection = new JPanel();
-			panelSelection.setLayout(new GridLayout(1,2));
-			panelSelection.add(spAvailableTasks);
-			panelSelection.add(txtDescription);
-			
-			panelSouth = new JPanel();
-			panelSouth.setLayout(new GridLayout(2,1));
-			panelSouth.add(panelParameters);
-			panelSouth.add(panelButtons);
-			
-			this.getContentPane().add(panelSouth, BorderLayout.SOUTH);
-			this.getContentPane().add(panelSelection, BorderLayout.CENTER);
-			this.setLocationRelativeTo(null);
-			
-			// add listeners here
-			availableList.addListSelectionListener(this);
-			btnSubmit.addActionListener(this);
-			btnCancel.addActionListener(this);
-		}
-		
-		public void prompt () {
-			this.setVisible(true);
-		}
-		
-		private String getDescription (int index) {
-			if (index < 0)
-				return "";
-			switch (index) {
-				case 0: return "SLAM and junk";
-				case 1: return "I'm not sure this works";
-				case 2: return "Push them into the light";
-				case 3: return "...";
-				case 4: return "...";
-			
-				default: return "Task not recognized";
-			}
-		}
-		
-		public void actionPerformed (ActionEvent e) {
-			Object source = e.getSource();
-			if (source == btnSubmit) {
-				txtParameters.setText(txtParameters.getText().trim());
-				
-				
-				this.setVisible(false);
-			} else if (source == btnCancel) {
-				this.setVisible(false);
-			}
-		}
-		
-		public void valueChanged (ListSelectionEvent e) {
-			int index = availableList.getSelectedIndex();
-			if (index >= 0)
-				txtDescription.setText(getDescription(index));
-		}
-	
-	}
-	
-	/*
-	*  BatteryIcon class
-	*  Graphical representation of battery level
-	*/
-	class BatteryIcon implements Icon {
-		private int width;
-	    private int height;
-	    private int level;
-	    
-		/** 
-		* Constructs a new BatteryIcon with all default parameters.
-		* Default width and height are 50.
-		* Default level is 100.
-		*/
-	    public BatteryIcon(){
-	    	this(100, 50, 50);
-	    }
-	    
-		/** 
-		* Constructs a new BatteryIcon with default width and height, and with the specified level.
-		* Default width and height are 50.
-		*/
-	    public BatteryIcon(int startLevel){
-	    	this(startLevel, 50, 50);
-	    }
-	    
-		/** 
-		* Constructs a new BatteryIcon with the specified level, width, and height.
-		*/
-	    public BatteryIcon(int startLevel, int w, int h){
-	    	level = startLevel;
-	    	width = w;
-	    	height = h;
-	    }
-	    
-	    public void paintIcon(Component c, Graphics g, int x, int y) {
-	        Graphics2D g2d = (Graphics2D) g.create();
-	        //clear the background
-	        g2d.setColor(Color.WHITE);
-	        g2d.fillRect(x + 1, y + 1, width - 2, height - 2);
-	        //outline
-	        g2d.setColor(Color.BLACK);
-	        g2d.drawRect((int)(x + width*.3), y + 2, (int)(width*.4), height - 4);
-	        //battery life rectangle
-	        g2d.setColor(Color.GREEN);
-	        int greenX = (int)(x + 1 + width*.3);
-	        int greenY = (int)((y+3) + Math.abs(level-100.0)*(height-6)/(100));
-	        int greenWidth = (int)(width*.4 - 2)+1;
-	        int greenHeight = 1+(int)(level-0.0)*(height-6)/(100);
-	        g2d.fillRect(greenX, greenY, greenWidth, greenHeight);
-	        //text
-	        g2d.setColor(Color.BLACK);
-	        g2d.drawString(level + "%", greenX + greenWidth/2 - 10, greenY + greenHeight/2 + 5);
-	        
-	        g2d.dispose();
-	    }
-	    
-		/**
-		* Sets the battery level for this BatteryIcon. The level should be given in raw form, i.e. 0-255 directly 
-		* from the robot. The value will be converted to a representative percentage automatically.
-		*
-		* @param newLevel the new battery reading from the robot that this BatteryIcon will display.
-		*/
-	    public void setLevel(int newLevel) {
-	    	level = convert(newLevel);
-	    	repaint();
-	    	System.out.println("Updated level to " + level);
-	    }
-		
-	    public int getIconWidth() {
-	        return width;
-	    }
-	    
-	    public int getIconHeight() {
-	        return height;
-	    }
-		
-		/**
-		* Converts a robot battery reading into representable form.
-		* Readings from the robot are returned as raw values, 0-255. This method converts the reading into a value
-		* from 0 to 100 so that the practical remaining charge is represented.
-		*
-		* @param level The battery level as returned by the robot.
-		* @returns The representable battery percentage.
-		*/
-		private int convert (int level) {
-			// TODO: make this a forreals conversion.
-			return (int) (100.0 * level / 128);
-		}
-		
-	}
-
-
-
-}
Index: trunk/code/projects/colonet/client/Colonet.java
===================================================================
--- trunk/code/projects/colonet/client/Colonet.java	(nonexistent)
+++ trunk/code/projects/colonet/client/Colonet.java	(revision 476)
@@ -0,0 +1,1523 @@
+//
+//  Colonet.java
+//
+
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.imageio.*;
+import java.awt.*;
+import java.awt.image.*;
+import java.awt.event.*;
+import java.net.*;
+import java.io.*;
+import java.util.*;
+
+
+/**
+*	The Colonet Graphical User Interface Applet for use locally and over an internet connection.
+*	@author Gregory Tress
+*	
+*	To generate javadoc on this file or other java files, use javadoc *.java -d doc, where doc
+*	is the name of the folder into which the files should be written.
+*/
+public class Colonet extends JApplet implements ActionListener, MouseInputListener, KeyListener, Runnable {
+
+	// Used for images
+	final int CANVAS_SIZE = 500;  //the applet may be slow if the canvas gets too large
+	final int BUFFER = 50;
+	final int RADIUS = 30;
+	
+	//Used for the robot controller
+	final int VECTOR_CONTROLLER_HEIGHT = 220;
+	final int VECTOR_CONTROLLER_WIDTH = 350;
+	
+
+	// Connection
+	JTextField txtHost;				
+	JTextField txtPort;				
+	JButton btnConnect;	
+	JButton btnGetXBeeIDs;
+	JLabel lblConnectionStatus;
+	JTextArea txtMatrix;
+	JTextArea txtInfo; 
+	JPanel panelConnect;
+	JPanel panelServerInterface;
+	Socket socket;					
+	OutputStreamWriter out;
+	DataUpdater dataUpdater;  
+	
+	// South
+	JPanel panelSouth;
+	JTextArea log;
+	JScrollPane spLog;
+	
+	// Control
+	JPanel panelControl;
+	JTabbedPane tabPaneControl;
+	JPanel panelRobotControl;
+	JPanel panelRobotDirection;
+	JPanel panelRobotDirectionButtons;
+	JPanel panelRobotCommands;
+	JButton btnF, btnB, btnL, btnR, btnActivate;
+	JComboBox cmbRobotNum;
+	JLabel lblBattery;
+	JLabel lblSelected;
+	BatteryIcon batteryIcon;
+	JPanel panelBattery;
+	VectorController vectorController;
+	BufferedImage imageVectorControl;
+	JButton btnAssignID;
+	boolean setWaypoint;
+	int setWaypointID;
+	JButton btnCommand_MoveTo;
+	JButton btnCommand_MoveAll;
+	JButton btnCommand_StopTask;
+	JButton btnCommand_ResumeTask;
+	JButton btnCommand_ChargeNow;
+	JButton btnCommand_StopCharging;
+	
+	// Task Manager
+	JPanel panelTaskManager;
+	JScrollPane spTaskManager;
+	JPanel panelTaskManagerControls;
+	JPanel panelTaskManagerControlsPriority;
+	DefaultListModel taskListModel;
+	JList taskList;
+	JButton btnAddTask;
+	JButton btnRemoveTask;
+	JButton btnMoveTaskUp;
+	JButton btnMoveTaskDown;
+	JButton btnUpdateTasks;
+	TaskAddWindow taskAddWindow;
+	
+	//Webcam
+	WebcamPanel panelWebcam;
+	GraphicsPanel panelGraph;
+	GraphicsConfiguration gc;
+	volatile BufferedImage image;
+	volatile Graphics2D canvas;
+	int cx, cy;
+	JTabbedPane tabPaneMain;
+	
+	Font botFont;
+	volatile int numBots;
+	volatile int selectedBot;  //the user has selected this bot graphically
+	volatile java.util.List <RobotIcon> robotIcons;  //contains boundary shapes around bots for click detection
+	volatile int[] xbeeID;
+	
+	Thread paintThread;
+	SelectionIndicator indicator;
+	WebcamLoader webcamLoader;
+	ColonetServerInterface csi;
+
+	
+	public void init () {
+		// Set the default look and feel - choose one
+        //String laf = UIManager.getSystemLookAndFeelClassName();
+		String laf = UIManager.getCrossPlatformLookAndFeelClassName();
+		//String laf = "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
+        try {
+            UIManager.setLookAndFeel(laf);
+        } catch (UnsupportedLookAndFeelException exc) {
+            System.err.println ("Warning: UnsupportedLookAndFeel: " + laf);
+        } catch (Exception exc) {
+            System.err.println ("Error loading " + laf + ": " + exc);
+        }
+		// We should invoke and wait to avoid browser display difficulties
+		Runnable r = new Runnable() {
+			public void run() {
+				createAndShowGUI();
+			}
+		};
+		try {
+			SwingUtilities.invokeAndWait(r);
+		} catch (InterruptedException e) {
+			//Not really sure why we would be in this situation
+			System.out.println("InterruptedException in init: " + e);
+		} catch (java.lang.reflect.InvocationTargetException e) {
+			//This could happen for various reasons if there is a problem in createAndShowGUI
+			e.printStackTrace();
+		}
+	}
+	
+	public void destroy () {
+		try { paintThread.interrupt(); } catch (Exception e) { }
+		try { indicator.interrupt(); } catch (Exception e) { }
+	}
+
+	private synchronized void createAndShowGUI () {
+		// init graphical elements
+		// Get the graphics configuration of the screen to create a buffer
+		gc = GraphicsEnvironment.getLocalGraphicsEnvironment()
+			.getDefaultScreenDevice().getDefaultConfiguration();
+		image = gc.createCompatibleImage(CANVAS_SIZE,CANVAS_SIZE);
+		canvas = image.createGraphics();
+		canvas.setStroke(new BasicStroke(2));  //set pen width
+		panelGraph = new GraphicsPanel(image, false);  //set automatic double-buffering to false. we are doing it manually.
+		panelWebcam = new WebcamPanel();
+		tabPaneMain = new JTabbedPane();
+		tabPaneMain.add(panelWebcam, "Webcam");
+		//tabPaneMain.add(panelGraph, "Graph");
+		
+		// Calculate center of canvas
+		cx = image.getWidth() / 2;
+		cy = image.getHeight() / 2;
+		
+		// Set up robots
+		botFont = new Font("Arial", Font.PLAIN, 14);
+		numBots = 0;
+		selectedBot = -1;
+		robotIcons = new ArrayList <RobotIcon> ();
+		
+		// Connection area
+		txtMatrix = new JTextArea();
+		txtMatrix.setBorder(BorderFactory.createTitledBorder("Input Matrix"));
+		txtInfo = new JTextArea();
+		txtInfo.setBorder(BorderFactory.createTitledBorder("Info"));
+		txtInfo.setEditable(false);
+		txtHost = new JTextField(this.getDocumentBase().getHost());
+		txtHost.setBorder(BorderFactory.createTitledBorder("Host"));
+		txtPort = new JTextField("10123");
+		txtPort.setBorder(BorderFactory.createTitledBorder("Port"));
+		btnConnect = new JButton("Connect");
+		btnGetXBeeIDs = new JButton("Get XBee IDs");
+		getRootPane().setDefaultButton(btnConnect);
+		lblConnectionStatus = new JLabel("Status: Offline");
+		panelConnect = new JPanel();
+		panelConnect.setLayout(new GridLayout(6,1));
+		panelConnect.add(lblConnectionStatus);
+		panelConnect.add(txtHost);
+		panelConnect.add(txtPort);
+		panelConnect.add(btnConnect);
+		//panelConnect.add(btnGetXBeeIDs);
+		panelServerInterface = new JPanel();
+		panelServerInterface.setLayout(new GridLayout(2,1));
+		panelServerInterface.add(panelConnect);
+		panelServerInterface.add(txtMatrix);
+	
+		// Robot direction panel
+		panelRobotDirection = new JPanel();
+		panelRobotDirectionButtons = new JPanel();
+		btnF = new JButton("^");
+		btnB = new JButton("v");
+		btnL = new JButton("<");
+		btnR = new JButton(">");
+		btnActivate = new JButton("o");
+		panelRobotDirectionButtons.setLayout(new GridLayout(1,5));
+		panelRobotDirectionButtons.add(btnActivate);
+		panelRobotDirectionButtons.add(btnF);
+		panelRobotDirectionButtons.add(btnB);
+		panelRobotDirectionButtons.add(btnL);
+		panelRobotDirectionButtons.add(btnR);
+		
+		imageVectorControl = gc.createCompatibleImage(VECTOR_CONTROLLER_WIDTH, VECTOR_CONTROLLER_HEIGHT);
+		vectorController = new VectorController(imageVectorControl);
+		panelRobotDirection.setLayout(new BorderLayout());
+		panelRobotDirection.add(vectorController, BorderLayout.CENTER);
+		panelRobotDirection.add(panelRobotDirectionButtons, BorderLayout.SOUTH);
+		
+		// Robot Control and Commands
+		panelRobotCommands = new JPanel();
+		panelRobotCommands.setLayout(new GridLayout(5,2));
+		cmbRobotNum = new JComboBox();
+		// Battery subset
+		batteryIcon = new BatteryIcon(25);
+		lblBattery = new JLabel(batteryIcon);
+		lblSelected = new JLabel("None");
+		// Command subset
+		setWaypoint = false;
+		setWaypointID = -1;
+		btnAssignID = new JButton("Assign ID");
+		btnCommand_MoveTo = new JButton("Move to ...");
+		btnCommand_MoveAll = new JButton("Move all ...");
+		btnCommand_StopTask = new JButton("Stop Current Task");
+		btnCommand_ResumeTask = new JButton("Resume Current Task");
+		btnCommand_ChargeNow = new JButton("Recharge Now");
+		btnCommand_StopCharging = new JButton("Stop Recharging");
+		panelRobotCommands.add(new JLabel("Select Robot to Control: "));
+		panelRobotCommands.add(cmbRobotNum);
+		panelRobotCommands.add(new JLabel("Battery Level: "));
+		panelRobotCommands.add(lblBattery);
+		panelRobotCommands.add(new JLabel("Selected Icon: "));
+		panelRobotCommands.add(lblSelected);
+		panelRobotCommands.add(btnAssignID);
+		panelRobotCommands.add(new JLabel(""));
+		panelRobotCommands.add(btnCommand_MoveTo);
+		panelRobotCommands.add(btnCommand_MoveAll);
+		//panelRobotCommands.add(btnCommand_StopTask);
+		//panelRobotCommands.add(btnCommand_ResumeTask);
+		//panelRobotCommands.add(btnCommand_ChargeNow);
+		//panelRobotCommands.add(btnCommand_StopCharging);
+		panelRobotControl = new JPanel();
+		panelRobotControl.setLayout(new GridLayout(2,1));
+		panelRobotControl.add(panelRobotDirection);
+		panelRobotControl.add(panelRobotCommands);
+		
+		
+		// Task Manager
+		panelTaskManager = new JPanel();
+		panelTaskManager.setLayout(new BorderLayout());
+		taskListModel = new DefaultListModel();
+		taskList = new JList(taskListModel);
+		taskList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+		taskList.setSelectedIndex(0);
+		spTaskManager = new JScrollPane(taskList);
+		panelTaskManagerControls = new JPanel();
+		panelTaskManagerControls.setLayout(new GridLayout(1,4));
+		panelTaskManagerControlsPriority = new JPanel();
+		panelTaskManagerControlsPriority.setLayout(new GridLayout(1,2));
+		btnAddTask = new JButton("Add...");
+		btnRemoveTask = new JButton("Remove");
+		btnMoveTaskUp = new JButton("^");
+		btnMoveTaskDown = new JButton("v");
+		btnUpdateTasks = new JButton("Update");
+		panelTaskManagerControlsPriority.add(btnMoveTaskUp);
+		panelTaskManagerControlsPriority.add(btnMoveTaskDown);
+		panelTaskManagerControls.add(btnAddTask);
+		panelTaskManagerControls.add(btnRemoveTask);
+		panelTaskManagerControls.add(btnUpdateTasks);
+		panelTaskManagerControls.add(panelTaskManagerControlsPriority);
+		panelTaskManager.add(spTaskManager, BorderLayout.CENTER);
+		panelTaskManager.add(panelTaskManagerControls, BorderLayout.SOUTH);
+		panelTaskManager.add(new JLabel("Current Task Queue"), BorderLayout.NORTH);
+		taskAddWindow = new TaskAddWindow();
+		
+		// Message log
+		log = new JTextArea();
+		spLog = new JScrollPane(log,
+			ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, 
+			ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+		spLog.setBorder(BorderFactory.createTitledBorder("Log"));
+		spLog.setPreferredSize(new Dimension(0, 120));
+		log.setEditable(false);
+		
+		// Main control mechanism
+		panelControl = new JPanel();
+		panelControl.setLayout(new GridLayout(1,1));
+		tabPaneControl = new JTabbedPane(JTabbedPane.TOP);
+		tabPaneControl.setPreferredSize(new Dimension(VECTOR_CONTROLLER_WIDTH, 0));
+		tabPaneControl.addTab("Connection", panelServerInterface);
+		tabPaneControl.addTab("Robots", panelRobotControl);
+		tabPaneControl.addTab("Tasks", panelTaskManager);
+		panelControl.add(tabPaneControl);
+		
+		// Set up elements in the south
+		panelSouth = new JPanel();
+		panelSouth.setLayout(new GridLayout(1,2));
+		//panelSouth.add(spLog);
+
+		// Put all elements in the ContentPane
+		this.getContentPane().setLayout(new BorderLayout());
+		this.getContentPane().add(tabPaneMain, BorderLayout.CENTER);
+		this.getContentPane().add(panelSouth, BorderLayout.SOUTH);
+		this.getContentPane().add(panelControl, BorderLayout.EAST);
+		this.setVisible(true);
+		
+		/* Add all listeners here */
+		// Task Management
+		btnAddTask.addActionListener(this);
+		btnRemoveTask.addActionListener(this);
+		btnMoveTaskUp.addActionListener(this);
+		btnMoveTaskDown.addActionListener(this);
+		btnUpdateTasks.addActionListener(this);
+		// Robot Control
+		btnF.addActionListener(this);
+		btnB.addActionListener(this);
+		btnL.addActionListener(this);
+		btnR.addActionListener(this);
+		btnF.addKeyListener(this);
+		btnB.addKeyListener(this);
+		btnL.addKeyListener(this);
+		btnR.addKeyListener(this);
+		btnActivate.addActionListener(this);
+		btnActivate.addKeyListener(this);
+		cmbRobotNum.addKeyListener(this);
+		btnCommand_MoveTo.addActionListener(this);
+		btnCommand_MoveAll.addActionListener(this);
+		btnCommand_StopTask.addActionListener(this);
+		btnCommand_ResumeTask.addActionListener(this);
+		btnCommand_ChargeNow.addActionListener(this);
+		btnCommand_StopCharging.addActionListener(this);
+		// Other
+		btnConnect.addActionListener(this);
+		btnGetXBeeIDs.addActionListener(this);
+		btnAssignID.addActionListener(this);
+		panelWebcam.addMouseListener(this);	
+				
+		// Set up animation threads
+		indicator = new SelectionIndicator(canvas);
+		indicator.setRadius(RADIUS+3, 15);  //a tad more than the bot radius
+	
+	}
+	
+	public void run () {
+		while (true) {
+			repaint();
+			try { 
+				Thread.sleep(90);
+			} catch (InterruptedException e) {
+				return;
+			}
+		}
+	}
+	
+	public void paint (Graphics g) {
+	    super.paint(g);
+	}
+	
+	public void update (Graphics g) {
+	    paint(g);
+	}
+		
+	/** 
+	* Gets the JTextArea used for storing the activity log. This method returns a reference to the 
+	* JTextArea that stores the log. The log can contain any activity that is revelant to the use
+	* of the applet, and may optionally display debugging information.
+	*
+	* @return the JTextArea where BOM matrix information is stored.
+	*/ 
+	public JTextArea getLog () {
+		return log;
+	}
+	
+	/** 
+	* Gets the JTextArea used for storing the BOM matrix data. This method returns a reference to the 
+	* JTextArea that stores the BOM matrix. The values in the matrix are stored as integers separated 
+	* by spaces, and the lines should be separated by a newline.
+	* 
+	* @return the JTextArea where BOM matrix information is stored.
+	*/
+	public JTextArea getMatrixInput () {
+		return txtMatrix;
+	}
+	
+	/**
+	* Parses a String containing BOM matrix information.
+	* The ColonetServerInterface receives lines of the BOM matrix.  (For encoding 
+	* information, see the ColonetServerInterface documentation.)  The entire matrix is passed
+	* to the client when requested. This method takes a string of the form 
+	* "[command code] [command code] [number of robots] [data0] [data1] ..."
+	* with tokens separated by spaces and containing no brackets.  
+	* The [command code]s are predefined values identifying this String as a BOM data
+	* String, [number of robots] is an integer, and the values that follow are 
+	* the sensor readings of the robots in order, starting with robot 0.  Only [number of robots]^2
+	* data entries will be read.  The matrix values are saved locally until the next String is parsed.
+	* 
+	*
+	* @param line the String containing BOM matrix information.
+	* @throws ArrayIndexOutOfBoundsException if there are fewer than [number of robots]^2 data entries in the String
+	*/
+	public void parseMatrix (String line) {
+		txtMatrix.setText("");
+		String [] str = line.split(" ");
+		int num = Integer.parseInt(str[2]);
+		for (int i = 0; i < num; i++) {
+			for (int j = 0; j < num; j++) {
+				String next = str[3 + i*num + j];
+				if (next.equals("-1"))
+					txtMatrix.append("-");
+				else 
+					txtMatrix.append(next);
+				if (j < num - 1) 
+					txtMatrix.append(" ");
+			}
+			if (i < num - 1) 
+				txtMatrix.append("\n");
+		}
+		
+	}
+	
+	public void connect () {
+	    webcamLoader = new WebcamLoader(this);
+		dataUpdater = new DataUpdater();
+		paintThread = new Thread(this, "paintThread");
+		csi = new ColonetServerInterface(this);
+		csi.connect(txtHost.getText(), txtPort.getText());
+		if (!csi.isReady())
+			return;
+		btnConnect.setEnabled(false);
+		lblConnectionStatus.setText("Status: Connected");
+		//paintThread.start();
+		dataUpdater.start();
+		webcamLoader.start();
+	}
+	
+	public void disconnect () {
+	    btnConnect.setEnabled(true);
+	    lblConnectionStatus.setText("Status: Disconnected");
+	    try { paintThread.interrupt(); } catch (Exception e) { }
+		try { indicator.interrupt(); } catch (Exception e) { }
+		
+	}
+	
+	/**
+	* Parses a String containing a task queue update.
+	* Format is currently not specified.
+	* This method currently does nothing.
+	*
+	* @param line the String containing task queue update information.
+	*/
+	public void parseQueue (String line) {
+		log.append("Got queue update\n");
+		//TODO: display new queue data in tasks tab
+	}
+	
+	/**
+	* Parses a String containing XBee ID values.
+	* The ColonetServerInterface receives Strings of XBee information.  (For encoding 
+	* information, see the ColonetServerInterface documentation.)  This method takes
+	* a string of the form "[command code] [command code] [number of robots] [id0] [id1] ..."
+	* with tokens separated by spaces and containing no brackets.  
+	* The [command code]s are predefined values identifying this String as an XBee
+	* ID String, [number of robots] is an integer, and the values that follow are 
+	* the IDs of the robots in order, starting with robot 0.  Only [number of robots] 
+	* will be read.  The ID values are saved locally until the next String is parsed.
+	* The purpose of having this list is to ensure that robots are properly identified for control purposes.
+	* This keeps robot identification consistent between sessions and prevents arbitrary assignment. 
+	*
+	* @param line the String containing XBee ID information.
+	* @throws ArrayIndexOutOfBoundsException if there are fewer than [number of robots] IDs in the String
+	* @see ColonetServerInterface#sendXBeeIDRequest()
+	*/
+	public void parseXBeeIDs (String line) {
+	
+		String [] str = line.split(" ");
+		int num = Integer.parseInt(str[2]);
+		xbeeID = new int[num];
+		for (int i = 0; i < num; i++)
+			xbeeID[i] = Integer.parseInt(str[i+3]);
+		
+		//update the list of robots to control
+		//but save the old value first
+		Object oldSelection = cmbRobotNum.getSelectedItem();
+		cmbRobotNum.removeAllItems();
+		cmbRobotNum.addItem(new String("   All   "));
+		for (int i = 0; i < num; i++)
+			cmbRobotNum.addItem(new String("" + xbeeID[i]));
+		cmbRobotNum.setSelectedItem(oldSelection);
+	}
+	
+	/**
+	* Parses a String containing battery information.
+	* The ColonetServerInterface receives Strings of battery information.  (For encoding 
+	* information, see the ColonetServerInterface documentation.)  This method takes
+	* a string of the form "[command code] [command code] [robot ID] [value]"
+	* with tokens separated by spaces and containing no brackets.  
+	* The [command code]s are predefined values identifying this String as a battery
+	* information String, [robot ID] is an integer, and [value] is a battery measurement.
+	* This updates the batery information for a single robot.
+	* 
+	*
+	* @param line the String containing battery information.
+	* @see ColonetServerInterface#sendBatteryRequest(int)
+	*/
+	public void parseBattery (String line) {
+		String [] str = line.split(" ");
+		int botNum = Integer.parseInt(str[2]);
+		int level = Integer.parseInt(str[3]);
+		int selected = -1;
+		try { 
+		    selected = Integer.parseInt((String)cmbRobotNum.getSelectedItem());
+		} catch (Exception e) {
+		}
+		if (selected == botNum) {
+			batteryIcon.setLevel(level);
+		}
+	}
+	
+	/**
+	* Parses a String containing visual robot position information along with 
+	* canonical ID assignments.
+	*/
+	public void parsePositions (String line) {
+		String [] str = line.split(" ");
+		java.util.List <RobotIcon> newList = new ArrayList <RobotIcon> ();
+		
+		for (int i = 2; i < str.length; i+=3) {
+			int id = Integer.parseInt(str[i]);
+			int x = Integer.parseInt(str[i+1]);
+			int y = Integer.parseInt(str[i+2]);
+			RobotIcon newIcon = new RobotIcon(id, x, y);
+			newList.add(newIcon);
+		}
+		
+		robotIcons = newList;
+	
+	}
+	
+	
+	//
+	// MouseListener methods
+	//
+	public void mouseExited(MouseEvent e) {
+	}
+	public void mouseEntered(MouseEvent e) {
+	}
+	public void mouseReleased(MouseEvent e) {
+	}
+	public void mouseClicked(MouseEvent e) {
+	}
+	public void mousePressed(MouseEvent e) {
+	
+	    // If we are selecting a waypoint (destination) for a specific bot
+	    if (setWaypoint && setWaypointID  >= 0) {
+	        setWaypoint = false;
+	        panelWebcam.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
+	        if (selectedBot < 0)
+	            return;
+	        
+	        RobotIcon r = robotIcons.get(selectedBot);
+	        r.destx = e.getX();
+	        r.desty = e.getY();
+	        
+	        csi.sendAbsoluteMove(r.id, r.destx, r.desty);
+	        
+	        return;
+	    }
+	    
+	    // If we are setting all waypoints
+	    if (setWaypoint) {
+	        setWaypoint = false;
+	        panelWebcam.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
+	        for (int i = 0; i < robotIcons.size(); i++) {
+	            RobotIcon r = robotIcons.get(i);
+	            r.destx = e.getX();
+	            r.desty = e.getY();
+	        }
+	        return;
+	    }
+	    
+	    // Otherwise, we are selecting a bot, or doing nothing
+		for (int i = 0; i < robotIcons.size(); i++) {
+		    RobotIcon r = robotIcons.get(i);
+		    if (r.contains(e.getX(), e.getY())) {
+		        selectedBot = i;
+		        lblSelected.setText(" " + r.id);
+		    }
+		}
+		repaint();
+	}
+	public void mouseDragged(MouseEvent e) {
+	}
+	public void mouseMoved(MouseEvent e) {
+	}
+	
+	//
+	// KeyListener methods
+	//
+	public void keyPressed (KeyEvent e) {
+		int code = e.getKeyCode();
+		if (code == KeyEvent.VK_UP) {
+			vectorController.setMaxForward();
+			vectorController.sendToServer();
+		} else if (code == KeyEvent.VK_DOWN) {
+			vectorController.setMaxReverse();
+			vectorController.sendToServer();
+		} else if (code == KeyEvent.VK_LEFT) {
+			vectorController.setMaxLeft();
+			vectorController.sendToServer();
+		} else if (code == KeyEvent.VK_RIGHT) {
+			vectorController.setMaxRight();
+			vectorController.sendToServer();
+		} else if (code == KeyEvent.VK_S) {
+			vectorController.setZero();
+			vectorController.sendToServer();
+		}
+	}
+	public void keyReleased (KeyEvent e) {
+	}
+	public void keyTyped (KeyEvent e) {
+	}
+	
+	
+	//
+	// ActionListener method
+	//
+	public void actionPerformed (ActionEvent e) {
+		Object source = e.getSource();
+		
+		// General Actions
+		if (source == btnConnect) {
+			connect();
+		} else if (source == btnGetXBeeIDs) {
+			csi.sendXBeeIDRequest();
+		} else if (source == btnAssignID) {
+		    String message;
+		    if (selectedBot < 0)
+		        return;
+		    int curID = robotIcons.get(selectedBot).id;
+		    if (curID < 0)
+		        message = "That robot is unidentified. Please specify its ID.";
+		    else
+		        message = "That robot has ID " + curID + ". You may reassign it now.";
+		    String result = JOptionPane.showInputDialog(this, message, "Robot Identification", JOptionPane.QUESTION_MESSAGE);
+		    if (result == null)
+		        return;
+	        int newID = -1;
+		    try {
+		        newID = Integer.parseInt(result);
+		    } catch (Exception ex) {
+		        csi.warn("Invalid ID.");
+		        return;
+		    }
+		    // Assign new ID and update display  
+			csi.sendIDAssignment(curID, newID);
+		    robotIcons.get(selectedBot).id = newID;
+		    robotIcons.get(selectedBot).color = Color.GREEN;
+		    lblSelected.setText(" " + newID);
+		    
+			
+		}
+		
+		// Robot Movement Controls
+		else if (source == btnF) {
+			vectorController.setMaxForward();
+			vectorController.sendToServer();
+		} else if (source == btnB) {
+			vectorController.setMaxReverse();
+			vectorController.sendToServer();
+		} else if (source == btnL) {
+			vectorController.setMaxLeft();
+			vectorController.sendToServer();
+		} else if (source == btnR) {
+			vectorController.setMaxRight();
+			vectorController.sendToServer();
+		} else if (source == btnActivate) {
+			vectorController.setZero();
+			vectorController.sendToServer();
+		}
+		// Robot Commands (non-movement)
+		else if (source == btnCommand_MoveTo) {
+		    if (selectedBot < 0)
+		        return;
+		    panelWebcam.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
+		    setWaypoint = true;
+		    setWaypointID = selectedBot;
+		    		
+		} else if (source == btnCommand_MoveAll) {
+		    panelWebcam.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
+		    setWaypoint = true;
+		    setWaypointID = -1;
+		    		
+		} else if (source == btnCommand_StopTask) {
+		
+		} else if (source == btnCommand_ResumeTask) {
+		
+		} else if (source == btnCommand_ChargeNow) {
+		
+		} else if (source == btnCommand_StopCharging) {
+		
+		}
+			
+		// Queue Management
+		else if (source == btnAddTask) {
+			taskAddWindow.prompt();
+		} else if (source == btnRemoveTask) {
+			if (taskList.getSelectedIndex() >= 0);
+				csi.sendQueueRemove(taskList.getSelectedIndex());
+			csi.sendQueueUpdate();
+		} else if (source == btnMoveTaskUp) {
+			csi.sendQueueReorder(taskList.getSelectedIndex(), taskList.getSelectedIndex() - 1);
+			csi.sendQueueUpdate();
+		} else if (source == btnMoveTaskDown) {
+			csi.sendQueueReorder(taskList.getSelectedIndex(), taskList.getSelectedIndex() + 1);
+			csi.sendQueueUpdate();
+		} else if (source == btnUpdateTasks) {
+			csi.sendQueueUpdate();
+		}
+	}
+	
+	/*
+	*	SelectionIndicator thread.
+	*	Graphical representation of the selection marker
+	*
+	*	step() and draw() are synchronized methods. step() is private and 
+	*	used to update the position of the crosshairs. draw() is called 
+	*	externally and should only run if all calculations in step() have
+	*	been completed.
+	*/
+	private class SelectionIndicator extends Thread {
+	
+		final int INDICATOR_DELAY = 180;
+		final double DTHETA = 0.4;    //larger values make the marker rotate faster
+		Graphics2D g;   //canvas to draw on
+		boolean running;
+		
+		int sx, sy;		//center
+		int r, dr;		//radius and width of marker
+		double theta;   //current angle
+		
+		volatile Polygon poly1, poly2, poly3, poly4;
+		
+		int px1, py1;
+		int rx1, ry1;
+		int px2, py2;
+		int rx2, ry2;
+		int px3, py3;
+		int rx3, ry3;
+		int px4, py4;
+		int rx4, ry4;
+		
+		int steps;
+	
+		public SelectionIndicator (Graphics2D g) {
+			super("SelectionIndicator");
+			this.g = g;
+			running = false;
+			steps = 0;
+			
+			theta = 0;
+			rx1 = 0; ry1 = 0;
+			px1 = 0; py1 = 0;
+			rx2 = 0; ry2 = 0;
+			px2 = 0; py2 = 0;
+			rx3 = 0; ry3 = 0;
+			px3 = 0; py3 = 0;
+			rx4 = 0; ry4 = 0;
+			px4 = 0; py4 = 0;
+		}
+		
+		public synchronized void setCenter (int sx, int sy) {
+			if (sx == this.sx && sy == this.sy) return;
+			this.sx = sx;
+			this.sy = sy;
+			steps = 0;
+		}
+		
+		public synchronized void setRadius (int r, int dr) {
+			this.r = r;
+			this.dr = dr;
+			steps = 0;
+		}
+		
+		public void run () {
+			running = true;
+			while (running) {
+				step();
+				try { 
+					Thread.sleep(INDICATOR_DELAY);
+				} catch (InterruptedException e) {
+					running = false;
+					return;
+				}
+			}
+		}
+		
+		private synchronized void step () {
+			Polygon poly1_new = new Polygon();
+			Polygon poly2_new = new Polygon();
+			Polygon poly3_new = new Polygon();
+			Polygon poly4_new = new Polygon();
+		
+			//the step
+			theta = (theta + DTHETA/Math.PI) % (Math.PI);
+			
+			//the calculation
+			//let p be the point of the pointy thing toward the center
+			//let r be the point at the opposite side
+			
+			//recalculate radius, if it will look cool, lolz
+			int newr = r;
+			if (steps < 100)
+			newr = (int)( r + 200/(steps+1) );
+			
+			//precompute values for dx and dy
+			int dx_inner = (int)(newr * Math.cos(theta));
+			int dy_inner = (int)(newr * Math.sin(theta));
+			int dx_outer = (int)((newr+dr) * Math.cos(theta));
+			int dy_outer = (int)((newr+dr) * Math.sin(theta));
+			
+			//calculate polygon constants
+			int dy_poly = (int)(dr/2 * Math.cos(theta));
+			int dx_poly = (int)(dr/2 * Math.sin(theta));
+			
+			//determine critical points
+			//kansas city shuffle!
+			px1 = sx + dx_inner;
+			py1 = sy - dy_inner;
+			rx1 = sx + dx_outer;
+			ry1 = sy - dy_outer;
+			px2 = sx - dx_inner;
+			py2 = sy + dy_inner;
+			rx2 = sx - dx_outer;
+			ry2 = sy + dy_outer;
+			px3 = sx - dy_inner;
+			py3 = sy - dx_inner;
+			rx3 = sx - dy_outer;
+			ry3 = sy - dx_outer;
+			px4 = sx + dy_inner;
+			py4 = sy + dx_inner;
+			rx4 = sx + dy_outer;
+			ry4 = sy + dx_outer;
+			
+			//create polygons
+			poly1_new.addPoint(px1, py1);
+			poly1_new.addPoint(rx1+dx_poly, ry1+dy_poly);
+			poly1_new.addPoint(rx1-dx_poly, ry1-dy_poly);
+			poly2_new.addPoint(px2, py2);
+			poly2_new.addPoint(rx2+dx_poly, ry2+dy_poly);
+			poly2_new.addPoint(rx2-dx_poly, ry2-dy_poly);
+			poly3_new.addPoint(px3, py3);
+			poly3_new.addPoint(rx3-dy_poly, ry3+dx_poly);
+			poly3_new.addPoint(rx3+dy_poly, ry3-dx_poly);
+			poly4_new.addPoint(px4, py4);
+			poly4_new.addPoint(rx4-dy_poly, ry4+dx_poly);
+			poly4_new.addPoint(rx4+dy_poly, ry4-dx_poly);
+			
+			//reassign updated polygons
+			poly1 = poly1_new;
+			poly2 = poly2_new;
+			poly3 = poly3_new;
+			poly4 = poly4_new;
+		
+			if (steps < 300) steps++;
+		}
+		
+		public synchronized void draw () {
+			if (!running) return;
+			g.setColor(Color.GRAY);
+			//draw polygons
+			g.fillPolygon(poly1);
+			g.fillPolygon(poly2);
+			g.fillPolygon(poly3);
+			g.fillPolygon(poly4);
+		}
+	
+	}
+	
+	/*
+	*	DataUpdater thread.
+	*   The purpose of this thread is to request data from the server at regular intervals.
+	*
+	*/
+	class DataUpdater extends Thread {
+		final int DATAUPDATER_DELAY = 2200;
+		
+		public DataUpdater () {
+			super("Colonet DataUpdater");
+		}
+		
+		public void run () {
+			String line;
+			while (true) {
+				try {
+					//request more data
+					if (csi != null && csi.isReady()) {
+                        csi.sendPositionRequest();
+						csi.sendXBeeIDRequest();
+						if (cmbRobotNum.getSelectedIndex() > 0) {
+						    String sel = (String) cmbRobotNum.getSelectedItem();
+						    int num = Integer.parseInt(sel);
+							csi.sendBatteryRequest(num);
+						}
+					}
+					Thread.sleep(DATAUPDATER_DELAY);
+				} catch (InterruptedException e) {
+					return;
+				} 
+			}
+		}
+
+	}
+	
+	/*
+	*	GraphicsPanel class
+	*	An extension of JPanel, designed for holding an image that will be repainted regularly.
+	*/
+	class GraphicsPanel extends JPanel {
+		protected Image img;
+	
+		public GraphicsPanel (Image img) {
+			super();
+			this.img = img;
+		}
+		
+		public GraphicsPanel (Image img, boolean isDoubleBuffered) {
+			super(isDoubleBuffered);
+			this.img = img;
+		}
+		
+		public void paint (Graphics g) {
+			// Place the buffered image on the screen, inside the panel
+			g.drawImage(img, 0, 0, Color.WHITE, this);
+		}
+	
+	}
+	
+	/*
+	*	WebcamPanel class
+	*	Enables more efficient image handling in a component-controlled environment
+	*/
+	class WebcamPanel extends JPanel {
+		int BORDER = 16;  // this is arbitrary. it makes the image look nice inside a border.
+		int BOT_RADIUS = 40;
+		volatile BufferedImage img;
+	
+		public WebcamPanel () {
+			super();
+		}
+		
+		public void setImage (BufferedImage newimg) {
+			if (img != null) {
+				img.flush();
+			}
+			System.gc();
+			img = newimg;
+		}
+		
+				
+		public void paint (Graphics g) {
+			
+			if (img == null)
+				return;
+			// Place the image on the screen, inside the panel
+			
+			int maxWidth = getWidth() - 2*BORDER;
+			int maxHeight = getHeight() - 2*BORDER;
+			double widthRatio = 1.0 * maxWidth / img.getWidth();
+			double heightRatio = 1.0 * maxHeight / img.getHeight();
+			int newWidth = 0;
+			int newHeight = 0;
+			int x = 0;
+			int y = 0;
+			
+			if (widthRatio > heightRatio) {  //height is the limiting factor
+			    newHeight = maxHeight;
+			    newWidth = img.getWidth() * maxHeight / img.getHeight();
+			    y = BORDER;
+			    x = (maxWidth - newWidth) / 2 + BORDER;
+			} else {  //width is the limiting factor
+			    newWidth = maxWidth;
+			    newHeight = img.getHeight() * maxWidth / img.getWidth();
+			    x = BORDER;
+			    y = (maxHeight - newHeight) / 2 + BORDER;
+			}
+			
+			Image imgScaled = img.getScaledInstance(newWidth, newHeight, Image.SCALE_FAST);
+			g.drawImage(imgScaled, x, y, this);
+			
+						
+			// Draw Identifiers
+			if (robotIcons == null)
+				return;
+			
+			((Graphics2D)g).setStroke(new BasicStroke(2));
+			for (int i = 0; i < robotIcons.size(); i++) {
+				RobotIcon r = robotIcons.get(i);
+				g.setColor(r.color);
+				if (widthRatio > heightRatio) {
+				    
+				
+				} else {
+				    
+				}
+				g.drawOval(r.x-RADIUS, r.y-RADIUS, 2*r.RADIUS, 2*r.RADIUS);
+				// If the robot has a destination, draw the vector
+				if (r.destx >= 0) {
+				    g.drawLine(r.x, r.y, r.destx, r.desty);
+				}
+			}
+			
+			// Identify currently-selected robot
+			if (selectedBot == -1)
+			    return;
+			g.setColor(Color.YELLOW);
+			RobotIcon r = robotIcons.get(selectedBot);
+			g.drawOval(r.x-RADIUS-6, r.y-RADIUS-6, 2*r.RADIUS+12, 2*r.RADIUS+12);
+			
+		}
+	
+	}
+	
+	/*
+	*	WebcamLoader class
+	*	Handles the loading of the webcam image.
+	*/
+	class WebcamLoader extends Thread 
+	{
+		final int WEBCAMLOADER_DELAY = 300;
+		final String IMAGE_PATH = "http://roboclub9.frc.ri.cmu.edu/colonet.jpg";
+				
+		URL imagePath;
+		
+		MediaTracker mt;
+		BufferedImage image;
+		Random rand;
+		
+		public WebcamLoader (JApplet applet)
+		{
+			super("ColonetWebcamLoader");
+			mt = new MediaTracker(applet);
+			ImageIO.setUseCache(false);
+			rand = new Random();
+		}
+		
+		public void run ()
+		{
+			while (true) {
+				try {
+					Thread.sleep(WEBCAMLOADER_DELAY);
+					if (image != null) 
+						image.flush();
+					System.gc();
+					try {
+				        imagePath = new URL(IMAGE_PATH + "?rand=" + rand.nextInt(50000));
+			        } catch (MalformedURLException e) {
+				        System.out.println("Malformed URL: could not form URL from: [" + IMAGE_PATH + "]\n");
+			        }
+					image = ImageIO.read(imagePath);
+					// The MediaTracker waitForID pauses the thread until the image is loaded.
+					// We don't want to display a half-downloaded image.
+					mt.addImage(image, 1);
+					mt.waitForID(1);
+					mt.removeImage(image);
+					// Save
+					panelWebcam.setImage(image);
+				} catch (InterruptedException e) {
+					return;
+				} catch (java.security.AccessControlException e) {
+					csi.warn("Could not load webcam.\n" + e);
+					return;
+				} catch (IOException e) {
+					log.append("IOException while trying to load image.");
+				}
+			}
+		}
+		
+	}
+	
+	/*
+	*  RobotIcon class
+	*  Provides a means for graphically representing and keeping track of webcam bots.
+	*/
+	class RobotIcon {
+		public final int RADIUS = 30;
+		public final int CLOSE = 80;
+		
+		public int x, y;
+		public int destx, desty;
+		public int id;
+		public Color color;
+		
+		public RobotIcon (int id, int x, int y) {
+			this.color = Color.RED;
+			this.x = x;
+			this.y = y;
+			this.id = id;
+			this.destx = -1;
+			this.desty = -1;
+		}
+		
+		/**
+		*  Relocates this RobotIcon to a new coordinate point.
+		*
+		*/
+		public void move (int newX, int newY) {
+			this.x = newX;
+			this.y = newY;
+		}
+		
+		/**
+		*  Determines if a given point is within a reasonable range of the current location
+		*  to be considered the same robot when moving. The threshold is determined by the 
+		*  CLOSE value.
+		*
+		*  @returns Whether or not the given point is reasonably close to the current location.
+		*
+		*/
+		public boolean isClose (int nx, int ny) {
+			int dist = (int) Point.distance(this.x, this.y, nx, ny);
+			return (dist < CLOSE);
+		}
+		
+		/**
+		*  Determines whether a given point is within the rectangle that circumscribes the
+		*  robot's circlular icon. Used for clicking on robots in webcam view.
+        *
+        */
+		public boolean contains (int px, int py) {
+		    Rectangle rect = new Rectangle(x-RADIUS, y-RADIUS, 2*RADIUS, 2*RADIUS);
+		    return rect.contains(px, py);
+		}
+		
+		public String toString () {
+			String s = "RobotIcon at (" + x + "," + y + "), id " + id;
+			return s;
+		}
+		
+	}
+
+	
+	/*
+	*	VectorController class
+	*	Manages robot motion control graphically
+	*/
+	class VectorController extends GraphicsPanel implements MouseListener, MouseMotionListener {
+		int x, y, cx, cy;
+		int width, height;
+		int side;
+		
+		public VectorController (Image img) {
+			super (img);
+			width = img.getWidth(null);
+			height = img.getHeight(null);
+			cx = img.getWidth(null)/2;
+			cy = img.getHeight(null)/2;
+			x = cx;
+			y = cy;
+			if (width < height)
+				side = width;
+			else
+				side = height;
+			this.addMouseListener(this);
+			this.addMouseMotionListener(this);
+		}
+		
+		public void setPoint (int x, int y) {
+			if (!isValidPoint(x, y))
+				return;
+			this.x = x;
+			this.y = y;
+			repaint();
+		}
+		
+		public boolean isValidPoint (int x, int y) {
+			double xterm = Math.pow(1.0*(x - cx)/(side/2), 2);
+			double yterm = Math.pow(1.0*(y - cy)/(side/2), 2);
+			return (xterm + yterm <= 1);
+		}
+		
+		public void notifyMouseEvent (MouseEvent e, boolean send) {
+			if (!isValidPoint(e.getX(), e.getY()))
+				return;
+			vectorController.setPoint(e.getX(), e.getY());
+			vectorController.repaint();
+			if (send)
+				vectorController.sendToServer();
+		}
+		
+		public void mouseExited(MouseEvent e) {
+		}
+		public void mouseEntered(MouseEvent e) {
+		}
+		public void mouseReleased(MouseEvent e) {
+			this.notifyMouseEvent(e, true);
+		}
+		public void mouseClicked(MouseEvent e) {
+			this.notifyMouseEvent(e, false);
+		}
+		public void mousePressed(MouseEvent e) {
+		}
+		public void mouseDragged(MouseEvent e) {
+			vectorController.notifyMouseEvent(e, false);
+		}
+		public void mouseMoved(MouseEvent e) {
+		}
+		
+		public int getSpeed () {
+			int dx = x - cx;
+			int dy = y - cy;
+			int v = (int) Math.sqrt( Math.pow(dx, 2) + Math.pow(dy, 2) );
+			return v;
+		}
+		
+		/** 
+		* Returns the angle of the control vector in positive degrees west of north,
+		* or negative degrees east of north, whichever is less than or equal to
+		* 180 degrees total.
+		*/
+		public int getAngle () {
+			int dx = x - cx;
+			int dy = cy - y;
+			// find reference angle in radians
+			double theta = Math.atan2(Math.abs(dx), Math.abs(dy));
+			// transform to degrees
+			theta = theta * 180 / Math.PI;
+			// adjust for quadrant
+			if (dx < 0 && dy < 0)
+				theta = 90 + theta;
+			else if (dx < 0 && dy >= 0)
+				theta = 90 - theta;
+			else if (dx >= 0 && dy < 0)
+				theta = -90 - theta;
+			else
+				theta = -90 + theta;
+			return (int) theta;
+		}
+		
+		public void paint (Graphics g) {
+			g.setColor(Color.BLACK);
+			g.fillRect(0, 0, width, height);
+			((Graphics2D)g).setStroke(new BasicStroke(1));
+			g.setColor(Color.RED);
+			g.drawOval(cx-side/2, cy-side/2, side, side);
+			((Graphics2D)g).setStroke(new BasicStroke(2));
+			g.setColor(Color.GREEN);
+			g.drawLine(cx, cy, x, y);
+			g.fillOval(x-3, y-3, 6, 6);
+		}
+		
+		public void setMaxForward () {
+			setPoint(cx, cy - (side/2) + 1);
+		}
+		
+		public void setMaxReverse () {
+			setPoint(cx, cy + (side/2) - 1);
+		}
+		
+		public void setMaxLeft () {
+			setPoint(cx - (side/2) + 1, cy);
+		}
+		
+		public void setMaxRight () {
+			setPoint(cx + (side/2) - 1, cy);
+		}
+		
+		public void setZero () {
+			setPoint(cx, cy);
+		}
+		
+		public void sendToServer () {
+			System.out.println("Attempting to send angle = " + getAngle() + ", speed = " + getSpeed() + "");
+			String dest = ColonetServerInterface.GLOBAL_DEST;
+			if (cmbRobotNum != null && cmbRobotNum.getSelectedIndex() > 0) {
+				dest = (String)cmbRobotNum.getSelectedItem();
+			}
+			
+			if (csi != null) {
+				/*
+				csi.sendData(ColonetServerInterface.MOVE + " " + getSpeed() + " " + getAngle(), dest);
+				*/
+				
+				//Directional commands
+				if (x > cx && y == cy) {  //move right
+					csi.sendData(ColonetServerInterface.MOTOR2_SET + " 0 200", dest);
+					csi.sendData(ColonetServerInterface.MOTOR1_SET + " 1 200", dest);
+				} else if (x < cx && y == cy) {  //move left
+					csi.sendData(ColonetServerInterface.MOTOR2_SET + " 1 200", dest);
+					csi.sendData(ColonetServerInterface.MOTOR1_SET + " 0 200", dest);
+				} else if (x == cx && y > cy) {  //move forward
+					csi.sendData(ColonetServerInterface.MOTOR2_SET + " 0 225", dest);
+					csi.sendData(ColonetServerInterface.MOTOR1_SET + " 0 225", dest);
+				} else if (x == cx && y < cy) {  //move backward
+					csi.sendData(ColonetServerInterface.MOTOR2_SET + " 1 225", dest);
+					csi.sendData(ColonetServerInterface.MOTOR1_SET + " 1 225", dest);
+				} else if (x == cx && y == cy) {  //stop!
+					csi.sendData(ColonetServerInterface.MOTOR2_SET + " 1 0", dest);
+					csi.sendData(ColonetServerInterface.MOTOR1_SET + " 1 0", dest);
+				}
+			}
+		}
+	
+	}
+	
+	/*
+	*	TaskAddWindow class
+	*	A window that provides a simple way to add tasks to a task queue.
+	*/
+	class TaskAddWindow extends JFrame implements ActionListener, ListSelectionListener {
+		JPanel panelButtons;
+		JPanel panelParameters;
+		JPanel panelSouth;
+		JPanel panelSelection;
+		JButton btnSubmit;
+		JButton btnCancel;
+		DefaultListModel availableListModel;
+		JList availableList;
+		JScrollPane spAvailableTasks;
+		JTextArea txtDescription;
+		JTextField txtParameters;
+		
+		public TaskAddWindow () {
+			super("Add a Task");
+			super.setSize(500,500);
+			super.setLayout(new BorderLayout());
+			
+			// set up buttons
+			btnSubmit = new JButton("Submit");
+			btnCancel = new JButton("Cancel");
+			panelButtons = new JPanel();
+			panelButtons.setLayout(new FlowLayout());
+			panelButtons.add(btnSubmit);
+			panelButtons.add(btnCancel);
+			this.getRootPane().setDefaultButton(btnSubmit);
+			
+			// set up task list
+			availableListModel = new DefaultListModel();
+			availableListModel.addElement("Map the Environment");
+			availableListModel.addElement("Clean Up Chemical Spill");
+			availableListModel.addElement("Grow Plants");
+			availableListModel.addElement("Save the Cheerleader");
+			availableListModel.addElement("Save the World");
+			availableList = new JList(availableListModel);
+			availableList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+			availableList.setSelectedIndex(-1);
+			spAvailableTasks = new JScrollPane(availableList);
+			spAvailableTasks.setBorder(BorderFactory.createTitledBorder("Select A Task"));
+			txtDescription = new JTextArea();
+			txtDescription.setEditable(false);
+			txtDescription.setLineWrap(true);
+			txtDescription.setWrapStyleWord(true);
+			txtDescription.setBorder(BorderFactory.createTitledBorder("Description"));
+			
+			//set up parameter area
+			panelParameters = new JPanel();
+			panelParameters.setLayout(new BorderLayout());
+			txtParameters = new JTextField();
+			panelParameters.add(new JLabel("Optional parameters for this task: "), BorderLayout.WEST);
+			panelParameters.add(txtParameters);
+			
+			// assemble objects
+			panelSelection = new JPanel();
+			panelSelection.setLayout(new GridLayout(1,2));
+			panelSelection.add(spAvailableTasks);
+			panelSelection.add(txtDescription);
+			
+			panelSouth = new JPanel();
+			panelSouth.setLayout(new GridLayout(2,1));
+			panelSouth.add(panelParameters);
+			panelSouth.add(panelButtons);
+			
+			this.getContentPane().add(panelSouth, BorderLayout.SOUTH);
+			this.getContentPane().add(panelSelection, BorderLayout.CENTER);
+			this.setLocationRelativeTo(null);
+			
+			// add listeners here
+			availableList.addListSelectionListener(this);
+			btnSubmit.addActionListener(this);
+			btnCancel.addActionListener(this);
+		}
+		
+		public void prompt () {
+			this.setVisible(true);
+		}
+		
+		private String getDescription (int index) {
+			if (index < 0)
+				return "";
+			switch (index) {
+				case 0: return "SLAM and junk";
+				case 1: return "I'm not sure this works";
+				case 2: return "Push them into the light";
+				case 3: return "...";
+				case 4: return "...";
+			
+				default: return "Task not recognized";
+			}
+		}
+		
+		public void actionPerformed (ActionEvent e) {
+			Object source = e.getSource();
+			if (source == btnSubmit) {
+				txtParameters.setText(txtParameters.getText().trim());
+				
+				
+				this.setVisible(false);
+			} else if (source == btnCancel) {
+				this.setVisible(false);
+			}
+		}
+		
+		public void valueChanged (ListSelectionEvent e) {
+			int index = availableList.getSelectedIndex();
+			if (index >= 0)
+				txtDescription.setText(getDescription(index));
+		}
+	
+	}
+	
+	/*
+	*  BatteryIcon class
+	*  Graphical representation of battery level
+	*/
+	class BatteryIcon implements Icon {
+		private int width;
+	    private int height;
+	    private int level;
+	    
+		/** 
+		* Constructs a new BatteryIcon with all default parameters.
+		* Default width and height are 50.
+		* Default level is 100.
+		*/
+	    public BatteryIcon(){
+	    	this(100, 50, 50);
+	    }
+	    
+		/** 
+		* Constructs a new BatteryIcon with default width and height, and with the specified level.
+		* Default width and height are 50.
+		*/
+	    public BatteryIcon(int startLevel){
+	    	this(startLevel, 50, 50);
+	    }
+	    
+		/** 
+		* Constructs a new BatteryIcon with the specified level, width, and height.
+		*/
+	    public BatteryIcon(int startLevel, int w, int h){
+	    	level = startLevel;
+	    	width = w;
+	    	height = h;
+	    }
+	    
+	    public void paintIcon(Component c, Graphics g, int x, int y) {
+	        Graphics2D g2d = (Graphics2D) g.create();
+	        //clear the background
+	        g2d.setColor(Color.WHITE);
+	        g2d.fillRect(x + 1, y + 1, width - 2, height - 2);
+	        //outline
+	        g2d.setColor(Color.BLACK);
+	        g2d.drawRect((int)(x + width*.3), y + 2, (int)(width*.4), height - 4);
+	        //battery life rectangle
+	        g2d.setColor(Color.GREEN);
+	        int greenX = (int)(x + 1 + width*.3);
+	        int greenY = (int)((y+3) + Math.abs(level-100.0)*(height-6)/(100));
+	        int greenWidth = (int)(width*.4 - 2)+1;
+	        int greenHeight = 1+(int)(level-0.0)*(height-6)/(100);
+	        g2d.fillRect(greenX, greenY, greenWidth, greenHeight);
+	        //text
+	        g2d.setColor(Color.BLACK);
+	        g2d.drawString(level + "%", greenX + greenWidth/2 - 10, greenY + greenHeight/2 + 5);
+	        
+	        g2d.dispose();
+	    }
+	    
+		/**
+		* Sets the battery level for this BatteryIcon. The level should be given in raw form, i.e. 0-255 directly 
+		* from the robot. The value will be converted to a representative percentage automatically.
+		*
+		* @param newLevel the new battery reading from the robot that this BatteryIcon will display.
+		*/
+	    public void setLevel(int newLevel) {
+	    	level = convert(newLevel);
+	    	repaint();
+	    	System.out.println("Updated level to " + level);
+	    }
+		
+	    public int getIconWidth() {
+	        return width;
+	    }
+	    
+	    public int getIconHeight() {
+	        return height;
+	    }
+		
+		/**
+		* Converts a robot battery reading into representable form.
+		* Readings from the robot are returned as raw values, 0-255. This method converts the reading into a value
+		* from 0 to 100 so that the practical remaining charge is represented.
+		*
+		* @param level The battery level as returned by the robot.
+		* @returns The representable battery percentage.
+		*/
+		private int convert (int level) {
+			// TODO: make this a forreals conversion.
+			return (int) (100.0 * level / 128);
+		}
+		
+	}
+
+
+
+}
Index: trunk/code/projects/colonet/client/ColonetServerInterface.java
===================================================================
--- trunk/code/projects/colonet/client/ColonetServerInterface.java	(nonexistent)
+++ trunk/code/projects/colonet/client/ColonetServerInterface.java	(revision 476)
@@ -0,0 +1,538 @@
+/*
+*	ColonetServerInterface.java
+*	Gregory Tress
+*/
+
+import java.net.*;
+import java.io.*;
+import javax.swing.JOptionPane;
+import javax.swing.JTextArea;
+
+/**
+* The Colonet server interface class. This class handles direct communication with the Colonet server. The general
+* contract is that this class will encapsulate the process of sending commands and requests to the server and 
+* receiving responses. This class should provide methods to send specific commands and requests so that the 
+* Colonet can easily communicate with the server. When data is received from the server, the ColonetServerInterface 
+* decides how to handle it and in many cases this means simply passing it to the Colonet. 
+* <p>
+* The motivation is that any number of Colonet-type classes could be designed for different purposes if needed, with
+* this class being used by each one for communication. 
+* For instance, if an application is designed which only monitors sensor data, or that only has access to
+* the task queue, etc., the application could easily plug in to this interface.
+* The Colonet should generally not contain communication-specific code or Strings of command and request data. 
+* If additional commands and requests are needed for permanent implementation, it is suggested that convenience
+* classes be created in the ColonetServerInterface and called from the Colonet.
+*
+* @author Gregory Tress 
+*/
+public class ColonetServerInterface 
+{
+
+	/* STATIC FIELDS
+	 * Eugene Marinelli, Fan
+	 * 10/27/06
+	 *
+	 * Colonet Definitions - common definitions and structs used in all colonet 
+	 * applications
+	
+	Old packet structure:
+
+    COMMAND PACKET STRUCTURE
+	1:  SEND_TO_ROBOT
+	2:  # of robot, or GLOBAL_DEST
+	3:  COLONET_COMMMAND
+	4:  message code (i.e. ORB_SET)
+	5:  any data, as many that fit in the packet
+	
+	REQUEST PACKET STRUCTURE
+	1:  REQUEST_FROM_SERVER
+	2:  # of robot
+	3:  COLONET_REQUEST
+	4:  ???
+  
+  9/12/07 New server interface structure
+    Client will no longer send full robot packets to the server.
+    Commands will be defined as necessary.
+	*/
+	
+	//General Colonet Interface
+	public static final String SEND_TO_ROBOT = "0";
+	public static final String REQUEST_FROM_SERVER = "1";
+	public static final String RESPONSE_TO_CLIENT_REQUEST = "2";
+	public static final String REQUEST_BOM_MATRIX = "144";
+	public static final String REQUEST_XBEE_IDS = "145";
+	
+	public static final String COLONET_COMMAND = "13"; //0x0D
+	public static final String COLONET_REQUEST = "14"; //0x0E
+	public static final String CORONET_RESPONSE = "15"; //0x0F
+	public static final String GLOBAL_DEST = "200";
+	public static final String CLIENT_REQUEST_ROBOT_POSITIONS = "86";
+	public static final String CLIENT_ASSIGN_ROBOT_ID = "87";
+	public static final String MOVE_TO_ABSOLUTE_POSITION = "83"; //0x53
+	
+	//Queue instructions
+	public static final String COLONET_QUEUE = "100";
+	public static final String QUEUE_UPDATE = "101"; 
+	public static final String QUEUE_ADD = "102";
+	public static final String QUEUE_REMOVE = "103";
+	public static final String QUEUE_REORDER = "104";
+	
+	//Use BATTERY to request battery level
+	public static final String BATTERY = "56"; //0x38
+	
+	//MOTORS
+	public static final String MOTORS_INIT = "23"; //0x17
+	public static final String MOTOR1_SET = "24"; //0x18
+	public static final String MOTOR2_SET = "25"; //0x19
+	public static final String MOTORS_OFF = "26"; //0x1A
+	public static final String MOVE = "27"; //0x1B
+	public static final String MOVE_AVOID = "28"; //0x1C
+	
+	//BUZZER
+	public static final String BUZZER_INIT = "0"; //0x00
+	public static final String BUZZER_SET_VAL = "1"; //0x01
+	public static final String BUZZER_SET_FREQ = "2"; //0x02
+	public static final String BUZZER_CHIRP = "3"; //0x03
+	public static final String BUZZER_OFF = "4"; //0x04
+
+	//ORB
+	public static final String ORB_INIT = "12"; //0x0C
+	public static final String ORB_SET = "13"; //0x0D
+	public static final String ORB_SET_COLOR = "14"; //0x0E
+	public static final String ORB_DISABLE = "15"; //0x0F
+	public static final String ORB_ENABLE = "16"; //0x10
+	public static final String ORB_SET_DIO = "17"; //0x11
+	public static final String LED_INIT = "18"; //0x12
+	public static final String LED_USER = "19"; //0x13
+	public static final String ORB_SET_NUM_NS = "20"; //0x14
+	public static final String ORB_SET_NUM = "21"; //0x15
+	public static final String ORB_SEND = "22"; //0x16
+
+		
+	Colonet colonet;  //save reference to the entire applet locally
+	Socket socket;
+	OutputStreamWriter out;
+	BufferedReader reader;
+	DataListener dataListener;
+	JTextArea log, txtMatrix;
+	
+	
+	/*
+	*	FUNCTION IMPLEMENTATIONS
+	*/
+
+	/**
+	* Constructs a new ColonetServerInterface. When constructing a ColonetServerInterface, a valid Colonet object
+	* reference must be provided to ensure that data is routed correctly. 
+	*
+	* @param colonet The Colonet object to save locally. This reference cannot be changed once the 
+	*		ColonetSreverInterface has been contsructed.
+	* @throws NullPointerException if colonet is null
+	*
+	*/
+	public ColonetServerInterface (Colonet colonet) {
+		this.colonet = colonet;
+		this.log = colonet.getLog();
+		this.txtMatrix = colonet.getMatrixInput();
+		dataListener = new DataListener();
+	}
+
+	public Socket getSocket () {
+		return socket;
+	}
+	
+	public OutputStreamWriter getOutputStreamWriter () {
+		return out;
+	}
+	
+	public BufferedReader getBufferedReader () {
+		return reader;
+	}
+	
+	public boolean isReady () {
+		if (socket == null || out == null || reader == null)
+			return false;
+		if (!socket.isConnected() || socket.isClosed() || socket.isInputShutdown() || socket.isOutputShutdown())
+			return false;
+		return true;
+	}
+	
+	public boolean isInputReady () {
+		try {
+			if (reader.ready()) return true;
+		} catch (Exception e) {
+			return false;
+		}
+		return false;
+	}
+	
+	public String getLine () throws IOException {
+		return reader.readLine();
+	}
+  
+	/**
+	 * Create socket connection to Colonet server.
+	 * If successful, start thread for listening for incoming data.
+	 */
+	public void connect (String strHost, String strPort) {
+		//make sure hostname and port are valid
+		if (strHost.equals("") || strPort.equals("")) {
+			err("Please enter a hostname and port.");
+			return;
+		}
+		int port = 0;
+		try {
+			port = Integer.parseInt(strPort);
+		} catch (Exception e) {
+			err("Invalid port");
+			return;
+		}
+		
+		//make sure we aren't already connected.
+		if (socket != null && socket.isConnected()) {
+			return;
+		}
+		
+		try {
+			socket = new Socket(strHost, port);
+			socket.setKeepAlive(true);
+		} catch (UnknownHostException e) {
+			log.append("Unknown host exception.\n");
+			err("Unknown Host Exception");
+			return;
+		} catch (IOException e) {
+			log.append("IO Exception.\n");
+			err("Could not create socket to " + strHost + ".\n" + e);
+			return;
+		} catch (java.security.AccessControlException e) {
+			log.append("Access Control Exception.\n");
+			err("Permission denied by java.security.AccessControlException.\n\n"
+				+"You may only connect to the server from which this applet was loaded.");
+			return;
+		}
+		if (socket == null || !socket.isConnected()) {
+			log.append("Connection is not ready. Try connecting again.\n");
+			return;
+		}
+		try {
+			out = new OutputStreamWriter(socket.getOutputStream());
+			reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+		} catch (IOException e) {
+			warn("Could not get transfer streams from socket connection.");
+		}
+		dataListener.start();
+	
+	}
+	
+	public void disconnect () {
+	    
+	}
+	
+	/*
+	*	sendString - only this method should actually write data to the output stream
+	*/
+	private void sendString (String s) {
+		//make sure we can send
+		if (!this.isReady()) {
+			log.append("Could not send data.\n");
+			return;
+		}
+		//send packet
+		try {
+			Thread.sleep(50);  //pause to be safe
+			out.write(s);
+			out.flush();
+			//log.append("Sent: " + s + "\n");
+		} catch (IOException e) {
+			log.setText("Could not send data.\n");
+		} catch (InterruptedException e) {
+			log.setText("Thread InterruptedException in sendData\n");
+		}
+	}
+	
+	/**
+	* General send-to-server method. This method is used by other command methods, which are usually convenience
+	* methods that simply specify arguments to this method. A command consists of a String which holds integers 
+	* separated by spaces. This method should not be used directly unless you know the format of the particular 
+	* command you are sending. If implementing a particular command for permanent use, it is recommended that 
+	* you create a new wrapper method specific to that command in the ColonetServerInterface file.
+	*
+	* Note that no checking is performed in this method to ensure the correct formatting of the String arguments.
+	* If malformed commands or robot numbers are specified, the behavior of the request at the server will be
+	* undefined and could result in server failure. 
+	*
+	* @param s The command String in its correct format. The format of a command String is ultimately specified
+	* by the Colonet server application and may change. 
+	* @param robotNumber The number of the robot that is the subject of the command, if any. The robot number 
+	* is specified as a single integer in a String. If the command does not have a single robot subject, this 
+	* argument can be null or an empty String, whichever is convenient. 
+	*/
+	public void sendData (String s, String robotNumber) { 
+		//create packet
+		String packet = "";
+		packet += ColonetServerInterface.SEND_TO_ROBOT;
+		if (robotNumber != null)
+			packet += " " + 7;  //robotNumber;
+		packet += " " + ColonetServerInterface.COLONET_COMMAND;
+		packet += " " + s;  //add  the command code here
+		packet += "\n";
+		sendString(packet);
+		txtMatrix.append("S:" + packet);
+	}
+	
+	/**
+	* General request-from-server method. This method is used by other request methods, which are usually convenience
+	* methods that simply specify arguments to this method. A request consists of a String which holds integers 
+	* separated by spaces. This method should not be used directly unless you know the format of the particular 
+	* request you are making. If implementing a particular request, it is recommended that you create a new method
+	* specific to that request in the ColonetServerInterface file.
+	*
+	*/
+	private void sendRequest (String s, String robotNumber) {
+		//create packet
+		String packet = "";
+		packet += ColonetServerInterface.REQUEST_FROM_SERVER;
+		packet += " " + robotNumber;
+		packet += " " + s;  //add  the command code here
+		packet += "\n";
+		sendString(packet);
+	}
+	
+	/** 
+	* Sends a request to the server to report the entire BOM sensor matrix. The server will reply at its convenience. 
+	* No guarantee is made (end-to-end or otherwise) that the server will respond in a timely manner or at all
+	* to any individual request.
+	*/
+	public void sendSensorDataRequest () {
+		sendRequest(ColonetServerInterface.REQUEST_BOM_MATRIX, "");
+	}
+	
+	/**
+	* Sends a request to the server to report a list of XBee IDs. The server will reply at its convenience. 
+	* The purpose of having this list is to ensure that robots are properly identified for control purposes.
+	* This keeps robot identification consistent between sessions and prevents arbitrary assignment. 
+	* No guarantee is made (end-to-end or otherwise) that the server will respond in a timely manner or at all
+	* to any individual request.
+	*
+	* @see Colonet#parseXBeeIDs(String)
+	*/
+	public void sendXBeeIDRequest () {
+		sendRequest(ColonetServerInterface.REQUEST_XBEE_IDS, "");
+	}
+	
+	/**
+	* Sends a battery request for a specific robot to the server. The server will reply at its convenience. 
+	* Behavior is undefined if an invalid robot number is specified. The server will probably not respond in 
+	* this case.
+	* No guarantee is made (end-to-end or otherwise) that the server will respond in a timely manner or at all
+	* to any individual request.
+	*
+	* @param robotNum The number of the robot for which we are requesting the battery. Note that this value
+	* is sent as-is to the server. No mapping to or from XBee IDs is performed. The contract for this is
+	* currently undefined.
+	* @see Colonet#parseBattery(String)
+	*/
+	public void sendBatteryRequest (int robotNum) {
+		//create packet
+		String packet = "";
+		packet += ColonetServerInterface.SEND_TO_ROBOT;
+		packet += " " + robotNum;
+		packet += " " + ColonetServerInterface.COLONET_REQUEST;
+		packet += " " + ColonetServerInterface.BATTERY;  //add  the command code here
+		packet += "\n";
+		sendString(packet);
+	}
+	
+	/**
+	* Requests a list of all robot positions and correspondind robot IDs.
+	*/
+	public void sendPositionRequest () {
+		sendRequest(ColonetServerInterface.CLIENT_REQUEST_ROBOT_POSITIONS, "");
+	}
+	
+	/**
+	* Send a robot ID assignment update to store on the server.
+	*/
+	public void sendIDAssignment (int oldID, int newID) {
+		String packet = "";
+		packet += ColonetServerInterface.REQUEST_FROM_SERVER;
+		packet += " " + oldID + " " + newID;
+		packet += "\n";
+		sendString(packet);
+		txtMatrix.append("ID " + oldID + " => " + newID + "\n");
+	}
+	
+	/** 
+	* Order a robot to move to an absolute coordinate point.
+	*/
+	public void sendAbsoluteMove (int id, int x, int y) {
+	    sendData(MOVE_TO_ABSOLUTE_POSITION + " " + x + " " + y, "" + id);
+	}
+	
+	/*
+	*	Queue management
+	*/
+	private void sendQueueInstruction (String inst) {
+		String packet = "";
+		packet += ColonetServerInterface.COLONET_QUEUE;
+		packet += " " + inst;
+		packet += "\n";
+		sendString(packet);
+	}
+	
+	/**
+	* Notifies the Colonet server to add a task to the current task queue. The Colonet server holds the canonical 
+	* task queue. Any applet can send tasks to add to the queue. Local copies of the queue in the applet are for
+	* display purposes only, and are not authoritative when adding tasks. All clients send additions asynchronously,
+	* and as a result no guarantee is made that a task will be added in the specificed location in the queue or at 
+	* all. If an invalid position is specified, the task will probably not be added to the queue and may cause
+	* server failure. Due to the asynchronous nature of the queue, we cannot easily account for concurrent
+	* modification failures on the client side.
+	*
+	* @param pos The position in the queue at which we would like the task to be placed. Note that this is not 
+	* guaranteed. Invalid positions may cause the task to be discarded at the server.
+	* @param data The String containing the command code(s) for the task and any arguments necessary to fully 
+	* define the behavior of the task. This format is currently not specified. In the future, the canonical format
+	* of the data String will ultimately be defined by the Colonet server.
+	* @param description A String that contains a description of the task. This will be the message displayed to
+	* the user when information about the task is requested. 
+	*/
+	public void sendQueueAdd (int pos, String data, String description) {
+		String packet = "";
+		packet += ColonetServerInterface.QUEUE_ADD;
+		packet += " " + pos;
+		packet += " " + data;
+		packet += " [" + description + "]";
+		packet += "\n";
+		sendQueueInstruction(packet);
+	}
+	
+	/**
+	* Notifies the Colonet server to remove a task from the current task queue. The Colonet server holds the canonical 
+	* task queue. Any applet can remove a task from the queue. Local copies of the queue in the applet are for
+	* display purposes only, and are not authoritative when removing tasks. All clients remove tasks asynchronously,
+	* and as a result no guarantee is made that the correct task will actually be removed. 
+	* If an invalid position is specified, the state of the queue is undefined and server failure may result.
+	* Due to the asynchronous nature of the queue, we cannot easily account for concurrent
+	* modification failures on the client side.
+	*
+	* @param pos The position in the queue at which we would like the task to be removed. Note that this is not 
+	* guaranteed. Invalid positions may result in a corrupted queue.
+	*/
+	public void sendQueueRemove (int pos) {
+		String packet = "";
+		packet += ColonetServerInterface.QUEUE_REMOVE;
+		packet += " " + pos;
+		packet += "\n";
+		sendQueueInstruction(packet);
+	}
+
+	/**
+	* Notifies the Colonet server to reorder tasks in the current task queue. The Colonet server holds the canonical 
+	* task queue. Any applet can reorder tasks in the queue. Local copies of the queue in the applet are for
+	* display purposes only, and are not authoritative when reordering tasks. All clients reorder tasks asynchronously,
+	* and as a result no guarantee is made that the correct tasks will actually be reordered. 
+	* If an invalid position is specified, the state of the queue is undefined and server failure may result.
+	* Due to the asynchronous nature of the queue, we cannot easily account for concurrent
+	* modification failures on the client side.
+	*
+	* @param pos1 The queue position of a task which we would like to reorder.
+	* @param pos2 The queue position of a task which we would like to reorder.
+	*/
+	public void sendQueueReorder (int pos1, int pos2) {
+		String packet = "";
+		packet += ColonetServerInterface.QUEUE_REORDER;
+		packet += " " + pos1;
+		packet += " " + pos2;
+		packet += "\n";
+		sendQueueInstruction(packet);
+	}
+
+	public void sendQueueUpdate () {
+		sendQueueInstruction(ColonetServerInterface.QUEUE_UPDATE);
+	}
+	
+	/**
+	 * Display informational message box on the screen. Used for casual communicaton to the user.
+	 * @param text Text to display
+	 */
+	public void msg (String text) {
+		JOptionPane.showMessageDialog(colonet, text, "Colonet", JOptionPane.INFORMATION_MESSAGE);
+	}
+	
+	/**
+	 * Display warning message box on the screen. Used for minor alerts or exceptions.
+	 * @param text Text to display
+	 */
+	public void warn (String text) {
+		JOptionPane.showMessageDialog(colonet, text, "Colonet", JOptionPane.WARNING_MESSAGE);
+	}
+	
+	/**
+	 * Display error message box on the screen. Used for major errors or exceptions in the program.
+	 * @param text Text to display
+	 */
+	public void err (String text) {
+		JOptionPane.showMessageDialog(colonet, text, "Colonet", JOptionPane.ERROR_MESSAGE);
+	}
+	
+		
+	/*
+	*	DataListener thread.
+	*
+	*/
+	class DataListener extends Thread {
+		final int DATALISTENER_DELAY = 222;
+		
+		public DataListener () {
+			super("Colonet DataListener");
+		}
+		
+		public void run () {
+			String line;
+			while (true) { 
+				try {
+					line = reader.readLine();
+					if (line == null)
+					    throw new IOException();
+					parseData(line);
+					Thread.sleep(DATALISTENER_DELAY);
+				} catch (InterruptedException e) {
+					return;
+				} catch (IOException e) {
+			        disconnect();
+				    colonet.disconnect();
+				    return;
+				}
+			}
+		}
+		
+		public void parseData (String line) {
+			// Sensor Matrix
+			if (line.startsWith(ColonetServerInterface.RESPONSE_TO_CLIENT_REQUEST + " " +
+				ColonetServerInterface.REQUEST_BOM_MATRIX))
+				colonet.parseMatrix(line);
+			// Task Queue
+			else if (line.startsWith(ColonetServerInterface.COLONET_QUEUE))
+				colonet.parseQueue(line);
+			// XBee IDs
+			else if (line.startsWith(ColonetServerInterface.RESPONSE_TO_CLIENT_REQUEST + " " +
+				ColonetServerInterface.REQUEST_XBEE_IDS))
+				colonet.parseXBeeIDs(line);
+			// Battery
+			else if (line.startsWith(ColonetServerInterface.RESPONSE_TO_CLIENT_REQUEST + " " +
+				ColonetServerInterface.BATTERY))
+				colonet.parseBattery(line);
+			// Robot Positions
+			else if (line.startsWith(ColonetServerInterface.RESPONSE_TO_CLIENT_REQUEST + " " +
+				ColonetServerInterface.CLIENT_REQUEST_ROBOT_POSITIONS))
+				colonet.parsePositions(line);
+			// Unknown type
+			else
+				txtMatrix.setText("Got unknown data: " + line + "\n");
+				
+		}
+
+	}
+
+}
Index: trunk/code/projects/colonet/client/index.xhtml
===================================================================
--- trunk/code/projects/colonet/client/index.xhtml	(nonexistent)
+++ trunk/code/projects/colonet/client/index.xhtml	(revision 476)
@@ -0,0 +1,57 @@
+<?xml version="1.0"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" 
+  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+  <head>
+    <title>Colony Control Applet - Carnegie Mellon Robotics Club</title>
+    <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
+    <link rel="stylesheet" type="text/css" href="colonetstyle.css" />
+  </head>
+
+  <body>
+
+    <div class="top">
+      <h3>Colonet</h3>
+      <img src="http://roboclub8.frc.ri.cmu.edu/mainwiki/roboclublogo.png" alt="RoboClub Logo" />
+    </div>
+
+    <div class="app">
+      <p>
+	<object class = "applet"
+	   archive = "Colonet.jar"
+	   type = "application/x-java-applet"
+	   width = "950"
+	   height = "550"
+	   codebase = "."
+	   codetype = "application/x-java-applet"
+	   name = "Colonet"
+	   title = "Colonet" >
+	  <param name="type" value="application/x-java-applet" /> 
+	  <param name = "code" value = "Colonet.class" />
+	  <param name = "cache_option" value = "No" />
+	</object>
+	<br />
+	Requires Java 5.
+	<br />
+      </p>
+    </div>
+
+    <div class="bottom">
+      <p><b>Colony Project Home page:</b>&nbsp;<a href="http://www.robotcolony.org/">www.robotcolony.org</a></p>
+
+      <p><b>Validator:</b><br />
+	<a href="http://validator.w3.org/check?uri=referer">
+	  <img src="http://www.w3.org/Icons/valid-xhtml11-blue"
+	       alt="Valid XHTML 1.0 Transitional"
+	       height="31"
+	       width="88"
+	       />
+	</a>
+	<br />
+      </p>
+
+    </div>
+
+  </body>
+</html>
Index: trunk/code/projects/colonet/client/Makefile
===================================================================
--- trunk/code/projects/colonet/client/Makefile	(nonexistent)
+++ trunk/code/projects/colonet/client/Makefile	(revision 476)
@@ -0,0 +1,45 @@
+# Colonet GUI Makefile
+# Gregory Tress
+#
+# DIR is the name of the output directory
+# JCFLAGS are the compiler options
+# JCWARN specifies which warnings should be displayed
+#
+# Complier Flags
+#  -g            Generate all debugging info
+#  -d <dir>      Specify where to place generated class files
+#  -target <vm>  Generate class files for a specific VM release (i.e. 1.6)
+#  -Xlint        Enable warnings
+
+JC = javac
+DIR = build
+JCFLAGS = -g -d $(DIR) -target 1.5
+JCWARN = -Xlint:deprecation,unchecked,fallthrough,path,finally
+
+# Java file compilation instructions
+
+default: $(DIR)/Colonet.class $(DIR)/ColonetServerInterface.class $(DIR)/Colonet.jar
+
+$(DIR)/Colonet.jar: $(DIR)/Colonet.class $(DIR)/ColonetServerInterface.class
+	@echo --- Creating archive file ---
+	cd $(DIR); jar cf Colonet.jar *.class; jarsigner -keystore colonetkey -storepass colonet Colonet.jar colonet
+	@echo --- Done ---
+
+$(DIR)/Colonet.class: Colonet.java
+	@echo --- Compiling ---
+	$(JC) $(JCWARN) $(JCFLAGS) Colonet.java
+
+$(DIR)/ColonetServerInterface.class: ColonetServerInterface.java
+	$(JC) $(JCWARN) $(JCFLAGS) ColonetServerInterface.java
+
+install:
+	@echo --- Copying files to /var/www/colonet ---
+	rm -rf /var/www/colonet/
+	mkdir /var/www/colonet/
+	cp $(DIR)/Colonet.jar /var/www/colonet/Colonet.jar
+	cp index.xhtml /var/www/colonet/index.xhtml
+	cp colonetstyle.css /var/www/colonet/colonetstyle.css
+
+clean:
+	$(RM) $(DIR)/*.class
+	$(RM) $(DIR)/*.jar
Index: trunk/code/projects/colonet/client/colonetstyle.css
===================================================================
--- trunk/code/projects/colonet/client/colonetstyle.css	(nonexistent)
+++ trunk/code/projects/colonet/client/colonetstyle.css	(revision 476)
@@ -0,0 +1,45 @@
+/* Colonet Applet Stylesheet */
+/* Gregory Tress */
+
+div
+{
+	background-color: #A00016;
+	color: white;
+	font-family: verdana, arial, helvetica, sans-serif;
+	padding: 2px 2px 2px 2px;
+}
+
+/* Top bar */
+div.top
+{
+	font-size: 14pt;
+}
+div.top img
+{
+	position: absolute;
+	top: 10px;
+	right: 10px;
+}
+
+/* The Applet */
+div.app
+{
+	background-color: white;
+	color: black;
+}
+
+object.applet
+{
+    
+}
+
+/* Bottom bar */
+div.bottom
+{
+	font-size: 12pt;
+}
+div.bottom a
+{
+	color: #DDFFFF;
+}
+
Index: trunk/code/projects/colonet/client/build/colonetkey
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: trunk/code/projects/colonet/client/build/colonetkey
===================================================================
--- trunk/code/projects/colonet/client/build/colonetkey	(nonexistent)
+++ trunk/code/projects/colonet/client/build/colonetkey	(revision 476)

Property changes on: trunk/code/projects/colonet/client/build/colonetkey
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
