diff --git a/Exporter-app.xml b/Exporter-app.xml
old mode 100644
new mode 100755
index 7deb7c5..dbb9ba7
--- a/Exporter-app.xml
+++ b/Exporter-app.xml
@@ -16,7 +16,7 @@
 	Japanese App name goes here
 	
 -->
-
+
   Exporter
   1.0
   Exporter
diff --git a/Exporter-app.xml b/Exporter-app.xml
old mode 100644
new mode 100755
index 7deb7c5..dbb9ba7
--- a/Exporter-app.xml
+++ b/Exporter-app.xml
@@ -16,7 +16,7 @@
 	Japanese App name goes here
 	
 -->
-
+
   Exporter
   1.0
   Exporter
diff --git a/Exporter.as b/Exporter.as
index 7a2a149..c520e93 100644
--- a/Exporter.as
+++ b/Exporter.as
@@ -79,43 +79,88 @@
 				
 			}
 		}
-		
-		private function DispatchCommand(msg)
+
+		private var jobQueue:Array = new Array();
+		private var activeJob:Job = null;
+		private function QueueJob(jobParams)
 		{
-			if (msg.hasOwnProperty("command"))
+			var job:Job = new Job(jobParams);
+			jobQueue.push(job);
+			CheckNewJob();
+		}
+		
+		private function CheckNewJob()
+		{
+			if (activeJob == null && jobQueue.length > 0)
 			{
-				var cmd = "" + msg.command;
-				switch (cmd)
+				activeJob = jobQueue.shift();
+				activeJob.Go(JobComplete);
+			}
+		}
+		
+		private function JobComplete()
+		{
+			Trace("Done: " + activeJob.GetID());
+			DriverCommand("done", activeJob.GetCompletedData());
+			
+			activeJob = null;
+			CheckNewJob();
+		}
+		
+		private function DispatchCommand(cmdData)
+		{
+			try
+			{
+				Trace("recv: " + typeof(cmdData) + " " + cmdData + " " + cmdData.hasOwnProperty("command"));
+				if (cmdData.hasOwnProperty("command"))
 				{
-					case "trace":
-						Trace(msg.command);
-					break;
-					case "quit":
-						Quit();
-					break;
-					default:
-						Trace("Recv: " + JSON.stringify(msg));
-					break;
-				}
+					var cmd = "" + cmdData.command;
+					Trace("cmd: " + cmd);
+					switch (cmd)
+					{
+						case "trace":
+							Trace(cmdData.string);
+						break;
+						case "exit":
+							Quit();
+						break;
+						case "job":
+							QueueJob(cmdData);
+						break;
+						default:
+							Trace("Recv: " + JSON.stringify(cmdData));
+						break;
+					}
+				}
+			} catch (e)
+			{
+				Print(e.toString());
 			}
 		}
 		
 		private function DriverRecv(e)
 		{
+			Trace("recv");
 			try
 			{
-				var cmd = driver.readUTF();
-				DispatchCommand(JSON.parse(cmd));
+				Trace(e.target.bytesAvailable);
+				var msg = driver.readUTF();
+				Trace("msg: " + msg);
+				Trace("avail: " + e.target.bytesAvailable);
+				var cmdData = JSON.parse(msg);
+				Trace("cmdData: " + cmdData + " " + typeof(cmdData));
+				DispatchCommand(cmdData);
 			}
-			catch (e:EOFError)
+			catch (eof:EOFError)
 			{
+				Trace("Waiting for more data... " + e.target.bytesAvailable);
 				// wait for more data
 			}
-			catch (e:IOError)
+			catch (err:IOError)
 			{
 				Trace("Driver IO error");
 			}
-			catch (e)
+			catch (err)
 			{
 				Trace("Problem reading from driver");
 			}
@@ -138,7 +183,9 @@
 		{
 			if (driver != null)
 			{
-				driver.writeUTF(str);
+				Trace(str);
+				driver.writeUTF(str);
+				driver.flush();
 			}
 		}
 		
diff --git a/Exporter-app.xml b/Exporter-app.xml
old mode 100644
new mode 100755
index 7deb7c5..dbb9ba7
--- a/Exporter-app.xml
+++ b/Exporter-app.xml
@@ -16,7 +16,7 @@
 	Japanese App name goes here
 	
 -->
-
+
   Exporter
   1.0
   Exporter
diff --git a/Exporter.as b/Exporter.as
index 7a2a149..c520e93 100644
--- a/Exporter.as
+++ b/Exporter.as
@@ -79,43 +79,88 @@
 				
 			}
 		}
-		
-		private function DispatchCommand(msg)
+
+		private var jobQueue:Array = new Array();
+		private var activeJob:Job = null;
+		private function QueueJob(jobParams)
 		{
-			if (msg.hasOwnProperty("command"))
+			var job:Job = new Job(jobParams);
+			jobQueue.push(job);
+			CheckNewJob();
+		}
+		
+		private function CheckNewJob()
+		{
+			if (activeJob == null && jobQueue.length > 0)
 			{
-				var cmd = "" + msg.command;
-				switch (cmd)
+				activeJob = jobQueue.shift();
+				activeJob.Go(JobComplete);
+			}
+		}
+		
+		private function JobComplete()
+		{
+			Trace("Done: " + activeJob.GetID());
+			DriverCommand("done", activeJob.GetCompletedData());
+			
+			activeJob = null;
+			CheckNewJob();
+		}
+		
+		private function DispatchCommand(cmdData)
+		{
+			try
+			{
+				Trace("recv: " + typeof(cmdData) + " " + cmdData + " " + cmdData.hasOwnProperty("command"));
+				if (cmdData.hasOwnProperty("command"))
 				{
-					case "trace":
-						Trace(msg.command);
-					break;
-					case "quit":
-						Quit();
-					break;
-					default:
-						Trace("Recv: " + JSON.stringify(msg));
-					break;
-				}
+					var cmd = "" + cmdData.command;
+					Trace("cmd: " + cmd);
+					switch (cmd)
+					{
+						case "trace":
+							Trace(cmdData.string);
+						break;
+						case "exit":
+							Quit();
+						break;
+						case "job":
+							QueueJob(cmdData);
+						break;
+						default:
+							Trace("Recv: " + JSON.stringify(cmdData));
+						break;
+					}
+				}
+			} catch (e)
+			{
+				Print(e.toString());
 			}
 		}
 		
 		private function DriverRecv(e)
 		{
+			Trace("recv");
 			try
 			{
-				var cmd = driver.readUTF();
-				DispatchCommand(JSON.parse(cmd));
+				Trace(e.target.bytesAvailable);
+				var msg = driver.readUTF();
+				Trace("msg: " + msg);
+				Trace("avail: " + e.target.bytesAvailable);
+				var cmdData = JSON.parse(msg);
+				Trace("cmdData: " + cmdData + " " + typeof(cmdData));
+				DispatchCommand(cmdData);
 			}
-			catch (e:EOFError)
+			catch (eof:EOFError)
 			{
+				Trace("Waiting for more data... " + e.target.bytesAvailable);
 				// wait for more data
 			}
-			catch (e:IOError)
+			catch (err:IOError)
 			{
 				Trace("Driver IO error");
 			}
-			catch (e)
+			catch (err)
 			{
 				Trace("Problem reading from driver");
 			}
@@ -138,7 +183,9 @@
 		{
 			if (driver != null)
 			{
-				driver.writeUTF(str);
+				Trace(str);
+				driver.writeUTF(str);
+				driver.flush();
 			}
 		}
 		
diff --git a/Exporter.exe b/Exporter.exe
old mode 100644
new mode 100755
index 829fdd0..745928e
--- a/Exporter.exe
+++ b/Exporter.exe
Binary files differ
diff --git a/Exporter-app.xml b/Exporter-app.xml
old mode 100644
new mode 100755
index 7deb7c5..dbb9ba7
--- a/Exporter-app.xml
+++ b/Exporter-app.xml
@@ -16,7 +16,7 @@
 	Japanese App name goes here
 	
 -->
-
+
   Exporter
   1.0
   Exporter
diff --git a/Exporter.as b/Exporter.as
index 7a2a149..c520e93 100644
--- a/Exporter.as
+++ b/Exporter.as
@@ -79,43 +79,88 @@
 				
 			}
 		}
-		
-		private function DispatchCommand(msg)
+
+		private var jobQueue:Array = new Array();
+		private var activeJob:Job = null;
+		private function QueueJob(jobParams)
 		{
-			if (msg.hasOwnProperty("command"))
+			var job:Job = new Job(jobParams);
+			jobQueue.push(job);
+			CheckNewJob();
+		}
+		
+		private function CheckNewJob()
+		{
+			if (activeJob == null && jobQueue.length > 0)
 			{
-				var cmd = "" + msg.command;
-				switch (cmd)
+				activeJob = jobQueue.shift();
+				activeJob.Go(JobComplete);
+			}
+		}
+		
+		private function JobComplete()
+		{
+			Trace("Done: " + activeJob.GetID());
+			DriverCommand("done", activeJob.GetCompletedData());
+			
+			activeJob = null;
+			CheckNewJob();
+		}
+		
+		private function DispatchCommand(cmdData)
+		{
+			try
+			{
+				Trace("recv: " + typeof(cmdData) + " " + cmdData + " " + cmdData.hasOwnProperty("command"));
+				if (cmdData.hasOwnProperty("command"))
 				{
-					case "trace":
-						Trace(msg.command);
-					break;
-					case "quit":
-						Quit();
-					break;
-					default:
-						Trace("Recv: " + JSON.stringify(msg));
-					break;
-				}
+					var cmd = "" + cmdData.command;
+					Trace("cmd: " + cmd);
+					switch (cmd)
+					{
+						case "trace":
+							Trace(cmdData.string);
+						break;
+						case "exit":
+							Quit();
+						break;
+						case "job":
+							QueueJob(cmdData);
+						break;
+						default:
+							Trace("Recv: " + JSON.stringify(cmdData));
+						break;
+					}
+				}
+			} catch (e)
+			{
+				Print(e.toString());
 			}
 		}
 		
 		private function DriverRecv(e)
 		{
+			Trace("recv");
 			try
 			{
-				var cmd = driver.readUTF();
-				DispatchCommand(JSON.parse(cmd));
+				Trace(e.target.bytesAvailable);
+				var msg = driver.readUTF();
+				Trace("msg: " + msg);
+				Trace("avail: " + e.target.bytesAvailable);
+				var cmdData = JSON.parse(msg);
+				Trace("cmdData: " + cmdData + " " + typeof(cmdData));
+				DispatchCommand(cmdData);
 			}
-			catch (e:EOFError)
+			catch (eof:EOFError)
 			{
+				Trace("Waiting for more data... " + e.target.bytesAvailable);
 				// wait for more data
 			}
-			catch (e:IOError)
+			catch (err:IOError)
 			{
 				Trace("Driver IO error");
 			}
-			catch (e)
+			catch (err)
 			{
 				Trace("Problem reading from driver");
 			}
@@ -138,7 +183,9 @@
 		{
 			if (driver != null)
 			{
-				driver.writeUTF(str);
+				Trace(str);
+				driver.writeUTF(str);
+				driver.flush();
 			}
 		}
 		
diff --git a/Exporter.exe b/Exporter.exe
old mode 100644
new mode 100755
index 829fdd0..745928e
--- a/Exporter.exe
+++ b/Exporter.exe
Binary files differ
diff --git a/Exporter.fla b/Exporter.fla
old mode 100644
new mode 100755
index 62c62d2..a0f0ea8
--- a/Exporter.fla
+++ b/Exporter.fla
Binary files differ
diff --git a/Exporter-app.xml b/Exporter-app.xml
old mode 100644
new mode 100755
index 7deb7c5..dbb9ba7
--- a/Exporter-app.xml
+++ b/Exporter-app.xml
@@ -16,7 +16,7 @@
 	Japanese App name goes here
 	
 -->
-
+
   Exporter
   1.0
   Exporter
diff --git a/Exporter.as b/Exporter.as
index 7a2a149..c520e93 100644
--- a/Exporter.as
+++ b/Exporter.as
@@ -79,43 +79,88 @@
 				
 			}
 		}
-		
-		private function DispatchCommand(msg)
+
+		private var jobQueue:Array = new Array();
+		private var activeJob:Job = null;
+		private function QueueJob(jobParams)
 		{
-			if (msg.hasOwnProperty("command"))
+			var job:Job = new Job(jobParams);
+			jobQueue.push(job);
+			CheckNewJob();
+		}
+		
+		private function CheckNewJob()
+		{
+			if (activeJob == null && jobQueue.length > 0)
 			{
-				var cmd = "" + msg.command;
-				switch (cmd)
+				activeJob = jobQueue.shift();
+				activeJob.Go(JobComplete);
+			}
+		}
+		
+		private function JobComplete()
+		{
+			Trace("Done: " + activeJob.GetID());
+			DriverCommand("done", activeJob.GetCompletedData());
+			
+			activeJob = null;
+			CheckNewJob();
+		}
+		
+		private function DispatchCommand(cmdData)
+		{
+			try
+			{
+				Trace("recv: " + typeof(cmdData) + " " + cmdData + " " + cmdData.hasOwnProperty("command"));
+				if (cmdData.hasOwnProperty("command"))
 				{
-					case "trace":
-						Trace(msg.command);
-					break;
-					case "quit":
-						Quit();
-					break;
-					default:
-						Trace("Recv: " + JSON.stringify(msg));
-					break;
-				}
+					var cmd = "" + cmdData.command;
+					Trace("cmd: " + cmd);
+					switch (cmd)
+					{
+						case "trace":
+							Trace(cmdData.string);
+						break;
+						case "exit":
+							Quit();
+						break;
+						case "job":
+							QueueJob(cmdData);
+						break;
+						default:
+							Trace("Recv: " + JSON.stringify(cmdData));
+						break;
+					}
+				}
+			} catch (e)
+			{
+				Print(e.toString());
 			}
 		}
 		
 		private function DriverRecv(e)
 		{
+			Trace("recv");
 			try
 			{
-				var cmd = driver.readUTF();
-				DispatchCommand(JSON.parse(cmd));
+				Trace(e.target.bytesAvailable);
+				var msg = driver.readUTF();
+				Trace("msg: " + msg);
+				Trace("avail: " + e.target.bytesAvailable);
+				var cmdData = JSON.parse(msg);
+				Trace("cmdData: " + cmdData + " " + typeof(cmdData));
+				DispatchCommand(cmdData);
 			}
-			catch (e:EOFError)
+			catch (eof:EOFError)
 			{
+				Trace("Waiting for more data... " + e.target.bytesAvailable);
 				// wait for more data
 			}
-			catch (e:IOError)
+			catch (err:IOError)
 			{
 				Trace("Driver IO error");
 			}
-			catch (e)
+			catch (err)
 			{
 				Trace("Problem reading from driver");
 			}
@@ -138,7 +183,9 @@
 		{
 			if (driver != null)
 			{
-				driver.writeUTF(str);
+				Trace(str);
+				driver.writeUTF(str);
+				driver.flush();
 			}
 		}
 		
diff --git a/Exporter.exe b/Exporter.exe
old mode 100644
new mode 100755
index 829fdd0..745928e
--- a/Exporter.exe
+++ b/Exporter.exe
Binary files differ
diff --git a/Exporter.fla b/Exporter.fla
old mode 100644
new mode 100755
index 62c62d2..a0f0ea8
--- a/Exporter.fla
+++ b/Exporter.fla
Binary files differ
diff --git a/Exporter.swf b/Exporter.swf
index 60adb24..df8c3fb 100644
--- a/Exporter.swf
+++ b/Exporter.swf
Binary files differ
diff --git a/Exporter-app.xml b/Exporter-app.xml
old mode 100644
new mode 100755
index 7deb7c5..dbb9ba7
--- a/Exporter-app.xml
+++ b/Exporter-app.xml
@@ -16,7 +16,7 @@
 	Japanese App name goes here
 	
 -->
-
+
   Exporter
   1.0
   Exporter
diff --git a/Exporter.as b/Exporter.as
index 7a2a149..c520e93 100644
--- a/Exporter.as
+++ b/Exporter.as
@@ -79,43 +79,88 @@
 				
 			}
 		}
-		
-		private function DispatchCommand(msg)
+
+		private var jobQueue:Array = new Array();
+		private var activeJob:Job = null;
+		private function QueueJob(jobParams)
 		{
-			if (msg.hasOwnProperty("command"))
+			var job:Job = new Job(jobParams);
+			jobQueue.push(job);
+			CheckNewJob();
+		}
+		
+		private function CheckNewJob()
+		{
+			if (activeJob == null && jobQueue.length > 0)
 			{
-				var cmd = "" + msg.command;
-				switch (cmd)
+				activeJob = jobQueue.shift();
+				activeJob.Go(JobComplete);
+			}
+		}
+		
+		private function JobComplete()
+		{
+			Trace("Done: " + activeJob.GetID());
+			DriverCommand("done", activeJob.GetCompletedData());
+			
+			activeJob = null;
+			CheckNewJob();
+		}
+		
+		private function DispatchCommand(cmdData)
+		{
+			try
+			{
+				Trace("recv: " + typeof(cmdData) + " " + cmdData + " " + cmdData.hasOwnProperty("command"));
+				if (cmdData.hasOwnProperty("command"))
 				{
-					case "trace":
-						Trace(msg.command);
-					break;
-					case "quit":
-						Quit();
-					break;
-					default:
-						Trace("Recv: " + JSON.stringify(msg));
-					break;
-				}
+					var cmd = "" + cmdData.command;
+					Trace("cmd: " + cmd);
+					switch (cmd)
+					{
+						case "trace":
+							Trace(cmdData.string);
+						break;
+						case "exit":
+							Quit();
+						break;
+						case "job":
+							QueueJob(cmdData);
+						break;
+						default:
+							Trace("Recv: " + JSON.stringify(cmdData));
+						break;
+					}
+				}
+			} catch (e)
+			{
+				Print(e.toString());
 			}
 		}
 		
 		private function DriverRecv(e)
 		{
+			Trace("recv");
 			try
 			{
-				var cmd = driver.readUTF();
-				DispatchCommand(JSON.parse(cmd));
+				Trace(e.target.bytesAvailable);
+				var msg = driver.readUTF();
+				Trace("msg: " + msg);
+				Trace("avail: " + e.target.bytesAvailable);
+				var cmdData = JSON.parse(msg);
+				Trace("cmdData: " + cmdData + " " + typeof(cmdData));
+				DispatchCommand(cmdData);
 			}
-			catch (e:EOFError)
+			catch (eof:EOFError)
 			{
+				Trace("Waiting for more data... " + e.target.bytesAvailable);
 				// wait for more data
 			}
-			catch (e:IOError)
+			catch (err:IOError)
 			{
 				Trace("Driver IO error");
 			}
-			catch (e)
+			catch (err)
 			{
 				Trace("Problem reading from driver");
 			}
@@ -138,7 +183,9 @@
 		{
 			if (driver != null)
 			{
-				driver.writeUTF(str);
+				Trace(str);
+				driver.writeUTF(str);
+				driver.flush();
 			}
 		}
 		
diff --git a/Exporter.exe b/Exporter.exe
old mode 100644
new mode 100755
index 829fdd0..745928e
--- a/Exporter.exe
+++ b/Exporter.exe
Binary files differ
diff --git a/Exporter.fla b/Exporter.fla
old mode 100644
new mode 100755
index 62c62d2..a0f0ea8
--- a/Exporter.fla
+++ b/Exporter.fla
Binary files differ
diff --git a/Exporter.swf b/Exporter.swf
index 60adb24..df8c3fb 100644
--- a/Exporter.swf
+++ b/Exporter.swf
Binary files differ
diff --git a/Job.as b/Job.as
new file mode 100755
index 0000000..859be61
--- /dev/null
+++ b/Job.as
@@ -0,0 +1,31 @@
+package
+{
+	import flash.utils.*;
+	public class Job
+	{
+		private var callback;
+		
+		private var id:int;
+		public function GetID():int { return this.id; }
+		public function Job(details)
+		{
+			id = parseInt(details["id"]);
+			Exporter.Instance.Trace("new job: " + id);
+		}
+		public function Go(callback)
+		{
+			Exporter.Instance.Trace("Job.Go() " + id);
+			this.callback = callback;
+			setTimeout(Done, 500);
+		}
+		public function Done()
+		{
+			Exporter.Instance.Trace("Job.Done() " + id);
+			this.callback();
+		}
+		public function GetCompletedData()
+		{
+			return {id:id};
+		}
+	}
+}
\ No newline at end of file
diff --git a/Exporter-app.xml b/Exporter-app.xml
old mode 100644
new mode 100755
index 7deb7c5..dbb9ba7
--- a/Exporter-app.xml
+++ b/Exporter-app.xml
@@ -16,7 +16,7 @@
 	Japanese App name goes here
 	
 -->
-
+
   Exporter
   1.0
   Exporter
diff --git a/Exporter.as b/Exporter.as
index 7a2a149..c520e93 100644
--- a/Exporter.as
+++ b/Exporter.as
@@ -79,43 +79,88 @@
 				
 			}
 		}
-		
-		private function DispatchCommand(msg)
+
+		private var jobQueue:Array = new Array();
+		private var activeJob:Job = null;
+		private function QueueJob(jobParams)
 		{
-			if (msg.hasOwnProperty("command"))
+			var job:Job = new Job(jobParams);
+			jobQueue.push(job);
+			CheckNewJob();
+		}
+		
+		private function CheckNewJob()
+		{
+			if (activeJob == null && jobQueue.length > 0)
 			{
-				var cmd = "" + msg.command;
-				switch (cmd)
+				activeJob = jobQueue.shift();
+				activeJob.Go(JobComplete);
+			}
+		}
+		
+		private function JobComplete()
+		{
+			Trace("Done: " + activeJob.GetID());
+			DriverCommand("done", activeJob.GetCompletedData());
+			
+			activeJob = null;
+			CheckNewJob();
+		}
+		
+		private function DispatchCommand(cmdData)
+		{
+			try
+			{
+				Trace("recv: " + typeof(cmdData) + " " + cmdData + " " + cmdData.hasOwnProperty("command"));
+				if (cmdData.hasOwnProperty("command"))
 				{
-					case "trace":
-						Trace(msg.command);
-					break;
-					case "quit":
-						Quit();
-					break;
-					default:
-						Trace("Recv: " + JSON.stringify(msg));
-					break;
-				}
+					var cmd = "" + cmdData.command;
+					Trace("cmd: " + cmd);
+					switch (cmd)
+					{
+						case "trace":
+							Trace(cmdData.string);
+						break;
+						case "exit":
+							Quit();
+						break;
+						case "job":
+							QueueJob(cmdData);
+						break;
+						default:
+							Trace("Recv: " + JSON.stringify(cmdData));
+						break;
+					}
+				}
+			} catch (e)
+			{
+				Print(e.toString());
 			}
 		}
 		
 		private function DriverRecv(e)
 		{
+			Trace("recv");
 			try
 			{
-				var cmd = driver.readUTF();
-				DispatchCommand(JSON.parse(cmd));
+				Trace(e.target.bytesAvailable);
+				var msg = driver.readUTF();
+				Trace("msg: " + msg);
+				Trace("avail: " + e.target.bytesAvailable);
+				var cmdData = JSON.parse(msg);
+				Trace("cmdData: " + cmdData + " " + typeof(cmdData));
+				DispatchCommand(cmdData);
 			}
-			catch (e:EOFError)
+			catch (eof:EOFError)
 			{
+				Trace("Waiting for more data... " + e.target.bytesAvailable);
 				// wait for more data
 			}
-			catch (e:IOError)
+			catch (err:IOError)
 			{
 				Trace("Driver IO error");
 			}
-			catch (e)
+			catch (err)
 			{
 				Trace("Problem reading from driver");
 			}
@@ -138,7 +183,9 @@
 		{
 			if (driver != null)
 			{
-				driver.writeUTF(str);
+				Trace(str);
+				driver.writeUTF(str);
+				driver.flush();
 			}
 		}
 		
diff --git a/Exporter.exe b/Exporter.exe
old mode 100644
new mode 100755
index 829fdd0..745928e
--- a/Exporter.exe
+++ b/Exporter.exe
Binary files differ
diff --git a/Exporter.fla b/Exporter.fla
old mode 100644
new mode 100755
index 62c62d2..a0f0ea8
--- a/Exporter.fla
+++ b/Exporter.fla
Binary files differ
diff --git a/Exporter.swf b/Exporter.swf
index 60adb24..df8c3fb 100644
--- a/Exporter.swf
+++ b/Exporter.swf
Binary files differ
diff --git a/Job.as b/Job.as
new file mode 100755
index 0000000..859be61
--- /dev/null
+++ b/Job.as
@@ -0,0 +1,31 @@
+package
+{
+	import flash.utils.*;
+	public class Job
+	{
+		private var callback;
+		
+		private var id:int;
+		public function GetID():int { return this.id; }
+		public function Job(details)
+		{
+			id = parseInt(details["id"]);
+			Exporter.Instance.Trace("new job: " + id);
+		}
+		public function Go(callback)
+		{
+			Exporter.Instance.Trace("Job.Go() " + id);
+			this.callback = callback;
+			setTimeout(Done, 500);
+		}
+		public function Done()
+		{
+			Exporter.Instance.Trace("Job.Done() " + id);
+			this.callback();
+		}
+		public function GetCompletedData()
+		{
+			return {id:id};
+		}
+	}
+}
\ No newline at end of file
diff --git a/args.py b/args.py
index ba9e26b..72e946d 100644
--- a/args.py
+++ b/args.py
@@ -78,4 +78,4 @@
   path = abspath(path)
   if not os.path.isdir(path) or not os.path.isfile(file):
     return False
-  return os.path.commonprefix(path, file) == path
+  return os.path.commonprefix([path, file]) == path
diff --git a/Exporter-app.xml b/Exporter-app.xml
old mode 100644
new mode 100755
index 7deb7c5..dbb9ba7
--- a/Exporter-app.xml
+++ b/Exporter-app.xml
@@ -16,7 +16,7 @@
 	Japanese App name goes here
 	
 -->
-
+
   Exporter
   1.0
   Exporter
diff --git a/Exporter.as b/Exporter.as
index 7a2a149..c520e93 100644
--- a/Exporter.as
+++ b/Exporter.as
@@ -79,43 +79,88 @@
 				
 			}
 		}
-		
-		private function DispatchCommand(msg)
+
+		private var jobQueue:Array = new Array();
+		private var activeJob:Job = null;
+		private function QueueJob(jobParams)
 		{
-			if (msg.hasOwnProperty("command"))
+			var job:Job = new Job(jobParams);
+			jobQueue.push(job);
+			CheckNewJob();
+		}
+		
+		private function CheckNewJob()
+		{
+			if (activeJob == null && jobQueue.length > 0)
 			{
-				var cmd = "" + msg.command;
-				switch (cmd)
+				activeJob = jobQueue.shift();
+				activeJob.Go(JobComplete);
+			}
+		}
+		
+		private function JobComplete()
+		{
+			Trace("Done: " + activeJob.GetID());
+			DriverCommand("done", activeJob.GetCompletedData());
+			
+			activeJob = null;
+			CheckNewJob();
+		}
+		
+		private function DispatchCommand(cmdData)
+		{
+			try
+			{
+				Trace("recv: " + typeof(cmdData) + " " + cmdData + " " + cmdData.hasOwnProperty("command"));
+				if (cmdData.hasOwnProperty("command"))
 				{
-					case "trace":
-						Trace(msg.command);
-					break;
-					case "quit":
-						Quit();
-					break;
-					default:
-						Trace("Recv: " + JSON.stringify(msg));
-					break;
-				}
+					var cmd = "" + cmdData.command;
+					Trace("cmd: " + cmd);
+					switch (cmd)
+					{
+						case "trace":
+							Trace(cmdData.string);
+						break;
+						case "exit":
+							Quit();
+						break;
+						case "job":
+							QueueJob(cmdData);
+						break;
+						default:
+							Trace("Recv: " + JSON.stringify(cmdData));
+						break;
+					}
+				}
+			} catch (e)
+			{
+				Print(e.toString());
 			}
 		}
 		
 		private function DriverRecv(e)
 		{
+			Trace("recv");
 			try
 			{
-				var cmd = driver.readUTF();
-				DispatchCommand(JSON.parse(cmd));
+				Trace(e.target.bytesAvailable);
+				var msg = driver.readUTF();
+				Trace("msg: " + msg);
+				Trace("avail: " + e.target.bytesAvailable);
+				var cmdData = JSON.parse(msg);
+				Trace("cmdData: " + cmdData + " " + typeof(cmdData));
+				DispatchCommand(cmdData);
 			}
-			catch (e:EOFError)
+			catch (eof:EOFError)
 			{
+				Trace("Waiting for more data... " + e.target.bytesAvailable);
 				// wait for more data
 			}
-			catch (e:IOError)
+			catch (err:IOError)
 			{
 				Trace("Driver IO error");
 			}
-			catch (e)
+			catch (err)
 			{
 				Trace("Problem reading from driver");
 			}
@@ -138,7 +183,9 @@
 		{
 			if (driver != null)
 			{
-				driver.writeUTF(str);
+				Trace(str);
+				driver.writeUTF(str);
+				driver.flush();
 			}
 		}
 		
diff --git a/Exporter.exe b/Exporter.exe
old mode 100644
new mode 100755
index 829fdd0..745928e
--- a/Exporter.exe
+++ b/Exporter.exe
Binary files differ
diff --git a/Exporter.fla b/Exporter.fla
old mode 100644
new mode 100755
index 62c62d2..a0f0ea8
--- a/Exporter.fla
+++ b/Exporter.fla
Binary files differ
diff --git a/Exporter.swf b/Exporter.swf
index 60adb24..df8c3fb 100644
--- a/Exporter.swf
+++ b/Exporter.swf
Binary files differ
diff --git a/Job.as b/Job.as
new file mode 100755
index 0000000..859be61
--- /dev/null
+++ b/Job.as
@@ -0,0 +1,31 @@
+package
+{
+	import flash.utils.*;
+	public class Job
+	{
+		private var callback;
+		
+		private var id:int;
+		public function GetID():int { return this.id; }
+		public function Job(details)
+		{
+			id = parseInt(details["id"]);
+			Exporter.Instance.Trace("new job: " + id);
+		}
+		public function Go(callback)
+		{
+			Exporter.Instance.Trace("Job.Go() " + id);
+			this.callback = callback;
+			setTimeout(Done, 500);
+		}
+		public function Done()
+		{
+			Exporter.Instance.Trace("Job.Done() " + id);
+			this.callback();
+		}
+		public function GetCompletedData()
+		{
+			return {id:id};
+		}
+	}
+}
\ No newline at end of file
diff --git a/args.py b/args.py
index ba9e26b..72e946d 100644
--- a/args.py
+++ b/args.py
@@ -78,4 +78,4 @@
   path = abspath(path)
   if not os.path.isdir(path) or not os.path.isfile(file):
     return False
-  return os.path.commonprefix(path, file) == path
+  return os.path.commonprefix([path, file]) == path
diff --git a/driver.py b/driver.py
index d8becd0..53a67ea 100644
--- a/driver.py
+++ b/driver.py
@@ -4,6 +4,9 @@
 import sys
 import threading
 import Queue
+import errno
+import json
+import struct
 
 class Driver:
   def __init__(self, port, use_stdin, use_air = False):
@@ -42,17 +45,17 @@
         self.sock.close()
         self.proc.wait()
         sys.exit(1)
-      self.conn.poll()
+      self.proc.poll()
 
     if self.conn:
       self.conn.setblocking(False)
     return self.conn != None
 
-  def send_msg(self, msg):
-    data = json.dumps(msg)
+  def send_json(self, jsonObj):
+    data = json.dumps(jsonObj)
     datalen = struct.pack(">H", len(data))
-    self.sock.send(datalen)
-    self.sock.send(data)
+    self.conn.send(datalen)
+    self.conn.send(data)
 
   def loop(self, msg_callback, stdin_callback = None):
     buf = ""
@@ -80,9 +83,10 @@
         if line == "":
           quit = True
         elif stdin_callback:
-          stdin_callback(line)
+          if not stdin_callback(line):
+            quit = True
       if quit:
-        self.send_msg(self.conn, {"command":"quit"})
+        self.send_json({"command":"exit"})
         self.conn.close()
         self.sock.close()
         self.proc.kill()
diff --git a/Exporter-app.xml b/Exporter-app.xml
old mode 100644
new mode 100755
index 7deb7c5..dbb9ba7
--- a/Exporter-app.xml
+++ b/Exporter-app.xml
@@ -16,7 +16,7 @@
 	Japanese App name goes here
 	
 -->
-
+
   Exporter
   1.0
   Exporter
diff --git a/Exporter.as b/Exporter.as
index 7a2a149..c520e93 100644
--- a/Exporter.as
+++ b/Exporter.as
@@ -79,43 +79,88 @@
 				
 			}
 		}
-		
-		private function DispatchCommand(msg)
+
+		private var jobQueue:Array = new Array();
+		private var activeJob:Job = null;
+		private function QueueJob(jobParams)
 		{
-			if (msg.hasOwnProperty("command"))
+			var job:Job = new Job(jobParams);
+			jobQueue.push(job);
+			CheckNewJob();
+		}
+		
+		private function CheckNewJob()
+		{
+			if (activeJob == null && jobQueue.length > 0)
 			{
-				var cmd = "" + msg.command;
-				switch (cmd)
+				activeJob = jobQueue.shift();
+				activeJob.Go(JobComplete);
+			}
+		}
+		
+		private function JobComplete()
+		{
+			Trace("Done: " + activeJob.GetID());
+			DriverCommand("done", activeJob.GetCompletedData());
+			
+			activeJob = null;
+			CheckNewJob();
+		}
+		
+		private function DispatchCommand(cmdData)
+		{
+			try
+			{
+				Trace("recv: " + typeof(cmdData) + " " + cmdData + " " + cmdData.hasOwnProperty("command"));
+				if (cmdData.hasOwnProperty("command"))
 				{
-					case "trace":
-						Trace(msg.command);
-					break;
-					case "quit":
-						Quit();
-					break;
-					default:
-						Trace("Recv: " + JSON.stringify(msg));
-					break;
-				}
+					var cmd = "" + cmdData.command;
+					Trace("cmd: " + cmd);
+					switch (cmd)
+					{
+						case "trace":
+							Trace(cmdData.string);
+						break;
+						case "exit":
+							Quit();
+						break;
+						case "job":
+							QueueJob(cmdData);
+						break;
+						default:
+							Trace("Recv: " + JSON.stringify(cmdData));
+						break;
+					}
+				}
+			} catch (e)
+			{
+				Print(e.toString());
 			}
 		}
 		
 		private function DriverRecv(e)
 		{
+			Trace("recv");
 			try
 			{
-				var cmd = driver.readUTF();
-				DispatchCommand(JSON.parse(cmd));
+				Trace(e.target.bytesAvailable);
+				var msg = driver.readUTF();
+				Trace("msg: " + msg);
+				Trace("avail: " + e.target.bytesAvailable);
+				var cmdData = JSON.parse(msg);
+				Trace("cmdData: " + cmdData + " " + typeof(cmdData));
+				DispatchCommand(cmdData);
 			}
-			catch (e:EOFError)
+			catch (eof:EOFError)
 			{
+				Trace("Waiting for more data... " + e.target.bytesAvailable);
 				// wait for more data
 			}
-			catch (e:IOError)
+			catch (err:IOError)
 			{
 				Trace("Driver IO error");
 			}
-			catch (e)
+			catch (err)
 			{
 				Trace("Problem reading from driver");
 			}
@@ -138,7 +183,9 @@
 		{
 			if (driver != null)
 			{
-				driver.writeUTF(str);
+				Trace(str);
+				driver.writeUTF(str);
+				driver.flush();
 			}
 		}
 		
diff --git a/Exporter.exe b/Exporter.exe
old mode 100644
new mode 100755
index 829fdd0..745928e
--- a/Exporter.exe
+++ b/Exporter.exe
Binary files differ
diff --git a/Exporter.fla b/Exporter.fla
old mode 100644
new mode 100755
index 62c62d2..a0f0ea8
--- a/Exporter.fla
+++ b/Exporter.fla
Binary files differ
diff --git a/Exporter.swf b/Exporter.swf
index 60adb24..df8c3fb 100644
--- a/Exporter.swf
+++ b/Exporter.swf
Binary files differ
diff --git a/Job.as b/Job.as
new file mode 100755
index 0000000..859be61
--- /dev/null
+++ b/Job.as
@@ -0,0 +1,31 @@
+package
+{
+	import flash.utils.*;
+	public class Job
+	{
+		private var callback;
+		
+		private var id:int;
+		public function GetID():int { return this.id; }
+		public function Job(details)
+		{
+			id = parseInt(details["id"]);
+			Exporter.Instance.Trace("new job: " + id);
+		}
+		public function Go(callback)
+		{
+			Exporter.Instance.Trace("Job.Go() " + id);
+			this.callback = callback;
+			setTimeout(Done, 500);
+		}
+		public function Done()
+		{
+			Exporter.Instance.Trace("Job.Done() " + id);
+			this.callback();
+		}
+		public function GetCompletedData()
+		{
+			return {id:id};
+		}
+	}
+}
\ No newline at end of file
diff --git a/args.py b/args.py
index ba9e26b..72e946d 100644
--- a/args.py
+++ b/args.py
@@ -78,4 +78,4 @@
   path = abspath(path)
   if not os.path.isdir(path) or not os.path.isfile(file):
     return False
-  return os.path.commonprefix(path, file) == path
+  return os.path.commonprefix([path, file]) == path
diff --git a/driver.py b/driver.py
index d8becd0..53a67ea 100644
--- a/driver.py
+++ b/driver.py
@@ -4,6 +4,9 @@
 import sys
 import threading
 import Queue
+import errno
+import json
+import struct
 
 class Driver:
   def __init__(self, port, use_stdin, use_air = False):
@@ -42,17 +45,17 @@
         self.sock.close()
         self.proc.wait()
         sys.exit(1)
-      self.conn.poll()
+      self.proc.poll()
 
     if self.conn:
       self.conn.setblocking(False)
     return self.conn != None
 
-  def send_msg(self, msg):
-    data = json.dumps(msg)
+  def send_json(self, jsonObj):
+    data = json.dumps(jsonObj)
     datalen = struct.pack(">H", len(data))
-    self.sock.send(datalen)
-    self.sock.send(data)
+    self.conn.send(datalen)
+    self.conn.send(data)
 
   def loop(self, msg_callback, stdin_callback = None):
     buf = ""
@@ -80,9 +83,10 @@
         if line == "":
           quit = True
         elif stdin_callback:
-          stdin_callback(line)
+          if not stdin_callback(line):
+            quit = True
       if quit:
-        self.send_msg(self.conn, {"command":"quit"})
+        self.send_json({"command":"exit"})
         self.conn.close()
         self.sock.close()
         self.proc.kill()
diff --git a/exporter.py b/exporter.py
index 6de7805..027380d 100755
--- a/exporter.py
+++ b/exporter.py
@@ -1,14 +1,12 @@
 #! /usr/bin/python
 
 import socket
-import errno
 import sys
 import os
 import os.path
 import json
 import traceback
 import shlex
-import struct
 from args import *
 from job import *
 from driver import *
@@ -52,33 +50,66 @@
           "scale": args["scale"] if "scale" in args else 1}
 
 jobs = {}
-driver = Driver(port)
+sent_all_jobs = False
+driver = Driver(port, from_stdin)
 
-if driver.start():
+def send_cmd(cmd, **kwargs):
+  global driver
+  kwargs["command"] = cmd
+  driver.send_json(kwargs)
+
+def send_job(job):
+  send_cmd("job", **job.get_cmd())
+
+def check_jobs_done():
+  global sent_all_, jobs
+  return sent_all_jobs and not len(jobs)
+
+if not from_stdin:
+  base_args = make_base_job_args(args)
+  for i in args["input"]:
+    try:
+      job = Job(input = i, **base_args)
+      jobs[job.id] = job
+    except Exception, e:
+      print e
+  sent_all_jobs = True
+  if check_jobs_done():
+    sys.exit(0)
+
+driver_started = driver.start()
+
+if driver_started:
   if not from_stdin:
-    base_args = make_base_job_args(args)
-    for i in args["input"]:
-      try:
-        job = Job(base_args, input = i)
-        jobs[job.id] = job
-      except Exception, e:
-        print e
-
-driver.loop(handle_command, handle_stdin)
+    for id in jobs:
+      send_job(jobs[id])
 
 def handle_stdin(line):
+  global sent_all_jobs, jobs
+  if line is None:
+    sent_all_jobs = True
+    if check_jobs_done():
+      return False
+    return True
   parts = shlex.split(line)
   (err, line_args) = ArgParser.parse_args(parts)
   if err is not None:
     print err
   else:
-    base_args= make_base_job_args(line_args)
+    base_args = make_base_job_args(dict(args.items() + line_args.items()))
     for i in line_args["input"]:
-      pass
-      #send_job(conn, base_cmd, i)
+      try:
+        job = Job(input = i, **base_args)
+        jobs[job.id] = job
+      except Exception, e:
+        print e
+      send_job(job)
+  return True
 
 def handle_command(msg_str):
+  # return False to quit the driver loop
   msg = json.loads(msg_str)
+  print msg
   if "command" in msg:
     cmd = msg["command"]
     if cmd == "exit":
@@ -86,10 +117,14 @@
     if cmd == "print" and "string" in msg:
       sys.stdout.write(msg["string"])
       sys.stdout.flush()
-    if cmd == "done" and "job_num" in msg:
-      job_num = int(cmd["job_num"])
-      if job_num == num_jobs_sent:
-        return False
+    if cmd == "done" and "id" in msg:
+      id = int(msg["id"])
+      if id in jobs:
+        jobs.pop(id)
+        if check_jobs_done():
+          return False
   return True
 
-
+# still have to loop() even if we didn't start succesfully,
+# as we may be waiting for the exporter process to close
+driver.loop(handle_command, handle_stdin)
diff --git a/Exporter-app.xml b/Exporter-app.xml
old mode 100644
new mode 100755
index 7deb7c5..dbb9ba7
--- a/Exporter-app.xml
+++ b/Exporter-app.xml
@@ -16,7 +16,7 @@
 	Japanese App name goes here
 	
 -->
-
+
   Exporter
   1.0
   Exporter
diff --git a/Exporter.as b/Exporter.as
index 7a2a149..c520e93 100644
--- a/Exporter.as
+++ b/Exporter.as
@@ -79,43 +79,88 @@
 				
 			}
 		}
-		
-		private function DispatchCommand(msg)
+
+		private var jobQueue:Array = new Array();
+		private var activeJob:Job = null;
+		private function QueueJob(jobParams)
 		{
-			if (msg.hasOwnProperty("command"))
+			var job:Job = new Job(jobParams);
+			jobQueue.push(job);
+			CheckNewJob();
+		}
+		
+		private function CheckNewJob()
+		{
+			if (activeJob == null && jobQueue.length > 0)
 			{
-				var cmd = "" + msg.command;
-				switch (cmd)
+				activeJob = jobQueue.shift();
+				activeJob.Go(JobComplete);
+			}
+		}
+		
+		private function JobComplete()
+		{
+			Trace("Done: " + activeJob.GetID());
+			DriverCommand("done", activeJob.GetCompletedData());
+			
+			activeJob = null;
+			CheckNewJob();
+		}
+		
+		private function DispatchCommand(cmdData)
+		{
+			try
+			{
+				Trace("recv: " + typeof(cmdData) + " " + cmdData + " " + cmdData.hasOwnProperty("command"));
+				if (cmdData.hasOwnProperty("command"))
 				{
-					case "trace":
-						Trace(msg.command);
-					break;
-					case "quit":
-						Quit();
-					break;
-					default:
-						Trace("Recv: " + JSON.stringify(msg));
-					break;
-				}
+					var cmd = "" + cmdData.command;
+					Trace("cmd: " + cmd);
+					switch (cmd)
+					{
+						case "trace":
+							Trace(cmdData.string);
+						break;
+						case "exit":
+							Quit();
+						break;
+						case "job":
+							QueueJob(cmdData);
+						break;
+						default:
+							Trace("Recv: " + JSON.stringify(cmdData));
+						break;
+					}
+				}
+			} catch (e)
+			{
+				Print(e.toString());
 			}
 		}
 		
 		private function DriverRecv(e)
 		{
+			Trace("recv");
 			try
 			{
-				var cmd = driver.readUTF();
-				DispatchCommand(JSON.parse(cmd));
+				Trace(e.target.bytesAvailable);
+				var msg = driver.readUTF();
+				Trace("msg: " + msg);
+				Trace("avail: " + e.target.bytesAvailable);
+				var cmdData = JSON.parse(msg);
+				Trace("cmdData: " + cmdData + " " + typeof(cmdData));
+				DispatchCommand(cmdData);
 			}
-			catch (e:EOFError)
+			catch (eof:EOFError)
 			{
+				Trace("Waiting for more data... " + e.target.bytesAvailable);
 				// wait for more data
 			}
-			catch (e:IOError)
+			catch (err:IOError)
 			{
 				Trace("Driver IO error");
 			}
-			catch (e)
+			catch (err)
 			{
 				Trace("Problem reading from driver");
 			}
@@ -138,7 +183,9 @@
 		{
 			if (driver != null)
 			{
-				driver.writeUTF(str);
+				Trace(str);
+				driver.writeUTF(str);
+				driver.flush();
 			}
 		}
 		
diff --git a/Exporter.exe b/Exporter.exe
old mode 100644
new mode 100755
index 829fdd0..745928e
--- a/Exporter.exe
+++ b/Exporter.exe
Binary files differ
diff --git a/Exporter.fla b/Exporter.fla
old mode 100644
new mode 100755
index 62c62d2..a0f0ea8
--- a/Exporter.fla
+++ b/Exporter.fla
Binary files differ
diff --git a/Exporter.swf b/Exporter.swf
index 60adb24..df8c3fb 100644
--- a/Exporter.swf
+++ b/Exporter.swf
Binary files differ
diff --git a/Job.as b/Job.as
new file mode 100755
index 0000000..859be61
--- /dev/null
+++ b/Job.as
@@ -0,0 +1,31 @@
+package
+{
+	import flash.utils.*;
+	public class Job
+	{
+		private var callback;
+		
+		private var id:int;
+		public function GetID():int { return this.id; }
+		public function Job(details)
+		{
+			id = parseInt(details["id"]);
+			Exporter.Instance.Trace("new job: " + id);
+		}
+		public function Go(callback)
+		{
+			Exporter.Instance.Trace("Job.Go() " + id);
+			this.callback = callback;
+			setTimeout(Done, 500);
+		}
+		public function Done()
+		{
+			Exporter.Instance.Trace("Job.Done() " + id);
+			this.callback();
+		}
+		public function GetCompletedData()
+		{
+			return {id:id};
+		}
+	}
+}
\ No newline at end of file
diff --git a/args.py b/args.py
index ba9e26b..72e946d 100644
--- a/args.py
+++ b/args.py
@@ -78,4 +78,4 @@
   path = abspath(path)
   if not os.path.isdir(path) or not os.path.isfile(file):
     return False
-  return os.path.commonprefix(path, file) == path
+  return os.path.commonprefix([path, file]) == path
diff --git a/driver.py b/driver.py
index d8becd0..53a67ea 100644
--- a/driver.py
+++ b/driver.py
@@ -4,6 +4,9 @@
 import sys
 import threading
 import Queue
+import errno
+import json
+import struct
 
 class Driver:
   def __init__(self, port, use_stdin, use_air = False):
@@ -42,17 +45,17 @@
         self.sock.close()
         self.proc.wait()
         sys.exit(1)
-      self.conn.poll()
+      self.proc.poll()
 
     if self.conn:
       self.conn.setblocking(False)
     return self.conn != None
 
-  def send_msg(self, msg):
-    data = json.dumps(msg)
+  def send_json(self, jsonObj):
+    data = json.dumps(jsonObj)
     datalen = struct.pack(">H", len(data))
-    self.sock.send(datalen)
-    self.sock.send(data)
+    self.conn.send(datalen)
+    self.conn.send(data)
 
   def loop(self, msg_callback, stdin_callback = None):
     buf = ""
@@ -80,9 +83,10 @@
         if line == "":
           quit = True
         elif stdin_callback:
-          stdin_callback(line)
+          if not stdin_callback(line):
+            quit = True
       if quit:
-        self.send_msg(self.conn, {"command":"quit"})
+        self.send_json({"command":"exit"})
         self.conn.close()
         self.sock.close()
         self.proc.kill()
diff --git a/exporter.py b/exporter.py
index 6de7805..027380d 100755
--- a/exporter.py
+++ b/exporter.py
@@ -1,14 +1,12 @@
 #! /usr/bin/python
 
 import socket
-import errno
 import sys
 import os
 import os.path
 import json
 import traceback
 import shlex
-import struct
 from args import *
 from job import *
 from driver import *
@@ -52,33 +50,66 @@
           "scale": args["scale"] if "scale" in args else 1}
 
 jobs = {}
-driver = Driver(port)
+sent_all_jobs = False
+driver = Driver(port, from_stdin)
 
-if driver.start():
+def send_cmd(cmd, **kwargs):
+  global driver
+  kwargs["command"] = cmd
+  driver.send_json(kwargs)
+
+def send_job(job):
+  send_cmd("job", **job.get_cmd())
+
+def check_jobs_done():
+  global sent_all_, jobs
+  return sent_all_jobs and not len(jobs)
+
+if not from_stdin:
+  base_args = make_base_job_args(args)
+  for i in args["input"]:
+    try:
+      job = Job(input = i, **base_args)
+      jobs[job.id] = job
+    except Exception, e:
+      print e
+  sent_all_jobs = True
+  if check_jobs_done():
+    sys.exit(0)
+
+driver_started = driver.start()
+
+if driver_started:
   if not from_stdin:
-    base_args = make_base_job_args(args)
-    for i in args["input"]:
-      try:
-        job = Job(base_args, input = i)
-        jobs[job.id] = job
-      except Exception, e:
-        print e
-
-driver.loop(handle_command, handle_stdin)
+    for id in jobs:
+      send_job(jobs[id])
 
 def handle_stdin(line):
+  global sent_all_jobs, jobs
+  if line is None:
+    sent_all_jobs = True
+    if check_jobs_done():
+      return False
+    return True
   parts = shlex.split(line)
   (err, line_args) = ArgParser.parse_args(parts)
   if err is not None:
     print err
   else:
-    base_args= make_base_job_args(line_args)
+    base_args = make_base_job_args(dict(args.items() + line_args.items()))
     for i in line_args["input"]:
-      pass
-      #send_job(conn, base_cmd, i)
+      try:
+        job = Job(input = i, **base_args)
+        jobs[job.id] = job
+      except Exception, e:
+        print e
+      send_job(job)
+  return True
 
 def handle_command(msg_str):
+  # return False to quit the driver loop
   msg = json.loads(msg_str)
+  print msg
   if "command" in msg:
     cmd = msg["command"]
     if cmd == "exit":
@@ -86,10 +117,14 @@
     if cmd == "print" and "string" in msg:
       sys.stdout.write(msg["string"])
       sys.stdout.flush()
-    if cmd == "done" and "job_num" in msg:
-      job_num = int(cmd["job_num"])
-      if job_num == num_jobs_sent:
-        return False
+    if cmd == "done" and "id" in msg:
+      id = int(msg["id"])
+      if id in jobs:
+        jobs.pop(id)
+        if check_jobs_done():
+          return False
   return True
 
-
+# still have to loop() even if we didn't start succesfully,
+# as we may be waiting for the exporter process to close
+driver.loop(handle_command, handle_stdin)
diff --git a/files.txt b/files.txt
new file mode 100755
index 0000000..0bfe689
--- /dev/null
+++ b/files.txt
@@ -0,0 +1,29 @@
+AnimationPiece.as					// represents single skeletal piece (stores graphic, or frames, + name)
+AnimationPieceSet.as				//
+AnimPieceExportBuilder.as
+AnimSetExportBuilder.as
+CharacterExporter.as
+CharacterSequence.as
+CharacterTypeGraphic.as
+ExportBuilder.as
+JSONPNGSetSaver.as
+Piece.as
+PieceFrameInfo.as
+PieceLibrary.as
+PieceSequence.as
+AnimPiecePacker.as
+AnimSetPacker.as
+IconPacker.as
+ScenePacker.as
+SkelAnimPacker.as
+AsyncGraphicPacker.as
+BitmapFont.as
+BitmapFontCopy.as
+FontCodepointData.as
+GraphicDefClipCollection.as
+GraphicPacker.as
+JSONPNGSetSaver.as
+ChunkedGraphic.as
+FileExportSet.as
+JSONPNGSet.as
+PNGExportHelper.as
diff --git a/Exporter-app.xml b/Exporter-app.xml
old mode 100644
new mode 100755
index 7deb7c5..dbb9ba7
--- a/Exporter-app.xml
+++ b/Exporter-app.xml
@@ -16,7 +16,7 @@
 	Japanese App name goes here
 	
 -->
-
+
   Exporter
   1.0
   Exporter
diff --git a/Exporter.as b/Exporter.as
index 7a2a149..c520e93 100644
--- a/Exporter.as
+++ b/Exporter.as
@@ -79,43 +79,88 @@
 				
 			}
 		}
-		
-		private function DispatchCommand(msg)
+
+		private var jobQueue:Array = new Array();
+		private var activeJob:Job = null;
+		private function QueueJob(jobParams)
 		{
-			if (msg.hasOwnProperty("command"))
+			var job:Job = new Job(jobParams);
+			jobQueue.push(job);
+			CheckNewJob();
+		}
+		
+		private function CheckNewJob()
+		{
+			if (activeJob == null && jobQueue.length > 0)
 			{
-				var cmd = "" + msg.command;
-				switch (cmd)
+				activeJob = jobQueue.shift();
+				activeJob.Go(JobComplete);
+			}
+		}
+		
+		private function JobComplete()
+		{
+			Trace("Done: " + activeJob.GetID());
+			DriverCommand("done", activeJob.GetCompletedData());
+			
+			activeJob = null;
+			CheckNewJob();
+		}
+		
+		private function DispatchCommand(cmdData)
+		{
+			try
+			{
+				Trace("recv: " + typeof(cmdData) + " " + cmdData + " " + cmdData.hasOwnProperty("command"));
+				if (cmdData.hasOwnProperty("command"))
 				{
-					case "trace":
-						Trace(msg.command);
-					break;
-					case "quit":
-						Quit();
-					break;
-					default:
-						Trace("Recv: " + JSON.stringify(msg));
-					break;
-				}
+					var cmd = "" + cmdData.command;
+					Trace("cmd: " + cmd);
+					switch (cmd)
+					{
+						case "trace":
+							Trace(cmdData.string);
+						break;
+						case "exit":
+							Quit();
+						break;
+						case "job":
+							QueueJob(cmdData);
+						break;
+						default:
+							Trace("Recv: " + JSON.stringify(cmdData));
+						break;
+					}
+				}
+			} catch (e)
+			{
+				Print(e.toString());
 			}
 		}
 		
 		private function DriverRecv(e)
 		{
+			Trace("recv");
 			try
 			{
-				var cmd = driver.readUTF();
-				DispatchCommand(JSON.parse(cmd));
+				Trace(e.target.bytesAvailable);
+				var msg = driver.readUTF();
+				Trace("msg: " + msg);
+				Trace("avail: " + e.target.bytesAvailable);
+				var cmdData = JSON.parse(msg);
+				Trace("cmdData: " + cmdData + " " + typeof(cmdData));
+				DispatchCommand(cmdData);
 			}
-			catch (e:EOFError)
+			catch (eof:EOFError)
 			{
+				Trace("Waiting for more data... " + e.target.bytesAvailable);
 				// wait for more data
 			}
-			catch (e:IOError)
+			catch (err:IOError)
 			{
 				Trace("Driver IO error");
 			}
-			catch (e)
+			catch (err)
 			{
 				Trace("Problem reading from driver");
 			}
@@ -138,7 +183,9 @@
 		{
 			if (driver != null)
 			{
-				driver.writeUTF(str);
+				Trace(str);
+				driver.writeUTF(str);
+				driver.flush();
 			}
 		}
 		
diff --git a/Exporter.exe b/Exporter.exe
old mode 100644
new mode 100755
index 829fdd0..745928e
--- a/Exporter.exe
+++ b/Exporter.exe
Binary files differ
diff --git a/Exporter.fla b/Exporter.fla
old mode 100644
new mode 100755
index 62c62d2..a0f0ea8
--- a/Exporter.fla
+++ b/Exporter.fla
Binary files differ
diff --git a/Exporter.swf b/Exporter.swf
index 60adb24..df8c3fb 100644
--- a/Exporter.swf
+++ b/Exporter.swf
Binary files differ
diff --git a/Job.as b/Job.as
new file mode 100755
index 0000000..859be61
--- /dev/null
+++ b/Job.as
@@ -0,0 +1,31 @@
+package
+{
+	import flash.utils.*;
+	public class Job
+	{
+		private var callback;
+		
+		private var id:int;
+		public function GetID():int { return this.id; }
+		public function Job(details)
+		{
+			id = parseInt(details["id"]);
+			Exporter.Instance.Trace("new job: " + id);
+		}
+		public function Go(callback)
+		{
+			Exporter.Instance.Trace("Job.Go() " + id);
+			this.callback = callback;
+			setTimeout(Done, 500);
+		}
+		public function Done()
+		{
+			Exporter.Instance.Trace("Job.Done() " + id);
+			this.callback();
+		}
+		public function GetCompletedData()
+		{
+			return {id:id};
+		}
+	}
+}
\ No newline at end of file
diff --git a/args.py b/args.py
index ba9e26b..72e946d 100644
--- a/args.py
+++ b/args.py
@@ -78,4 +78,4 @@
   path = abspath(path)
   if not os.path.isdir(path) or not os.path.isfile(file):
     return False
-  return os.path.commonprefix(path, file) == path
+  return os.path.commonprefix([path, file]) == path
diff --git a/driver.py b/driver.py
index d8becd0..53a67ea 100644
--- a/driver.py
+++ b/driver.py
@@ -4,6 +4,9 @@
 import sys
 import threading
 import Queue
+import errno
+import json
+import struct
 
 class Driver:
   def __init__(self, port, use_stdin, use_air = False):
@@ -42,17 +45,17 @@
         self.sock.close()
         self.proc.wait()
         sys.exit(1)
-      self.conn.poll()
+      self.proc.poll()
 
     if self.conn:
       self.conn.setblocking(False)
     return self.conn != None
 
-  def send_msg(self, msg):
-    data = json.dumps(msg)
+  def send_json(self, jsonObj):
+    data = json.dumps(jsonObj)
     datalen = struct.pack(">H", len(data))
-    self.sock.send(datalen)
-    self.sock.send(data)
+    self.conn.send(datalen)
+    self.conn.send(data)
 
   def loop(self, msg_callback, stdin_callback = None):
     buf = ""
@@ -80,9 +83,10 @@
         if line == "":
           quit = True
         elif stdin_callback:
-          stdin_callback(line)
+          if not stdin_callback(line):
+            quit = True
       if quit:
-        self.send_msg(self.conn, {"command":"quit"})
+        self.send_json({"command":"exit"})
         self.conn.close()
         self.sock.close()
         self.proc.kill()
diff --git a/exporter.py b/exporter.py
index 6de7805..027380d 100755
--- a/exporter.py
+++ b/exporter.py
@@ -1,14 +1,12 @@
 #! /usr/bin/python
 
 import socket
-import errno
 import sys
 import os
 import os.path
 import json
 import traceback
 import shlex
-import struct
 from args import *
 from job import *
 from driver import *
@@ -52,33 +50,66 @@
           "scale": args["scale"] if "scale" in args else 1}
 
 jobs = {}
-driver = Driver(port)
+sent_all_jobs = False
+driver = Driver(port, from_stdin)
 
-if driver.start():
+def send_cmd(cmd, **kwargs):
+  global driver
+  kwargs["command"] = cmd
+  driver.send_json(kwargs)
+
+def send_job(job):
+  send_cmd("job", **job.get_cmd())
+
+def check_jobs_done():
+  global sent_all_, jobs
+  return sent_all_jobs and not len(jobs)
+
+if not from_stdin:
+  base_args = make_base_job_args(args)
+  for i in args["input"]:
+    try:
+      job = Job(input = i, **base_args)
+      jobs[job.id] = job
+    except Exception, e:
+      print e
+  sent_all_jobs = True
+  if check_jobs_done():
+    sys.exit(0)
+
+driver_started = driver.start()
+
+if driver_started:
   if not from_stdin:
-    base_args = make_base_job_args(args)
-    for i in args["input"]:
-      try:
-        job = Job(base_args, input = i)
-        jobs[job.id] = job
-      except Exception, e:
-        print e
-
-driver.loop(handle_command, handle_stdin)
+    for id in jobs:
+      send_job(jobs[id])
 
 def handle_stdin(line):
+  global sent_all_jobs, jobs
+  if line is None:
+    sent_all_jobs = True
+    if check_jobs_done():
+      return False
+    return True
   parts = shlex.split(line)
   (err, line_args) = ArgParser.parse_args(parts)
   if err is not None:
     print err
   else:
-    base_args= make_base_job_args(line_args)
+    base_args = make_base_job_args(dict(args.items() + line_args.items()))
     for i in line_args["input"]:
-      pass
-      #send_job(conn, base_cmd, i)
+      try:
+        job = Job(input = i, **base_args)
+        jobs[job.id] = job
+      except Exception, e:
+        print e
+      send_job(job)
+  return True
 
 def handle_command(msg_str):
+  # return False to quit the driver loop
   msg = json.loads(msg_str)
+  print msg
   if "command" in msg:
     cmd = msg["command"]
     if cmd == "exit":
@@ -86,10 +117,14 @@
     if cmd == "print" and "string" in msg:
       sys.stdout.write(msg["string"])
       sys.stdout.flush()
-    if cmd == "done" and "job_num" in msg:
-      job_num = int(cmd["job_num"])
-      if job_num == num_jobs_sent:
-        return False
+    if cmd == "done" and "id" in msg:
+      id = int(msg["id"])
+      if id in jobs:
+        jobs.pop(id)
+        if check_jobs_done():
+          return False
   return True
 
-
+# still have to loop() even if we didn't start succesfully,
+# as we may be waiting for the exporter process to close
+driver.loop(handle_command, handle_stdin)
diff --git a/files.txt b/files.txt
new file mode 100755
index 0000000..0bfe689
--- /dev/null
+++ b/files.txt
@@ -0,0 +1,29 @@
+AnimationPiece.as					// represents single skeletal piece (stores graphic, or frames, + name)
+AnimationPieceSet.as				//
+AnimPieceExportBuilder.as
+AnimSetExportBuilder.as
+CharacterExporter.as
+CharacterSequence.as
+CharacterTypeGraphic.as
+ExportBuilder.as
+JSONPNGSetSaver.as
+Piece.as
+PieceFrameInfo.as
+PieceLibrary.as
+PieceSequence.as
+AnimPiecePacker.as
+AnimSetPacker.as
+IconPacker.as
+ScenePacker.as
+SkelAnimPacker.as
+AsyncGraphicPacker.as
+BitmapFont.as
+BitmapFontCopy.as
+FontCodepointData.as
+GraphicDefClipCollection.as
+GraphicPacker.as
+JSONPNGSetSaver.as
+ChunkedGraphic.as
+FileExportSet.as
+JSONPNGSet.as
+PNGExportHelper.as
diff --git a/job.py b/job.py
index 4385544..d100368 100644
--- a/job.py
+++ b/job.py
@@ -1,16 +1,18 @@
 import os.path
+from args import *
 
 class Job:
   next_id = 0
   def __init__(self, input, type = 1, scale = 1, base = None):
     if not os.path.isfile(input):
       raise Exception("Failed: couldn't open " + input)
-    self.id = next_id
-    next_id += 1
+    self.id = Job.next_id
+    Job.next_id += 1
     self.input = abspath(input)
     self.base = base if base is not None else os.path.split(input)[0]
     if not file_in_path(self.input, self.base):
       raise Exception("Failed: " + input + " is not in base dir " + self.base)
     self.type = type
     self.scale = scale
-    self.done = False
+  def get_cmd(self):
+    return {"type":self.type, "scale":self.scale, "id":self.id}
diff --git a/Exporter-app.xml b/Exporter-app.xml
old mode 100644
new mode 100755
index 7deb7c5..dbb9ba7
--- a/Exporter-app.xml
+++ b/Exporter-app.xml
@@ -16,7 +16,7 @@
 	Japanese App name goes here
 	
 -->
-
+
   Exporter
   1.0
   Exporter
diff --git a/Exporter.as b/Exporter.as
index 7a2a149..c520e93 100644
--- a/Exporter.as
+++ b/Exporter.as
@@ -79,43 +79,88 @@
 				
 			}
 		}
-		
-		private function DispatchCommand(msg)
+
+		private var jobQueue:Array = new Array();
+		private var activeJob:Job = null;
+		private function QueueJob(jobParams)
 		{
-			if (msg.hasOwnProperty("command"))
+			var job:Job = new Job(jobParams);
+			jobQueue.push(job);
+			CheckNewJob();
+		}
+		
+		private function CheckNewJob()
+		{
+			if (activeJob == null && jobQueue.length > 0)
 			{
-				var cmd = "" + msg.command;
-				switch (cmd)
+				activeJob = jobQueue.shift();
+				activeJob.Go(JobComplete);
+			}
+		}
+		
+		private function JobComplete()
+		{
+			Trace("Done: " + activeJob.GetID());
+			DriverCommand("done", activeJob.GetCompletedData());
+			
+			activeJob = null;
+			CheckNewJob();
+		}
+		
+		private function DispatchCommand(cmdData)
+		{
+			try
+			{
+				Trace("recv: " + typeof(cmdData) + " " + cmdData + " " + cmdData.hasOwnProperty("command"));
+				if (cmdData.hasOwnProperty("command"))
 				{
-					case "trace":
-						Trace(msg.command);
-					break;
-					case "quit":
-						Quit();
-					break;
-					default:
-						Trace("Recv: " + JSON.stringify(msg));
-					break;
-				}
+					var cmd = "" + cmdData.command;
+					Trace("cmd: " + cmd);
+					switch (cmd)
+					{
+						case "trace":
+							Trace(cmdData.string);
+						break;
+						case "exit":
+							Quit();
+						break;
+						case "job":
+							QueueJob(cmdData);
+						break;
+						default:
+							Trace("Recv: " + JSON.stringify(cmdData));
+						break;
+					}
+				}
+			} catch (e)
+			{
+				Print(e.toString());
 			}
 		}
 		
 		private function DriverRecv(e)
 		{
+			Trace("recv");
 			try
 			{
-				var cmd = driver.readUTF();
-				DispatchCommand(JSON.parse(cmd));
+				Trace(e.target.bytesAvailable);
+				var msg = driver.readUTF();
+				Trace("msg: " + msg);
+				Trace("avail: " + e.target.bytesAvailable);
+				var cmdData = JSON.parse(msg);
+				Trace("cmdData: " + cmdData + " " + typeof(cmdData));
+				DispatchCommand(cmdData);
 			}
-			catch (e:EOFError)
+			catch (eof:EOFError)
 			{
+				Trace("Waiting for more data... " + e.target.bytesAvailable);
 				// wait for more data
 			}
-			catch (e:IOError)
+			catch (err:IOError)
 			{
 				Trace("Driver IO error");
 			}
-			catch (e)
+			catch (err)
 			{
 				Trace("Problem reading from driver");
 			}
@@ -138,7 +183,9 @@
 		{
 			if (driver != null)
 			{
-				driver.writeUTF(str);
+				Trace(str);
+				driver.writeUTF(str);
+				driver.flush();
 			}
 		}
 		
diff --git a/Exporter.exe b/Exporter.exe
old mode 100644
new mode 100755
index 829fdd0..745928e
--- a/Exporter.exe
+++ b/Exporter.exe
Binary files differ
diff --git a/Exporter.fla b/Exporter.fla
old mode 100644
new mode 100755
index 62c62d2..a0f0ea8
--- a/Exporter.fla
+++ b/Exporter.fla
Binary files differ
diff --git a/Exporter.swf b/Exporter.swf
index 60adb24..df8c3fb 100644
--- a/Exporter.swf
+++ b/Exporter.swf
Binary files differ
diff --git a/Job.as b/Job.as
new file mode 100755
index 0000000..859be61
--- /dev/null
+++ b/Job.as
@@ -0,0 +1,31 @@
+package
+{
+	import flash.utils.*;
+	public class Job
+	{
+		private var callback;
+		
+		private var id:int;
+		public function GetID():int { return this.id; }
+		public function Job(details)
+		{
+			id = parseInt(details["id"]);
+			Exporter.Instance.Trace("new job: " + id);
+		}
+		public function Go(callback)
+		{
+			Exporter.Instance.Trace("Job.Go() " + id);
+			this.callback = callback;
+			setTimeout(Done, 500);
+		}
+		public function Done()
+		{
+			Exporter.Instance.Trace("Job.Done() " + id);
+			this.callback();
+		}
+		public function GetCompletedData()
+		{
+			return {id:id};
+		}
+	}
+}
\ No newline at end of file
diff --git a/args.py b/args.py
index ba9e26b..72e946d 100644
--- a/args.py
+++ b/args.py
@@ -78,4 +78,4 @@
   path = abspath(path)
   if not os.path.isdir(path) or not os.path.isfile(file):
     return False
-  return os.path.commonprefix(path, file) == path
+  return os.path.commonprefix([path, file]) == path
diff --git a/driver.py b/driver.py
index d8becd0..53a67ea 100644
--- a/driver.py
+++ b/driver.py
@@ -4,6 +4,9 @@
 import sys
 import threading
 import Queue
+import errno
+import json
+import struct
 
 class Driver:
   def __init__(self, port, use_stdin, use_air = False):
@@ -42,17 +45,17 @@
         self.sock.close()
         self.proc.wait()
         sys.exit(1)
-      self.conn.poll()
+      self.proc.poll()
 
     if self.conn:
       self.conn.setblocking(False)
     return self.conn != None
 
-  def send_msg(self, msg):
-    data = json.dumps(msg)
+  def send_json(self, jsonObj):
+    data = json.dumps(jsonObj)
     datalen = struct.pack(">H", len(data))
-    self.sock.send(datalen)
-    self.sock.send(data)
+    self.conn.send(datalen)
+    self.conn.send(data)
 
   def loop(self, msg_callback, stdin_callback = None):
     buf = ""
@@ -80,9 +83,10 @@
         if line == "":
           quit = True
         elif stdin_callback:
-          stdin_callback(line)
+          if not stdin_callback(line):
+            quit = True
       if quit:
-        self.send_msg(self.conn, {"command":"quit"})
+        self.send_json({"command":"exit"})
         self.conn.close()
         self.sock.close()
         self.proc.kill()
diff --git a/exporter.py b/exporter.py
index 6de7805..027380d 100755
--- a/exporter.py
+++ b/exporter.py
@@ -1,14 +1,12 @@
 #! /usr/bin/python
 
 import socket
-import errno
 import sys
 import os
 import os.path
 import json
 import traceback
 import shlex
-import struct
 from args import *
 from job import *
 from driver import *
@@ -52,33 +50,66 @@
           "scale": args["scale"] if "scale" in args else 1}
 
 jobs = {}
-driver = Driver(port)
+sent_all_jobs = False
+driver = Driver(port, from_stdin)
 
-if driver.start():
+def send_cmd(cmd, **kwargs):
+  global driver
+  kwargs["command"] = cmd
+  driver.send_json(kwargs)
+
+def send_job(job):
+  send_cmd("job", **job.get_cmd())
+
+def check_jobs_done():
+  global sent_all_, jobs
+  return sent_all_jobs and not len(jobs)
+
+if not from_stdin:
+  base_args = make_base_job_args(args)
+  for i in args["input"]:
+    try:
+      job = Job(input = i, **base_args)
+      jobs[job.id] = job
+    except Exception, e:
+      print e
+  sent_all_jobs = True
+  if check_jobs_done():
+    sys.exit(0)
+
+driver_started = driver.start()
+
+if driver_started:
   if not from_stdin:
-    base_args = make_base_job_args(args)
-    for i in args["input"]:
-      try:
-        job = Job(base_args, input = i)
-        jobs[job.id] = job
-      except Exception, e:
-        print e
-
-driver.loop(handle_command, handle_stdin)
+    for id in jobs:
+      send_job(jobs[id])
 
 def handle_stdin(line):
+  global sent_all_jobs, jobs
+  if line is None:
+    sent_all_jobs = True
+    if check_jobs_done():
+      return False
+    return True
   parts = shlex.split(line)
   (err, line_args) = ArgParser.parse_args(parts)
   if err is not None:
     print err
   else:
-    base_args= make_base_job_args(line_args)
+    base_args = make_base_job_args(dict(args.items() + line_args.items()))
     for i in line_args["input"]:
-      pass
-      #send_job(conn, base_cmd, i)
+      try:
+        job = Job(input = i, **base_args)
+        jobs[job.id] = job
+      except Exception, e:
+        print e
+      send_job(job)
+  return True
 
 def handle_command(msg_str):
+  # return False to quit the driver loop
   msg = json.loads(msg_str)
+  print msg
   if "command" in msg:
     cmd = msg["command"]
     if cmd == "exit":
@@ -86,10 +117,14 @@
     if cmd == "print" and "string" in msg:
       sys.stdout.write(msg["string"])
       sys.stdout.flush()
-    if cmd == "done" and "job_num" in msg:
-      job_num = int(cmd["job_num"])
-      if job_num == num_jobs_sent:
-        return False
+    if cmd == "done" and "id" in msg:
+      id = int(msg["id"])
+      if id in jobs:
+        jobs.pop(id)
+        if check_jobs_done():
+          return False
   return True
 
-
+# still have to loop() even if we didn't start succesfully,
+# as we may be waiting for the exporter process to close
+driver.loop(handle_command, handle_stdin)
diff --git a/files.txt b/files.txt
new file mode 100755
index 0000000..0bfe689
--- /dev/null
+++ b/files.txt
@@ -0,0 +1,29 @@
+AnimationPiece.as					// represents single skeletal piece (stores graphic, or frames, + name)
+AnimationPieceSet.as				//
+AnimPieceExportBuilder.as
+AnimSetExportBuilder.as
+CharacterExporter.as
+CharacterSequence.as
+CharacterTypeGraphic.as
+ExportBuilder.as
+JSONPNGSetSaver.as
+Piece.as
+PieceFrameInfo.as
+PieceLibrary.as
+PieceSequence.as
+AnimPiecePacker.as
+AnimSetPacker.as
+IconPacker.as
+ScenePacker.as
+SkelAnimPacker.as
+AsyncGraphicPacker.as
+BitmapFont.as
+BitmapFontCopy.as
+FontCodepointData.as
+GraphicDefClipCollection.as
+GraphicPacker.as
+JSONPNGSetSaver.as
+ChunkedGraphic.as
+FileExportSet.as
+JSONPNGSet.as
+PNGExportHelper.as
diff --git a/job.py b/job.py
index 4385544..d100368 100644
--- a/job.py
+++ b/job.py
@@ -1,16 +1,18 @@
 import os.path
+from args import *
 
 class Job:
   next_id = 0
   def __init__(self, input, type = 1, scale = 1, base = None):
     if not os.path.isfile(input):
       raise Exception("Failed: couldn't open " + input)
-    self.id = next_id
-    next_id += 1
+    self.id = Job.next_id
+    Job.next_id += 1
     self.input = abspath(input)
     self.base = base if base is not None else os.path.split(input)[0]
     if not file_in_path(self.input, self.base):
       raise Exception("Failed: " + input + " is not in base dir " + self.base)
     self.type = type
     self.scale = scale
-    self.done = False
+  def get_cmd(self):
+    return {"type":self.type, "scale":self.scale, "id":self.id}
diff --git a/session.vim b/session.vim
new file mode 100644
index 0000000..88e63d7
--- /dev/null
+++ b/session.vim
@@ -0,0 +1,564 @@
+let SessionLoad = 1
+if &cp | set nocp | endif
+let s:cpo_save=&cpo
+set cpo&vim
+imap  
+inoremap   pumvisible() ? "\" : "\"
+inoremap   pumvisible() ? "\" : "\"
+inoremap   pumvisible() ? "\" : "\"
+nnoremap   :TmuxNavigateLeft
+nnoremap   :TmuxNavigateDown
+nnoremap   :TmuxNavigateUp
+nnoremap   :TmuxNavigateRight
+nnoremap   :TmuxNavigatePrevious
+nnoremap \d :YcmShowDetailedDiagnostic
+map \\ (easymotion-prefix)
+vnoremap  \c :call CopyMarkWithCursor("<", ">")
+nnoremap  \c :set opfunc=OpSysCopyMark
g@
+vmap gx NetrwBrowseXVis
+nmap gx NetrwBrowseX
+vnoremap  NetrwBrowseXVis :call netrw#BrowseXVis()
+nnoremap  NetrwBrowseX :call netrw#BrowseX(expand((exists("g:netrw_gx")? g:netrw_gx : '')),netrw#CheckIfRemote())
+map  (easymotion-prefix)N (easymotion-N)
+map  (easymotion-prefix)n (easymotion-n)
+map  (easymotion-prefix)k (easymotion-k)
+map  (easymotion-prefix)j (easymotion-j)
+map  (easymotion-prefix)gE (easymotion-gE)
+map  (easymotion-prefix)ge (easymotion-ge)
+map  (easymotion-prefix)E (easymotion-E)
+map  (easymotion-prefix)e (easymotion-e)
+map  (easymotion-prefix)B (easymotion-B)
+map  (easymotion-prefix)b (easymotion-b)
+map  (easymotion-prefix)W (easymotion-W)
+map  (easymotion-prefix)w (easymotion-w)
+map  (easymotion-prefix)T (easymotion-T)
+map  (easymotion-prefix)t (easymotion-t)
+map  (easymotion-prefix)s (easymotion-s)
+map  (easymotion-prefix)F (easymotion-F)
+map  (easymotion-prefix)f (easymotion-f)
+xnoremap  (easymotion-activate) :call EasyMotion#activate(1)
+nnoremap  (easymotion-activate) :call EasyMotion#activate(0)
+snoremap  (easymotion-activate) :call EasyMotion#activate(0)
+onoremap  (easymotion-activate) :call EasyMotion#activate(0)
+noremap  (easymotion-dotrepeat) :call EasyMotion#DotRepeat()
+xnoremap  (easymotion-repeat) :call EasyMotion#Repeat(1)
+nnoremap  (easymotion-repeat) :call EasyMotion#Repeat(0)
+snoremap  (easymotion-repeat) :call EasyMotion#Repeat(0)
+onoremap  (easymotion-repeat) :call EasyMotion#Repeat(0)
+xnoremap  (easymotion-prev) :call EasyMotion#NextPrevious(1,1)
+nnoremap  (easymotion-prev) :call EasyMotion#NextPrevious(0,1)
+snoremap  (easymotion-prev) :call EasyMotion#NextPrevious(0,1)
+onoremap  (easymotion-prev) :call EasyMotion#NextPrevious(0,1)
+xnoremap  (easymotion-next) :call EasyMotion#NextPrevious(1,0)
+nnoremap  (easymotion-next) :call EasyMotion#NextPrevious(0,0)
+snoremap  (easymotion-next) :call EasyMotion#NextPrevious(0,0)
+onoremap  (easymotion-next) :call EasyMotion#NextPrevious(0,0)
+xnoremap  (easymotion-wl) :call EasyMotion#WBL(1,0)
+nnoremap  (easymotion-wl) :call EasyMotion#WBL(0,0)
+snoremap  (easymotion-wl) :call EasyMotion#WBL(0,0)
+onoremap  (easymotion-wl) :call EasyMotion#WBL(0,0)
+xnoremap  (easymotion-lineforward) :call EasyMotion#LineAnywhere(1,0)
+nnoremap  (easymotion-lineforward) :call EasyMotion#LineAnywhere(0,0)
+snoremap  (easymotion-lineforward) :call EasyMotion#LineAnywhere(0,0)
+onoremap  (easymotion-lineforward) :call EasyMotion#LineAnywhere(0,0)
+xnoremap  (easymotion-lineanywhere) :call EasyMotion#LineAnywhere(1,2)
+nnoremap  (easymotion-lineanywhere) :call EasyMotion#LineAnywhere(0,2)
+snoremap  (easymotion-lineanywhere) :call EasyMotion#LineAnywhere(0,2)
+onoremap  (easymotion-lineanywhere) :call EasyMotion#LineAnywhere(0,2)
+xnoremap  (easymotion-bd-wl) :call EasyMotion#WBL(1,2)
+nnoremap  (easymotion-bd-wl) :call EasyMotion#WBL(0,2)
+snoremap  (easymotion-bd-wl) :call EasyMotion#WBL(0,2)
+onoremap  (easymotion-bd-wl) :call EasyMotion#WBL(0,2)
+xnoremap  (easymotion-linebackward) :call EasyMotion#LineAnywhere(1,1)
+nnoremap  (easymotion-linebackward) :call EasyMotion#LineAnywhere(0,1)
+snoremap  (easymotion-linebackward) :call EasyMotion#LineAnywhere(0,1)
+onoremap  (easymotion-linebackward) :call EasyMotion#LineAnywhere(0,1)
+xnoremap  (easymotion-bl) :call EasyMotion#WBL(1,1)
+nnoremap  (easymotion-bl) :call EasyMotion#WBL(0,1)
+snoremap  (easymotion-bl) :call EasyMotion#WBL(0,1)
+onoremap  (easymotion-bl) :call EasyMotion#WBL(0,1)
+xnoremap  (easymotion-el) :call EasyMotion#EL(1,0)
+nnoremap  (easymotion-el) :call EasyMotion#EL(0,0)
+snoremap  (easymotion-el) :call EasyMotion#EL(0,0)
+onoremap  (easymotion-el) :call EasyMotion#EL(0,0)
+xnoremap  (easymotion-gel) :call EasyMotion#EL(1,1)
+nnoremap  (easymotion-gel) :call EasyMotion#EL(0,1)
+snoremap  (easymotion-gel) :call EasyMotion#EL(0,1)
+onoremap  (easymotion-gel) :call EasyMotion#EL(0,1)
+xnoremap  (easymotion-bd-el) :call EasyMotion#EL(1,2)
+nnoremap  (easymotion-bd-el) :call EasyMotion#EL(0,2)
+snoremap  (easymotion-bd-el) :call EasyMotion#EL(0,2)
+onoremap  (easymotion-bd-el) :call EasyMotion#EL(0,2)
+xnoremap  (easymotion-jumptoanywhere) :call EasyMotion#JumpToAnywhere(1,2)
+nnoremap  (easymotion-jumptoanywhere) :call EasyMotion#JumpToAnywhere(0,2)
+snoremap  (easymotion-jumptoanywhere) :call EasyMotion#JumpToAnywhere(0,2)
+onoremap  (easymotion-jumptoanywhere) :call EasyMotion#JumpToAnywhere(0,2)
+xnoremap  (easymotion-vim-n) :call EasyMotion#Search(1,0,1)
+nnoremap  (easymotion-vim-n) :call EasyMotion#Search(0,0,1)
+snoremap  (easymotion-vim-n) :call EasyMotion#Search(0,0,1)
+onoremap  (easymotion-vim-n) :call EasyMotion#Search(0,0,1)
+xnoremap  (easymotion-n) :call EasyMotion#Search(1,0,0)
+nnoremap  (easymotion-n) :call EasyMotion#Search(0,0,0)
+snoremap  (easymotion-n) :call EasyMotion#Search(0,0,0)
+onoremap  (easymotion-n) :call EasyMotion#Search(0,0,0)
+xnoremap  (easymotion-bd-n) :call EasyMotion#Search(1,2,0)
+nnoremap  (easymotion-bd-n) :call EasyMotion#Search(0,2,0)
+snoremap  (easymotion-bd-n) :call EasyMotion#Search(0,2,0)
+onoremap  (easymotion-bd-n) :call EasyMotion#Search(0,2,0)
+xnoremap  (easymotion-vim-N) :call EasyMotion#Search(1,1,1)
+nnoremap  (easymotion-vim-N) :call EasyMotion#Search(0,1,1)
+snoremap  (easymotion-vim-N) :call EasyMotion#Search(0,1,1)
+onoremap  (easymotion-vim-N) :call EasyMotion#Search(0,1,1)
+xnoremap  (easymotion-N) :call EasyMotion#Search(1,1,0)
+nnoremap  (easymotion-N) :call EasyMotion#Search(0,1,0)
+snoremap  (easymotion-N) :call EasyMotion#Search(0,1,0)
+onoremap