changeset 0:76568becd6d6

Rhope Alpha 2a source import
author Mike Pavone <pavone@retrodev.com>
date Tue, 28 Apr 2009 23:06:07 +0000
parents
children b3f71490858c
files basicweb.rhope blueprint.c buffer.c calc.rhope copying.txt datum.c datum.h debug.c debugmacros.h dict.c ds_hardware.c ds_main.c extendlib.rhope extendlib.vistxt fib.rhope file.c framework.rhope framework.vistxt hello.rhope interp.c interp.h list.c makefile makefile.linux makefile.osx makefile.win32 makefile.win32wind ms_window.c ms_window.h mt19937ar.c mt19937ar.h net.c number.c pair.rhope parser.c parser.h parser.vistxt readme.txt said.rhope saveload.c saveload.h string.c structs.h syl_generic.cpp syl_generic.h syl_window.cpp syl_window.h vis_threading.c vis_threading.h visuality.c visuality.h visuality_cmd.c webserver.rhope webserver.vistxt window.c window_test.c worker.c
diffstat 57 files changed, 19639 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/basicweb.rhope	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,16 @@
+/*
+	Uses the webserver library to serve static files from the current directory
+*/
+
+//Import the library that does all the hard work
+Import webserver.rhope
+
+Main[]
+{
+	Print["Starting webserver"]
+	//Since we're just serving static files we don't need to setup any handlers
+	handlers <- New@Dictionary[]
+	//Start listening on port 80
+	Listen on Port[80,["Connection Start"]Set Input[1, handlers]]
+	Wait Forever[]
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/blueprint.c	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,119 @@
+#include "datum.h"
+#include "structs.h"
+#include "parser.h"
+#include "interp.h"
+
+int vis_blueprint_new(datum ** params, queue_entry * entry)
+{
+	company * comp = create_company(entry->instance->def->program, params[0]->c.generic.data, 0, 0, TRUE);
+	release_ref(params[0]);
+	params[0] = new_datum(BUILTIN_TYPE_BLUEPRINT, 2, 0, entry->instance->def->program);
+	params[0]->c.generic.data = comp;
+	return 0;
+}
+
+int vis_blueprint_addfield(datum ** params, queue_entry * entry)
+{
+	company * comp = params[0]->c.generic.data;
+	char * type_name = params[2]->c.generic.data;
+	int type;
+	switch(type_name[0])
+	{
+		case 'B':
+			if(strcmp(type_name, "Byte"))
+				type = ROOM_VIS_REF;
+			else
+				type = ROOM_BYTE;
+			break;
+		case 'W':
+			if(strcmp(type_name, "Word"))
+				type = ROOM_VIS_REF;
+			else
+				type = ROOM_SHORT;
+			break;
+		case 'L':
+			if(strcmp(type_name, "Long"))
+				type = ROOM_VIS_REF;
+			else
+				type = ROOM_LONG;
+			break;
+		case 'D':
+			if(strcmp(type_name, "Double"))
+				type = ROOM_VIS_REF;
+			else
+				type = ROOM_DOUBLE;
+			break;
+		case 'S':
+			if(strcmp(type_name, "Single"))
+				type = ROOM_VIS_REF;
+			else
+				type = ROOM_SINGLE;
+			break;
+		default:
+			type = ROOM_VIS_REF;
+			break;
+	}
+	add_comp_room(comp, params[1]->c.generic.data, -1, -1, type, type);
+	release_ref(params[1]);
+	release_ref(params[2]);
+	return 0;
+}
+
+int vis_blueprint_name(datum ** params, queue_entry * entry)
+{
+	company * comp = params[0]->c.generic.data;
+	release_ref(params[0]);
+	params[0] = make_string(comp->name, -1, entry->instance->def->program);
+	return 0;
+}
+
+int vis_blueprint_getfields(datum ** params, queue_entry * entry)
+{
+	int i;
+	company * comp = params[0]->c.generic.data;
+	release_ref(params[0]);
+	params[0] = create_list(entry->instance->def->program);
+	for(i = 0; i < comp->num_rooms; ++i)
+	{
+		params[1] = make_string(comp->room_list[i].name, -1, entry->instance->def->program);
+		vis_list_append(params,entry);
+	}
+	return 0;
+}
+
+int vis_get_blueprint(datum ** params, queue_entry * entry)
+{
+	company * comp = params[0]->company;
+	release_ref(params[0]);
+	params[0] = new_datum(BUILTIN_TYPE_BLUEPRINT, 2, 0, entry->instance->def->program);
+	params[0]->c.generic.data = comp;
+	return 0;
+}
+
+int vis_get_field(datum ** params, queue_entry * entry)
+{
+	datum * name = params[1];
+	int returnval = get_comp_room_by_name(params, name->c.generic.data, NULL, entry, entry->instance->def->program);
+	release_ref(name);
+	return returnval;
+}
+
+int vis_set_field(datum ** params, queue_entry * entry)
+{
+	datum * name = params[1];
+	int returnval;
+	params[1] = params[2];
+	returnval = set_comp_room_by_name(params, name->c.generic.data, NULL, entry, entry->instance->def->program);
+	release_ref(name);
+	return returnval;
+}
+
+int vis_program_newblueprint(datum ** params, queue_entry * entry)
+{
+	program * prog = params[0]->c.generic.data;
+	company * comp = create_company(prog, params[1]->c.generic.data, 0, 0, TRUE);
+	release_ref(params[1]);
+	params[1] = new_datum(BUILTIN_TYPE_BLUEPRINT, 2, 0, entry->instance->def->program);
+	params[1]->c.generic.data = comp;
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/buffer.c	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,190 @@
+#include "datum.h"
+#include "vis_threading.h"
+#include "structs.h"
+#include <string.h>
+
+//TODO: Make some kind of "notifier" lock that takes some kind of callback
+//to be called when the lock becomes free
+
+typedef struct
+{
+	int offset;
+	char * buffer;
+	int size;
+	VIS_CRITICAL_SECTION(lock)
+} fixed_buffer;
+	
+int vis_buffer_new(datum ** params, queue_entry * entry)
+{
+	int size = params[0]->c.integers.num_a;
+	fixed_buffer * buf;
+	release_ref(params[0]);
+	params[0] = new_datum(BUILTIN_TYPE_BUFFER, 1, sizeof(fixed_buffer) + size, entry->instance->def->program);
+	buf = params[0]->c.generic.data;
+	buf->offset = 0;
+	buf->buffer = ((char *)buf) + sizeof(fixed_buffer);
+	buf->size = size;
+	VIS_InitializeCriticalSection(buf->lock);
+	return 0;
+}
+
+int vis_buffer_lock(datum ** params, queue_entry * entry)
+{
+	fixed_buffer * buf = params[0]->c.generic.data;
+	VIS_EnterCriticalSection(buf->lock);
+	return 0;
+}
+
+int vis_buffer_unlock(datum ** params, queue_entry * entry)
+{
+	fixed_buffer * buf = params[0]->c.generic.data;
+	VIS_LeaveCriticalSection(buf->lock);
+	return 0;
+}
+
+int vis_buffer_putbyte(datum ** params, queue_entry * entry)
+{
+	fixed_buffer * buf = params[0]->c.generic.data;
+	char byte = params[1]->c.integers.num_a;
+	release_ref(params[1]);
+	if(buf->offset < buf->size)
+	{
+		buf->buffer[buf->offset++] = byte;
+		params[1] = NULL;
+	}
+	else
+	{
+		params[1] = params[0];
+		params[1] = NULL;
+	}
+	return 0;
+}
+
+int vis_buffer_writebyte(datum ** params, queue_entry * entry)
+{
+	fixed_buffer * buf = params[0]->c.generic.data;
+	char byte = params[1]->c.integers.num_a;
+	release_ref(params[1]);
+	if(buf->offset < buf->size)
+	{
+		buf->buffer[buf->offset] = byte;
+		params[1] = NULL;
+	}
+	else
+	{
+		params[1] = params[0];
+		params[1] = NULL;
+	}
+	return 0;
+}
+
+int vis_buffer_putshort(datum ** params, queue_entry * entry)
+{
+	fixed_buffer * buf = params[0]->c.generic.data;
+	short * wordbuf;
+	short word = params[1]->c.integers.num_a;
+	release_ref(params[1]);
+	if(buf->offset < buf->size)
+	{
+		wordbuf = (short *)buf->buffer;
+		wordbuf[buf->offset >> 1] = word;
+		params[1] = NULL;
+		buf->offset += 2;
+	}
+	else
+	{
+		params[1] = params[0];
+		params[1] = NULL;
+	}
+	return 0;
+}
+
+int vis_buffer_writeshort(datum ** params, queue_entry * entry)
+{
+	fixed_buffer * buf = params[0]->c.generic.data;
+	short * wordbuf;
+	short word = params[1]->c.integers.num_a;
+	release_ref(params[1]);
+	if(buf->offset < buf->size)
+	{
+		wordbuf = (short *)buf->buffer;
+		wordbuf[buf->offset >> 1] = word;
+		params[1] = NULL;
+	}
+	else
+	{
+		params[1] = params[0];
+		params[1] = NULL;
+	}
+	return 0;
+}
+
+int vis_buffer_putlong(datum ** params, queue_entry * entry)
+{
+	fixed_buffer * buf = params[0]->c.generic.data;
+	long * longbuf;
+	long lword = params[1]->c.integers.num_a;
+	release_ref(params[1]);
+	if(buf->offset < buf->size)
+	{
+		longbuf = (long *)buf->buffer;
+		longbuf[buf->offset >> 2] = lword;
+		params[1] = NULL;
+		buf->offset += 4;
+	}
+	else
+	{
+		params[1] = params[0];
+		params[1] = NULL;
+	}
+	return 0;
+}
+
+int vis_buffer_writelong(datum ** params, queue_entry * entry)
+{
+	fixed_buffer * buf = params[0]->c.generic.data;
+	long * longbuf;
+	long lword = params[1]->c.integers.num_a;
+	release_ref(params[1]);
+	if(buf->offset < buf->size)
+	{
+		longbuf = (long *)buf->buffer;
+		longbuf[buf->offset >> 2] = lword;
+		params[1] = NULL;
+	}
+	else
+	{
+		params[1] = params[0];
+		params[1] = NULL;
+	}
+	return 0;
+}
+
+int vis_buffer_reset(datum ** params, queue_entry * entry)
+{
+	fixed_buffer * buf = params[0]->c.generic.data;
+	buf->offset = 0;
+	return 0;
+}
+
+#if defined(SEGA) | defined(NINTENDO_DS)
+int vis_buffer_fromaddress(datum ** params, queue_entry * entry)
+{
+	char buffer;
+	datum * out;
+	int size = params[1]->c.integers.num_a;
+	fixed_buffer * buf;
+	release_ref(params[1]);
+	out = new_datum(BUILTIN_TYPE_BUFFER, 1, sizeof(fixed_buffer), entry->instance->def->program);
+	buf = out->c.generic.data;
+	buf->offset = 0;
+	buf->buffer = (char *)(params[0]->c.integers.num_a);
+	buf->size = size;
+	VIS_InitializeCriticalSection(buf->lock);
+	release_ref(params[0]);
+	params[0] = out;
+	return 0;
+}
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/calc.rhope	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,37 @@
+/*
+	This program implements a simple GUI calculator
+	Currently only the Windows and Syllable ports of Rhope have GUI support
+*/
+
+
+Add[window]
+{
+	[window]Get Value["right"]
+	{
+		<String@Real Number[~]
+		{
+			[window]Set Value["left", [~] + [[window]Get Value["left"]]]
+			[window]Set Value["right", "0"]
+		}
+	}
+}
+
+Sub[window]
+{
+	[window]Get Value["right"]
+	{
+		[window]Set Value["left", [<String@Real Number[ [window]Get Value["left"] ]] - [~]]
+		[window]Set Value["right", "0"]
+	}
+}
+
+Main[]
+{
+	[[[[[[New@Window["Visuality Calculator", 400.0, 400.0]
+	]Add Widget["+", [New@Button["+", 20.0, 20.0]]Set Handler["click","Add"], 20.0, 60.0]
+	]Add Widget["-", [New@Button["-", 20.0, 20.0]]Set Handler["click","Sub"], 60.0, 60.0]
+	]Add Widget["left", [New@Input Box["0", 170.0, 20.0]]Set Type["numeric"], 20.0, 20.0]
+	]Add Widget["right", [New@Input Box["0", 170.0, 20.0]]Set Type["numeric"], 210.0, 20.0]
+	]Show[20.0,20.0]
+	]Wait Close
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/copying.txt	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,10 @@
+Copyright (c) 2008, Michael Pavone
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+ - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 
+ - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 
+ - Neither the name of the Rhope Project nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/datum.c	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,448 @@
+#include "structs.h"
+#include "datum.h"
+#include "interp.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef WIN32
+	#include <winsock.h>
+#else
+	#include <sys/types.h>
+	#include <sys/socket.h>
+	#include <netinet/in.h>
+	#include <netdb.h>
+	#include <arpa/inet.h>
+#endif
+
+#ifdef TEXT_FILE_DEBUG
+extern FILE * debugfile;
+#endif
+
+extern char * debugbuffer;
+
+datum_storage first_datum_storage;
+datum_storage * first_free;
+
+VIS_CRITICAL_SECTION(datum_alloc_lock)
+
+void init_datum_storage()
+{
+	short i;
+	first_datum_storage.available = DATUMS_PER_STORAGE;
+	for(i = 0; i < DATUMS_PER_STORAGE/8; ++i)
+		first_datum_storage.inuse[i] = 0;
+	first_datum_storage.next = NULL;
+	//first_datum_storage.num = 0;
+	//first_free = &first_datum_storage;
+	VIS_InitializeCriticalSection(datum_alloc_lock);
+}
+
+datum * datum_alloc()
+{
+	short i, j;
+	datum_storage *last, *current = /*first_free;*/&first_datum_storage;
+	VIS_PROFILE_START(PROF_DATUM_ALLOC);
+	//DEBUGPUTS("Begin datum_alloc()\n");
+	VIS_EnterCriticalSection(datum_alloc_lock);
+		while(current && !(current->available))
+		{
+			last = current;
+			current = current->next;
+		}
+		if(current)
+		{
+			for(i = 0; i < (DATUMS_PER_STORAGE >> 3); ++i)
+				if(current->inuse[i] != 0xFF)
+					break;
+			for(j = 0; j < 8; ++j)
+				if(!CHECK_INUSE(current, i, j))
+					break;
+			//DEBUGPRINTF("inuse[%d] = %X\n", i, current->inuse[i]);
+			i = (i << 3) | j;
+			//DEBUGPRINTF("Allocated datum %X:%d\n", current, i);
+			SET_INUSE(current, i);
+			--(current->available);
+	VIS_LeaveCriticalSection(datum_alloc_lock);
+			//DEBUGPUTS("End datum_alloc()\n");
+			//DEBUGPRINTF("datum_alloc(%X)\n", current->datums + i);
+			VIS_PROFILE_END(PROF_DATUM_ALLOC);
+			return current->datums + i;
+		}
+		else
+		{
+			current = MALLOC(sizeof(datum_storage),"datum storage");
+			//first_free = current;
+			//DEBUGPRINTF("New datum_storage %X\n", current);
+			last->next = current;
+			current->available = DATUMS_PER_STORAGE - 1;
+			current->inuse[0] = 1;
+			//current->num = last->num+1;
+			for(i = 1; i < DATUMS_PER_STORAGE>>3; ++i)
+				current->inuse[i] = 0;
+			current->next = NULL;
+	VIS_LeaveCriticalSection(datum_alloc_lock);
+			//DEBUGPUTS("End datum_alloc()\n");
+			//DEBUGPRINTF("datum_alloc(%X)\n", current->datums);
+			VIS_PROFILE_END(PROF_DATUM_ALLOC);
+			return current->datums;
+		}
+	
+}
+
+void free_datum(datum * adatum)
+{
+	datum_storage *last=NULL, *current = &first_datum_storage;
+//	DEBUGPUTS("Begin free_datum()\n");
+	VIS_EnterCriticalSection(datum_alloc_lock);
+	while(current && !(adatum >= (datum *)current && adatum <= (((datum *)current) + DATUMS_PER_STORAGE)))
+	{
+		last = current;
+		current = current->next;
+	}
+	if(current)
+	{
+		//DEBUGPRINTF("Freed datum %X:%d\n", current, adatum-((datum *)current));
+		//DEBUGPRINTF("inuse[%d] = %X\n", (adatum-(current->datums))>>3, current->inuse[adatum-(current->datums)>>3]);
+		//DEBUGPRINTF("&= %X\n", ~(1 << ((adatum-(current->datums)) & 3)));
+		CLEAR_INUSE(current, adatum-(current->datums));
+		//DEBUGPRINTF("inuse[%d] = %X\n", (adatum-(current->datums))>>3, current->inuse[adatum-(current->datums)>>3]);
+		++(current->available);
+		if(current->available == DATUMS_PER_STORAGE && last && last->available)
+		{
+			last->next = NULL;
+			/*last->next = current->next;
+			if(last->num < first_free->num || first_free == current)
+				first_free = last;*/
+			//DEBUGPRINTF("Freeing datum_storage %X\n", current);
+			VIS_FREE(current, "free datum block");
+		}
+		/*else
+		{
+			if(current->num < first_free->num)
+				first_free = current;
+		}*/
+	}
+	VIS_LeaveCriticalSection(datum_alloc_lock);
+	//DEBUGPUTS("End free_datum()\n");
+}
+
+
+
+datum * new_datum_comp(company * comp, unsigned char union_type, int generic_len)
+{
+	datum * adatum;
+	VIS_PROFILE_START(PROF_NEW_DATUM);
+	//adatum = datum_alloc();
+	adatum = MALLOC(sizeof(datum),"datum");
+	DEBUGPRINTF("Allocated: %X\n", adatum);
+	//DEBUGPRINTF("datum_alloc returned %X.\n", adatum);
+	adatum->company = comp;
+	adatum->union_type = union_type;
+	/*if(type > 0)
+		adatum->methods = get_method_list(type);*/
+	if(union_type == 1)//generic data
+	{
+		//DEBUGPUTS("union_type == 1\n");
+		adatum->c.generic.len = generic_len;
+		if(generic_len > 0)
+		{
+			//DEBUGPRINTF("malloc(%d);\n", generic_len);
+			adatum->c.generic.data = MALLOC(generic_len,"datum generic data");
+			//DEBUGPUTS("after malloc");
+		}
+		else
+			adatum->c.generic.data = NULL;
+	}
+	adatum->ref_count = 1;
+//	DEBUGPUTS("Initializing lock.\n");
+	VIS_InitializeCriticalSection(adatum->lock);
+	//DEBUGPRINTF( "New datum at: %X\n", adatum);
+	VIS_PROFILE_END(PROF_NEW_DATUM);
+	return adatum;
+}
+
+datum * new_datum(unsigned short type, unsigned char union_type, int generic_len, program * prog)
+{
+	return new_datum_comp(prog->companylist + type, union_type, generic_len);
+}
+
+datum * copy_datum(datum * adatum, int newsize)
+{
+	//NOTE: This function makes some assumptions that might not be safe everywhere in the interpretter, needs more thought
+	int ref_count, real_len, new_entry_count;
+	dict_data * dict;
+	datum * output;
+	worker_datum * work;
+	int i;
+	VIS_EnterCriticalSection(adatum->lock);
+		ref_count = adatum->ref_count;
+	VIS_LeaveCriticalSection(adatum->lock);
+	if(adatum->union_type == 1)
+		if(adatum->company->type_id == BUILTIN_TYPE_LIST)
+			real_len = (adatum->c.generic.len-1) * sizeof(datum *) + sizeof(list_data);
+		else
+		{
+			real_len = adatum->c.generic.len;
+		}
+	else
+		real_len = 0;
+	if(ref_count > 1 || newsize > real_len)
+	{
+		if(adatum->company->type_id == BUILTIN_TYPE_FILE)
+		{
+			VIS_EnterCriticalSection(((file_data *)adatum->c.generic.data)->shared->lock);
+				((file_data *)adatum->c.generic.data)->shared->ref_count++;
+			VIS_LeaveCriticalSection(((file_data *)adatum->c.generic.data)->shared->lock);
+		}
+		if(newsize)
+			output = new_datum_comp(adatum->company, adatum->union_type, newsize);
+		else
+			output = new_datum_comp(adatum->company, adatum->union_type, real_len);
+		switch(adatum->union_type)
+		{
+		case 1:
+			if(adatum->company->type_id == BUILTIN_TYPE_LIST)
+			{
+				((list_data *)output->c.generic.data)->num_entries = ((list_data *)adatum->c.generic.data)->num_entries;
+				for(i = 0; i < ((list_data *)adatum->c.generic.data)->num_entries; ++i)
+					((list_data *)output->c.generic.data)->entries[i] = add_ref(((list_data *)adatum->c.generic.data)->entries[i]);
+			}
+		#ifdef GUI_LIB
+			else if(adatum->company->type_id == BUILTIN_TYPE_WINDOW)
+			{
+				((vis_window *)output->c.generic.data)->title = add_ref(((vis_window *)adatum->c.generic.data)->title);
+				((vis_window *)output->c.generic.data)->widget_dict = add_ref(((vis_window *)adatum->c.generic.data)->widget_dict);
+				((vis_window *)output->c.generic.data)->widget_xpos = add_ref(((vis_window *)adatum->c.generic.data)->widget_xpos);
+				((vis_window *)output->c.generic.data)->widget_ypos = add_ref(((vis_window *)adatum->c.generic.data)->widget_ypos);
+				((vis_window *)output->c.generic.data)->id_list = add_ref(((vis_window *)adatum->c.generic.data)->id_list);
+				((vis_window *)output->c.generic.data)->width = ((vis_window *)adatum->c.generic.data)->width;
+				((vis_window *)output->c.generic.data)->height = ((vis_window *)adatum->c.generic.data)->height;
+			}
+		#ifdef SYLLABLE
+			else if(adatum->company->type_id == BUILTIN_TYPE_BUTTON || adatum->company->type_id == BUILTIN_TYPE_INPUTBOX || adatum->company->type_id == BUILTIN_TYPE_CHECKBOX || adatum->company->type_id == BUILTIN_TYPE_DROPDOWN)
+		#else
+			else if(adatum->company->type_id == BUILTIN_TYPE_BUTTON || adatum->company->type_id == BUILTIN_TYPE_INPUTBOX)
+		#endif
+			{
+				((vis_widget *)output->c.generic.data)->label = add_ref(((vis_widget *)adatum->c.generic.data)->label);
+				((vis_widget *)output->c.generic.data)->value = add_ref(((vis_widget *)adatum->c.generic.data)->value);
+				((vis_widget *)output->c.generic.data)->handler_dict = add_ref(((vis_widget *)adatum->c.generic.data)->handler_dict);
+				((vis_widget *)output->c.generic.data)->width = ((vis_widget *)adatum->c.generic.data)->width;
+				((vis_widget *)output->c.generic.data)->height = ((vis_widget *)adatum->c.generic.data)->height;
+				((vis_widget *)output->c.generic.data)->flags = ((vis_widget *)adatum->c.generic.data)->flags;
+			}
+		#endif
+			else if(real_len >= newsize && newsize)
+				memcpy(output->c.generic.data, adatum->c.generic.data, newsize);
+			else
+				memcpy(output->c.generic.data, adatum->c.generic.data, real_len);
+				
+			if(adatum->company->build_size > 0)
+			{
+				for(i = 0; i < adatum->company->num_rooms; ++i)
+						if(adatum->company->room_list[i].get_func_type == ROOM_VIS_REF)
+						{
+							//DEBUGPRINTF("Member add ref (get_func): %X, generic.data: %X\n", (datum*)(((char *)adatum->c.generic.data) + (int)adatum->company->room_list[i].get_func), adatum->c.generic.data);
+							add_ref(*((datum**)(((char *)adatum->c.generic.data) + (int)adatum->company->room_list[i].get_func)));
+						}
+						else if(adatum->company->room_list[i].set_func_type == ROOM_VIS_REF)
+						{
+							//DEBUGPRINTF("Member add ref (set_func): %X, generic.data: %X\n", (datum*)(((char *)adatum->c.generic.data) + (int)adatum->company->room_list[i].set_func), adatum->c.generic.data);
+							add_ref(*((datum**)(((char *)adatum->c.generic.data) + (int)adatum->company->room_list[i].set_func)));
+						}
+			}
+			else if(adatum->company->type_id == BUILTIN_TYPE_DICT)
+			{
+				dict = output->c.generic.data;
+				for(i = 0; i < dict->num_nodes; ++i)
+						add_ref(dict->nodes[i].payload);
+			}
+			else if(adatum->company->type_id == BUILTIN_TYPE_WORKER)
+			{
+				work = output->c.generic.data;
+				add_program_ref(work->def->program);
+				for(i = 0; i < work->def->num_inputs; ++i)
+					add_ref(work->params[i]);
+			}
+			
+			if(adatum->c.generic.len != real_len)
+				output->c.generic.len = adatum->c.generic.len;
+			break;
+		case 2:
+			output->c.integers.num_a = adatum->c.integers.num_a;
+			output->c.integers.num_b = adatum->c.integers.num_b;
+			break;
+		case 3:
+			output->c.real = adatum->c.real;
+			break;
+		default:
+			//oops;
+			break;
+		}
+		release_ref(adatum);
+	}
+	else if(newsize && real_len == adatum->c.generic.len)
+	{
+		adatum->c.generic.len = newsize;
+		output = adatum;
+	}
+	else
+		output = adatum;
+	return output;
+}
+
+datum * add_ref(datum * adatum)
+{
+	int tmp;
+	VIS_PROFILE_START(PROF_ADDREF);
+	if(!adatum)
+	{
+		//DEBUGPUTS("add_ref on NULL datum\n");
+		return NULL;
+	}
+	DEBUGPRINTF("add_ref: %X\n",adatum);
+	/*tmp = (int)(&(adatum->ref_count));
+	__asm
+	{
+		mov ebx, tmp
+		lock inc dword ptr [ebx]
+	}*/
+	
+	VIS_EnterCriticalSection(adatum->lock);
+		++(adatum->ref_count);
+	VIS_LeaveCriticalSection(adatum->lock);
+	VIS_PROFILE_END(PROF_ADDREF);
+	return adatum;
+}
+
+void release_ref(datum * adatum)
+{
+	int i,tmp;
+	dict_data * dict;
+	worker_datum * worker;
+	VIS_PROFILE_START(PROF_RELEASE);
+	DEBUGPRINTF( "relase_ref: %X\n",adatum);
+	if(!adatum)
+		return;
+	
+	/*tmp = (int)(&(adatum->ref_count));
+	__asm
+	{
+		mov ebx, tmp
+		lock dec dword ptr [ebx]
+	}*/
+	//DEBUGPUTS("entering lock");
+	VIS_EnterCriticalSection(adatum->lock);
+		//DEBUGPUTS("got critical section\n");
+		--(adatum->ref_count);
+		if(adatum->ref_count == 0)
+		{
+			//DEBUGPRINTF("datum_free(%X)\n", adatum);
+			
+	VIS_LeaveCriticalSection(adatum->lock);
+			//DEBUGPUTS("left lock");
+			VIS_DeleteCriticalSection(adatum->lock);
+			if(adatum->union_type == 1)
+			{
+				//DEBUGPRINTF( "Freeing adatum->c.generic.data(%X)\n",(int)adatum->c.generic.data);
+				if(adatum->company->build_size > 0)
+				{
+					for(i = 0; i < adatum->company->num_rooms; ++i)
+						if(adatum->company->room_list[i].get_func_type == ROOM_VIS_REF)
+						{
+							//DEBUGPRINTF("Member release ref (get_func): %X, generic.data: %X\n", (datum*)(((char *)adatum->c.generic.data) + (int)adatum->company->room_list[i].get_func), adatum->c.generic.data);
+							release_ref(*((datum**)(((char *)adatum->c.generic.data) + (int)adatum->company->room_list[i].get_func)));
+						}
+						else if(adatum->company->room_list[i].set_func_type == ROOM_VIS_REF)
+						{
+							//DEBUGPRINTF("Member release ref (set_func): %X, generic.data: %X\n", (datum*)(((char *)adatum->c.generic.data) + (int)adatum->company->room_list[i].set_func), adatum->c.generic.data);
+							release_ref(*((datum**)(((char *)adatum->c.generic.data) + (int)adatum->company->room_list[i].set_func)));
+						}
+				}
+				else if(adatum->company->type_id == BUILTIN_TYPE_LIST)
+					for(i = 0; i < ((list_data *)adatum->c.generic.data)->num_entries; ++i)
+						release_ref(((list_data *)adatum->c.generic.data)->entries[i]);
+				else if(adatum->company->type_id == BUILTIN_TYPE_FILE)
+				{
+					VIS_EnterCriticalSection(((file_data *)adatum->c.generic.data)->shared->lock);
+						--(((file_data *)adatum->c.generic.data)->shared->ref_count);
+						if(((file_data *)adatum->c.generic.data)->shared->ref_count == 0)
+						{
+					VIS_LeaveCriticalSection(((file_data *)adatum->c.generic.data)->shared->lock);
+							VIS_DeleteCriticalSection(((file_data *)adatum->c.generic.data)->shared->lock);
+#ifndef SEGA
+							if(((file_data *)adatum->c.generic.data)->shared->status == FILE_READ || ((file_data *)adatum->c.generic.data)->shared->status == FILE_WRITE)
+								fclose(((file_data *)adatum->c.generic.data)->shared->file);
+#endif
+							VIS_FREE(((file_data *)adatum->c.generic.data)->shared, "Shared file struct");
+						}
+						else
+						{
+					VIS_LeaveCriticalSection(((file_data *)adatum->c.generic.data)->shared->lock);
+						}
+				}
+				else if(adatum->company->type_id == BUILTIN_TYPE_DICT)
+				{
+					dict = adatum->c.generic.data;
+					for(i = 0; i < dict->num_nodes; ++i)
+						release_ref(dict->nodes[i].payload);
+				}
+				else if(adatum->company->type_id == BUILTIN_TYPE_WORKER)
+				{
+					worker = adatum->c.generic.data;
+					for(i = 0; i < worker->def->num_inputs; ++i)
+						if(worker->params[i])
+						{
+							DEBUGPRINTF("Releasing worker param %d\n", i);
+							release_ref(worker->params[i]);
+						}
+					release_program_ref(worker->def->program);
+				}
+				#ifdef SYLLABLE
+				else if(adatum->company->type_id == BUILTIN_TYPE_WINDOW)
+				{
+					release_ref(((vis_window *)adatum->c.generic.data)->title);
+					release_ref(((vis_window *)adatum->c.generic.data)->widget_dict);
+					release_ref(((vis_window *)adatum->c.generic.data)->widget_xpos);
+					release_ref(((vis_window *)adatum->c.generic.data)->widget_ypos);
+					release_ref(((vis_window *)adatum->c.generic.data)->id_list);
+				}
+				else if(adatum->company->type_id == BUILTIN_TYPE_BUTTON)
+				{
+					release_ref(((vis_widget *)adatum->c.generic.data)->label);
+					release_ref(((vis_widget *)adatum->c.generic.data)->handler_dict);
+				}
+				#endif
+				VIS_FREE(adatum->c.generic.data, "datum->c.generic.data");
+			} else if(adatum->company->type_id == BUILTIN_TYPE_NETCLIENT)
+			#ifdef WIN32
+				closesocket(adatum->c.integers.num_a);
+			#else
+				close(adatum->c.integers.num_a);
+			#endif
+			else if(adatum->company->type_id == BUILTIN_TYPE_PROGRAM)
+				release_program_ref(adatum->c.generic.data);
+			DEBUGPRINTF("Freeing: %X\n",adatum);
+			//free_datum(adatum);
+			free(adatum);
+		}
+		else
+		{
+	VIS_LeaveCriticalSection(adatum->lock);
+	//DEBUGPUTS("left lock");
+		}
+	VIS_PROFILE_END(PROF_RELEASE);
+	//DEBUGPUTS("exit release_ref\n");
+	
+}
+
+void datum_set_yesno(datum * adatum, int val)
+{
+	adatum->c.integers.num_a = val;
+}
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/datum.h	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,161 @@
+#ifndef _DATUM_H_
+#define _DATUM_H_
+
+#include "vis_threading.h"
+#include "debugmacros.h"
+
+/*
+Old Datum structure
+typedef struct
+{
+	unsigned char type;//0=String,1=Bool,2=Int32,3=UInt32,4=Float, bit 7 = dynamically allocated (i.e. call free when datum is freed)
+	int len;
+	void * contents;
+} datum;
+*/
+
+//Support structs for new datum structure
+#ifdef CPLUSPLUS
+extern "C" {
+#endif
+#ifndef PROGRAM_STRUCT_DECLARED_
+#define PROGRAM_STRUCT_DECLARED_
+//icky hack until I figure out a better one
+//defined in both datum.h and structs.h ugh
+
+typedef struct
+{
+	char filename[512];
+	struct defchunk * defs;
+	struct defchunk * current;
+	//struct worker_def * deflist;
+	//int num_defs;
+	//int defs_storage;
+	struct company * companylist;
+	int num_companies;
+	int companies_storage;
+	int refcount;
+	VIS_CRITICAL_SECTION(lock)
+} program;
+
+#endif
+
+typedef struct
+{
+	unsigned int len;
+	void * data;
+} generic_data;
+typedef struct
+{
+	int num_a;
+	int num_b;
+} two_ints;
+//New datum structure
+typedef struct
+{
+	//unsigned short type;
+	struct company * company;
+	unsigned char union_type;
+	union
+	{
+		generic_data generic;
+		two_ints integers;
+		double real;
+	} c;
+	int ref_count;
+	VIS_CRITICAL_SECTION(lock)
+} datum;
+
+#define DATUMS_PER_STORAGE	512
+typedef struct datum_storage
+{
+	datum datums[DATUMS_PER_STORAGE];
+	unsigned short available;
+	unsigned char inuse[DATUMS_PER_STORAGE/8];
+	int num;
+	struct datum_storage * next;
+} datum_storage;
+#define CHECK_INUSE(storage, index, subindex)	((storage->inuse[index]) & (1 << (subindex)))
+#define	SET_INUSE(storage, index)	(storage->inuse[index >> 3] |= (1 << (index & 7)))
+#define	CLEAR_INUSE(storage, index)	(storage->inuse[index >> 3] &= ~(1 << (index & 7)))
+
+datum * new_datum(unsigned short type, unsigned char union_type, int generic_len, program * prog);
+datum * add_ref(datum * adatum);
+void release_ref(datum * adatum);
+void datum_set_yesno(datum * adatum, int val);
+void init_datum_storage();
+datum * copy_datum(datum * adatum, int newsize);
+#ifdef CPLUSPLUS
+}
+#endif
+
+#define DATUM_YES	1
+#define DATUM_NO	0
+
+#define BUILTIN_TYPE_SCREEN_CUSTOM		17
+#define BUILTIN_TYPE_CUSTOM_WIDGET		16
+#define BUILTIN_TYPE_CHECKBOX			20
+#define BUILTIN_TYPE_DROPDOWN			21
+#ifdef GUI_LIB
+	#ifdef SYLLABLE
+		#define USER_DEFINED_TYPES			22
+		#define BUILTIN_TYPE_BLUEPRINT		19
+		#define BUILTIN_TYPE_BUFFER			18
+	#else
+		#define USER_DEFINED_TYPES			18
+		#define BUILTIN_TYPE_BLUEPRINT		17
+		#define BUILTIN_TYPE_BUFFER			16
+	#endif
+	#define BUILTIN_TYPE_PROGRAM		15
+	#define BUILTIN_TYPE_GLOBAL_STORE	14
+	#define BUILTIN_TYPE_NETCLIENT		13
+#else
+	#ifdef SEGA
+		#define	USER_DEFINED_TYPES			12
+		#define BUILTIN_TYPE_BLUEPRINT		11
+		#define BUILTIN_TYPE_BUFFER			10
+		#define BUILTIN_TYPE_PROGRAM		9
+		#define BUILTIN_TYPE_GLOBAL_STORE	8
+	#else
+		#ifdef NO_NET
+			#define	USER_DEFINED_TYPES			13
+			#define BUILTIN_TYPE_BLUEPRINT		12
+			#define BUILTIN_TYPE_BUFFER			11
+			#define BUILTIN_TYPE_PROGRAM		10
+			#define BUILTIN_TYPE_GLOBAL_STORE	9
+		#else
+			#define	USER_DEFINED_TYPES			14
+			#define BUILTIN_TYPE_BLUEPRINT		13
+			#define BUILTIN_TYPE_BUFFER			12
+			#define BUILTIN_TYPE_PROGRAM		11
+			#define BUILTIN_TYPE_GLOBAL_STORE	10
+		#endif
+	#endif
+	#define	BUILTIN_TYPE_NETCLIENT		9
+#endif
+#define BUILTIN_TYPE_INPUTBOX			12
+#define BUILTIN_TYPE_BUTTON				11
+#define BUILTIN_TYPE_WINDOW_SHOWN		10
+#define BUILTIN_TYPE_WINDOW 			9
+#ifdef SEGA
+	#define BUILTIN_TYPE_WORKER			7
+#else
+	#define BUILTIN_TYPE_WORKER				8
+#endif //SEGA
+#define BUILTIN_TYPE_FILE				7
+#define BUILTIN_TYPE_DICT				6
+#define BUILTIN_TYPE_LIST				5
+#define BUILTIN_TYPE_REAL				4
+#define BUILTIN_TYPE_WHOLE				3
+#define BUILTIN_TYPE_STRING				2
+#define BUILTIN_TYPE_YESNO				1
+#define ANY_TYPE						0
+
+#endif //_DATUM_H_
+
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/debug.c	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,9 @@
+#include <stdlib.h>
+#include "debugmacros.h"
+
+void * debug_malloc(size_t size, char * msg)
+{
+	void * ptr = malloc(size);
+	DEBUGPRINTF("malloc: %X (%X bytes), %s\n", ptr, size, msg);
+	return ptr;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/debugmacros.h	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,72 @@
+#ifndef	_DEBUGMACROS_H_
+#define	_DEBUGMACROS_H_
+
+//#define TEXT_FILE_DEBUG	1
+
+#ifdef TEXT_FILE_DEBUG
+#include <stdio.h>
+
+void * debug_malloc(size_t size, char * msg);
+
+#define DEBUGPRINTF(format, ...)	fprintf(debugfile, format, __VA_ARGS__); fflush(debugfile)
+#define DEBUGPUTS(string)			fputs(string, debugfile); fflush(debugfile)
+
+extern FILE * debugfile;
+
+#ifdef MALLOC_DEBUG
+#define MALLOC(size, msg)			debug_malloc(size, msg)
+#define VIS_FREE(ptr, msg)				fprintf(debugfile, "free: %X, %s\n", ptr, msg); fflush(debugfile); free(ptr)
+#else
+#define MALLOC(size, msg)			malloc(size)
+#define VIS_FREE(ptr, msg)			free(ptr)
+#endif
+
+#else
+#ifdef	BOX_DEBUG
+
+#define DEBUGPRINTF(format, ...)	sprintf(debugbuffer, format, __VA_ARGS__); MessageBox(NULL, debugbuffer, "Debug", MB_OK)
+#define DEBUGPUTS(string)			MessageBox(NULL, string, "Debug", MB_OK)
+
+#else
+#ifdef CONSOLE_DEBUG
+#include <stdio.h>
+
+#define	DEBUGPRINTF(format, ...)	printf(format, __VA_ARGS__); fflush(stdout);
+#define	DEBUGPUTS(string)			fputs(string, stdout); fflush(stdout);
+
+#else
+
+#define	DEBUGPRINTF
+#define	DEBUGPUTS
+
+#define MALLOC(size, msg)			malloc(size)
+#define VIS_FREE(ptr, msg)				free(ptr)
+
+#endif	//CONSOLE_DEBUG
+#endif	//BOX_DEBUG
+#endif	//TEXT_FILE_DEBUG
+
+
+
+#ifdef WIN32
+	#ifdef GUI_LIB
+		extern char errorbuffer[1024];
+		#define ERRORPUTS(string)			DEBUGPUTS(string); MessageBox(NULL, string, "Rhope Error", MB_OK);
+		#define ERRORPRINTF(format, ...)	DEBUGPRINTF(format, __VA_ARGS__); sprintf(errorbuffer, format, __VA_ARGS__); MessageBox(NULL, errorbuffer, "Rhope Error", MB_OK);
+	#else
+		#define ERRORPUTS(string)	DEBUGPUTS(string); puts(string)/*fputs(string, stderr);*/
+		#define ERRORPRINTF(format, ...)	DEBUGPRINTF(format, __VA_ARGS__); printf(format, __VA_ARGS__);/* fprintf(stderr, format, __VA_ARGS__); */
+	#endif
+#else
+	#if defined(SEGA) | defined(NINTENDO_DS)
+		#define ERRORPUTS(string)	DEBUGPUTS(string); puts(string)
+		#define ERRORPRINTF(format, ...)	DEBUGPRINTF(format, __VA_ARGS__); printf(format, __VA_ARGS__)
+	#else
+		#define ERRORPUTS(string)	DEBUGPUTS(string); fputs(string, stderr)
+		#define ERRORPRINTF(format, ...)	DEBUGPRINTF(format, __VA_ARGS__); fprintf(stderr, format, __VA_ARGS__)
+	#endif
+#endif
+
+#endif //_DEBUGMACROS_H_
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dict.c	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,475 @@
+#include "datum.h"
+#include "structs.h"
+#include "debugmacros.h"
+#include <string.h>
+#include <stdlib.h>
+//Index, Swap, Remove, Set, Length, New
+
+ternary_node * find_node(datum * dict, datum * key, BOOL novalue)
+{
+	int i = 0;
+	ternary_node * nodes;
+	ternary_node * current = ((dict_data *)dict->c.generic.data)->nodes;
+	nodes = current;
+	if(((dict_data *)dict->c.generic.data)->num_nodes <= 0 || key->c.generic.len <= 1)
+		return NULL;
+	while(current >= nodes)
+	{
+		DEBUGPRINTF("current->letter: %c, key[%d]: %c\n", current->letter, i, ((char*)key->c.generic.data)[i]);
+		if(((char*)key->c.generic.data)[i] == current->letter)
+			if(i == (key->c.generic.len-2))
+				if(current->payload || novalue)
+					return current;
+				else
+					return NULL;
+			else
+			{
+				current = nodes + current->next;
+				++i;
+			}
+		else if(((char *)key->c.generic.data)[i] > current->letter)
+			current = nodes + current->right;
+		else
+			current = nodes + current->left;
+	}
+	return NULL;
+}
+
+int vis_dict_index(datum ** inputlist, queue_entry * worker_entry)
+{
+	datum * output;
+	int i = 0;
+	ternary_node * found = find_node(inputlist[0], inputlist[1], FALSE);
+	release_ref(inputlist[1]);
+	if(found)
+	{
+		DEBUGPRINTF("Found payload: %X\n", found->payload);
+		/*if(found->payload->type == BUILTIN_TYPE_STRING)
+		{
+			DEBUGPRINTF("Payload: %s\n", found->payload->c.generic.data);
+		}*/
+			
+		output = add_ref(found->payload);
+		inputlist[1] = NULL;
+	}
+	else
+	{
+		inputlist[1] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, worker_entry->instance->def->program);
+		inputlist[1]->c.integers.num_a = 0;
+		output = NULL;
+	}
+	release_ref(inputlist[0]);
+	inputlist[0] = output;
+	return 0;
+}
+
+int vis_dict_swap(datum ** inputlist, queue_entry * worker_entry)
+{
+	ternary_node *first, *second;
+	datum * temp;
+	inputlist[0] = copy_datum(inputlist[0],0);
+	first = find_node(inputlist[0], inputlist[1], FALSE);
+	if(first)
+	{
+		second = find_node(inputlist[0], inputlist[2], FALSE);
+		if(second)
+		{
+			temp = first->payload;
+			first->payload = second->payload;
+			second->payload = temp;
+		}
+	}
+	release_ref(inputlist[1]);
+	release_ref(inputlist[2]);
+	return 0;
+}
+
+int vis_dict_remove(datum ** inputlist, queue_entry * worker_entry)
+{
+	//NOTE: Currently optimized for speed not for memory usage
+	//Doesn't remove ternary_nodes that are no longer needed
+	ternary_node * found;
+	dict_data * dict;
+	inputlist[0] = copy_datum(inputlist[0],0);
+	found = find_node(inputlist[0], inputlist[1], FALSE);
+	release_ref(inputlist[1]);
+	dict = (dict_data *)inputlist[0]->c.generic.data;
+	if(found)
+	{
+		release_ref(found->payload);
+		found->payload = NULL;
+		--(dict->num_entries);
+	}
+	return 0;
+}
+
+int vis_dict_set(datum ** inputlist, queue_entry * worker_entry)
+{
+	ternary_node * found, *current, *last;
+	dict_data * dict, *new_dict;
+	int new_node_storage,i,dir;
+	int newlen;
+	//DEBUGPRINTF("Payload: %s\n", inputlist[2]->c.generic.data);
+	inputlist[0] = copy_datum(inputlist[0],0);
+	found = find_node(inputlist[0], inputlist[1], TRUE);
+	dict = (dict_data *)inputlist[0]->c.generic.data;
+	DEBUGPRINTF("key: %s\n", inputlist[1]->c.generic.data);
+	DEBUGPRINTF("Num nodes: %d, num entries: %d\n", dict->num_nodes, dict->num_entries);
+	if(found)
+	{
+		if(found->payload)
+			release_ref(found->payload);
+		else
+			++(dict->num_entries);
+		found->payload = inputlist[2];
+	}
+	else if(inputlist[1]->c.generic.len > 1) //FIXME: silently fail on zero-length keys for now
+	{
+		if(dict->num_nodes)
+		{
+			current = dict->nodes;
+			i = 0;
+			while(current >= dict->nodes)
+			{
+				DEBUGPRINTF("Current node: %X\n", current);
+				last = current;
+				DEBUGPRINTF("Current letter: %c, key letter: %c\n", current->letter,((char *)inputlist[1]->c.generic.data)[i]);
+				if(((char *)inputlist[1]->c.generic.data)[i] == current->letter)
+				{
+					DEBUGPUTS("Went straight\n");
+					++i;
+					current = dict->nodes + current->next;
+					dir = 0;
+				}
+				else if(((char *)inputlist[1]->c.generic.data)[i] > current->letter)
+				{
+					DEBUGPUTS("Went right\n");
+					current = dict->nodes + current->right;
+					dir = 1;
+				}
+				else
+				{
+					DEBUGPUTS("Went left\n");
+					current = dict->nodes + current->left;
+					dir = 2;
+				}
+			}
+			DEBUGPRINTF("Matched %d out of %d characters\n", i, (inputlist[1]->c.generic.len-1));
+			DEBUGPRINTF("node_storage: %d, num_nodes: %d\n", dict->node_storage, dict->num_nodes);
+			if((dict->node_storage-dict->num_nodes) < ((inputlist[1]->c.generic.len-1) - i))
+			{
+				DEBUGPUTS("Allocating more storage\n");
+				new_node_storage = inputlist[1]->c.generic.len - 1 - i + dict->num_nodes;
+				new_node_storage += new_node_storage >> 1; //1.5 times required storage
+				newlen = sizeof(dict_data) + sizeof(ternary_node) * (new_node_storage-1);
+				new_dict = malloc(newlen);
+				DEBUGPRINTF("After malloc: new_dict = %X, size: %d, new_node_storage: %d\n", new_dict, newlen, new_node_storage);
+				memcpy(new_dict, dict, sizeof(dict_data) + sizeof(ternary_node) * (dict->num_nodes-1));
+				DEBUGPUTS("After memcpyy\n");
+				new_dict->node_storage = new_node_storage;
+				//new_dict->num_entries = dict->num_entries + 1;
+				new_dict->num_nodes = dict->num_nodes;
+				DEBUGPRINTF("last was: %X, dict->nodes was: %X, ", last, dict->nodes);
+				last = new_dict->nodes + (last - dict->nodes);
+				DEBUGPRINTF("last is now: %X, dict->nodes is now : %X, ", last, new_dict->nodes);
+				VIS_FREE(dict, "dictionary object");
+				DEBUGPUTS("After free\n");
+				dict = new_dict;
+				inputlist[0]->c.generic.data = dict;
+				inputlist[0]->c.generic.len = newlen;
+			}
+			++(dict->num_entries);
+			DEBUGPRINTF("Setting current to: %X\n", dict->nodes + dict->num_nodes);
+			current =dict->nodes + dict->num_nodes;
+			DEBUGPUTS("Setting left, right and next pointer to null\n");
+			current->left = current->right = current->next = -1;
+			current->payload = NULL;
+			current->letter = ((char *)inputlist[1]->c.generic.data)[i];
+			DEBUGPRINTF("Setting pointer in last node (%X) to current node\n", last);
+			if(dir == 1)
+				last->right = dict->num_nodes;
+			else if(dir == 2)
+				last->left = dict->num_nodes;
+			else
+				last->next = dict->num_nodes;
+			++i;
+			++(dict->num_nodes);
+			last = current;
+			DEBUGPUTS("Entering node add loop\n");
+			for(;i < (inputlist[1]->c.generic.len-1); ++i)
+			{
+				DEBUGPRINTF("Adding node at index %d\n", dict->num_nodes);
+				current = dict->nodes + dict->num_nodes;
+				last->next = dict->num_nodes;
+				current->left = current->right = current->next = -1;
+				current->payload = NULL;
+				current->letter = ((char *)inputlist[1]->c.generic.data)[i];
+				++(dict->num_nodes);
+				last = current;
+			}
+			DEBUGPUTS("Loop complete\n");
+			last->payload = inputlist[2];
+		}
+		else
+		{
+			if(dict->node_storage < (inputlist[1]->c.generic.len-1))
+			{
+				VIS_FREE(dict, "dictionary object");
+				newlen = sizeof(dict_data) + sizeof(ternary_node) * ((inputlist[1]->c.generic.len-1)<<2);
+				dict = malloc(newlen);
+				dict->node_storage = ((inputlist[1]->c.generic.len-1)<<2) + 1;
+				inputlist[0]->c.generic.data = dict;
+				inputlist[0]->c.generic.len = newlen;
+				
+			}
+			dict->num_entries = 1;
+			dict->num_nodes = (inputlist[1]->c.generic.len-1);
+			for(i = 0; i < dict->num_nodes; ++i)
+			{
+				dict->nodes[i].left = dict->nodes[i].right = -1;
+				dict->nodes[i].letter = ((char *)inputlist[1]->c.generic.data)[i];
+				if(i == (dict->num_nodes - 1))
+				{
+					dict->nodes[i].next = -1;
+					dict->nodes[i].payload = inputlist[2];
+				}
+				else
+				{
+					dict->nodes[i].next = i + 1;
+					dict->nodes[i].payload = NULL;
+				}
+			}
+		}
+	}
+	release_ref(inputlist[1]);
+	DEBUGPRINTF("Num nodes after set: %d\n", dict->num_nodes);
+	//DEBUGPRINTF("Payload: %s\n", inputlist[2]->c.generic.data);
+	return 0;
+}
+
+int vis_dict_length(datum ** inputlist, queue_entry * worker_entry)
+{
+	datum * output;
+	dict_data * dict = ((dict_data *)inputlist[0]->c.generic.data);
+	output = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program);
+	output->c.integers.num_a = dict->num_entries;
+	release_ref(inputlist[0]);
+	inputlist[0] = output;
+	return 0;
+}
+
+datum * create_dict(program * prog)
+{
+	dict_data * dict;
+	datum * dat = new_datum(BUILTIN_TYPE_DICT, 1, sizeof(dict_data) + sizeof(ternary_node)*23, prog);
+	dict = (dict_data *)dat->c.generic.data;
+	dict->num_entries = 0;
+	dict->num_nodes = 0;
+	dict->node_storage = 24;
+	return dat;
+}
+
+int vis_dict_new(datum ** inputlist, queue_entry * worker_entry)
+{
+	inputlist[0] = create_dict(worker_entry->instance->def->program);
+	return 0;
+}
+
+#define APPEND_KEY_STORE(key, key_store, key_size, val) if(key_size == key_store) { key_store = key_store + (key_store>>1); key = realloc(key, key_store); } key[key_size++] = val
+
+int vis_dict_first(datum ** inputlist, queue_entry * worker_entry)
+{
+	dict_data * dict = inputlist[0]->c.generic.data;
+	char * key;
+	int key_store = 128;
+	int key_size = 0;
+	
+	int i = 0;
+	ternary_node * nodes;
+	ternary_node * current = dict->nodes;
+	nodes = current;
+	if(dict->num_nodes <= 0)
+	{
+		inputlist[1] = inputlist[0];
+		inputlist[0] = NULL;
+	}
+	else
+	{
+		key = malloc(128);
+		while(1)
+		{
+			if(current->left >= 0)
+			{
+				current = nodes + current->left;
+			} else if(current->payload) {
+				APPEND_KEY_STORE(key, key_store, key_size, current->letter);
+				APPEND_KEY_STORE(key, key_store, key_size, '\0');
+				release_ref(inputlist[0]);
+				inputlist[0] = new_datum(BUILTIN_TYPE_STRING, 2, 0, worker_entry->instance->def->program);
+				inputlist[0]->union_type = 1;
+				inputlist[0]->c.generic.data = key;
+				inputlist[0]->c.generic.len = key_size;
+				inputlist[1] = NULL;
+				break;
+			} else if(current->next >= 0) {
+				APPEND_KEY_STORE(key, key_store, key_size, current->letter);
+				current = nodes + current->next;
+			} else if(current->right >= 0) {
+				current = nodes + current->right;
+			} else {
+				inputlist[1] = inputlist[0];
+				inputlist[0] = NULL;
+				VIS_FREE(key, "dictionary key store");
+				break;
+			}
+		}
+	}
+	return 0;
+}
+
+int vis_dict_next(datum ** inputlist, queue_entry * worker_entry)
+{
+	dict_data * dict = inputlist[0]->c.generic.data;
+	char * key;
+	char * old_key = inputlist[1]->c.generic.data;
+	int old_key_len = inputlist[1]->c.generic.len-2;
+	int key_store = inputlist[1]->c.generic.len;
+	int key_size = 0;
+	
+	int i = 0;
+	ternary_node * nodes;
+	ternary_node * current = dict->nodes;
+	ternary_node * decision = NULL;
+	int decision_key_size;
+	BOOL next_flag = FALSE;
+	nodes = current;
+	
+	if(dict->num_nodes <= 0)
+	{
+		release_ref(inputlist[1]);
+		inputlist[1] = inputlist[0];
+		inputlist[0] = NULL;
+		return 0;
+	}
+	else
+	{
+		key = malloc(key_store);
+		while(current >= nodes)
+		{
+			if(old_key[i] == current->letter)
+				if(i == (old_key_len))
+				{
+					if(current->left >= 0)
+					{
+						current = nodes + current->left;
+						break;
+					}
+					else if(current->next >= 0)
+					{
+						APPEND_KEY_STORE(key, key_store, key_size, current->letter);
+						current = nodes + current->next;
+						break;
+					}
+					else if(current->right >= 0)
+					{
+						current = nodes + current->right;
+						break;
+					}
+					else
+					{
+						if(decision)
+						{
+							key_size = decision_key_size;
+							current = decision;
+							if(next_flag)
+							{
+								APPEND_KEY_STORE(key, key_store, key_size, current->letter);
+								current = nodes + current->next;
+							}
+							break;
+						}
+						else
+						{
+							VIS_FREE(key, "dictionary key store");
+							release_ref(inputlist[1]);
+							inputlist[1] = inputlist[0];
+							inputlist[0] = NULL;
+							return 0;
+						}
+					}
+				}
+				else
+				{
+					if(current->right >= 0)
+					{
+						decision = nodes + current->right;
+						decision_key_size = key_size;
+						next_flag = FALSE;
+					}
+					APPEND_KEY_STORE(key, key_store, key_size, current->letter);
+					++i;
+					current = nodes + current->next;
+				}
+			else if(old_key[i] > current->letter)
+				current = nodes + current->right;
+			else
+			{
+				if(current->next >= 0)
+				{
+					//APPEND_KEY_STORE(key, key_store, key_size, current->letter);
+					decision = current;//nodes + current->next;
+					decision_key_size = key_size;
+					next_flag = TRUE;
+				}
+				else if(current->right >= 0)
+				{
+					decision = nodes + current->right;
+					decision_key_size = key_size;
+					next_flag = FALSE;
+				}
+				current = nodes + current->left;
+			}
+		}
+		if(current < nodes)
+		{
+			VIS_FREE(key, "dictionary key store");
+			release_ref(inputlist[1]);
+			inputlist[1] = inputlist[0];
+			inputlist[0] = NULL;
+			return 0;
+		}
+		while(1)
+		{
+			if(current->left >= 0)
+			{
+				current = nodes + current->left;
+			} else if(current->payload) {
+				APPEND_KEY_STORE(key, key_store, key_size, current->letter);
+				APPEND_KEY_STORE(key, key_store, key_size, '\0');
+				release_ref(inputlist[0]);
+				release_ref(inputlist[1]);
+				inputlist[1] = NULL;
+				inputlist[0] = new_datum(BUILTIN_TYPE_STRING, 2, 0, worker_entry->instance->def->program);
+				inputlist[0]->union_type = 1;
+				inputlist[0]->c.generic.data = key;
+				inputlist[0]->c.generic.len = key_size;
+				break;
+			} else if(current->next >= 0) {
+				APPEND_KEY_STORE(key, key_store, key_size, current->letter);
+				current = nodes + current->next;
+			} else if(current->right >= 0) {
+				current = nodes + current->right;
+			} else {
+				release_ref(inputlist[1]);
+				inputlist[1] = inputlist[0];
+				inputlist[0] = NULL;
+				VIS_FREE(key, "dictionary key store");
+				break;
+			}
+		}
+	}
+	return 0;
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ds_hardware.c	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,170 @@
+#include <nds/interrupts.h>
+#include <nds.h>
+#include "datum.h"
+#include "interp.h"
+#include "structs.h"
+#include <string.h>
+
+#define IRQ_STUB(num) void irq_stub_##num () { rhope_irq(num); }
+
+datum * irq_workers[MAX_INTERRUPTS] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
+program * irq_programs[MAX_INTERRUPTS];
+worker_instance irq_instances[MAX_INTERRUPTS];
+int irq_queue[MAX_INTERRUPTS];
+int irq_queue_count = 0;
+
+void rhope_irq(int num)
+{
+	if(num < MAX_INTERRUPTS && irq_workers[num])
+	{
+		if(irq_queue_count < MAX_INTERRUPTS)
+			irq_queue[irq_queue_count++] = num;
+		//TODO Add some kind of error handling for when the IRQ_QUEUE Is full?
+	}
+}
+
+IRQ_STUB(0)
+IRQ_STUB(1)
+IRQ_STUB(2)
+IRQ_STUB(3)
+IRQ_STUB(4)
+IRQ_STUB(5)
+IRQ_STUB(6)
+IRQ_STUB(7)
+IRQ_STUB(8)
+IRQ_STUB(9)
+IRQ_STUB(10)
+IRQ_STUB(11)
+IRQ_STUB(12)
+IRQ_STUB(13)
+IRQ_STUB(14)
+IRQ_STUB(15)
+IRQ_STUB(16)
+IRQ_STUB(17)
+IRQ_STUB(18)
+IRQ_STUB(19)
+IRQ_STUB(20)
+IRQ_STUB(21)
+IRQ_STUB(22)
+IRQ_STUB(23)
+IRQ_STUB(24)
+
+
+
+
+VoidFunctionPointer handlerList[MAX_INTERRUPTS] = {irq_stub_0,irq_stub_1,irq_stub_2,irq_stub_3,irq_stub_4,irq_stub_5,irq_stub_6,irq_stub_7,irq_stub_8,irq_stub_9,irq_stub_10,irq_stub_11,irq_stub_12,irq_stub_13,irq_stub_14,irq_stub_15,irq_stub_16,irq_stub_17,irq_stub_18,irq_stub_19,irq_stub_20,irq_stub_21,irq_stub_22,irq_stub_23,irq_stub_24};
+
+int vis_register_handler(datum ** params, queue_entry * entry)
+{
+	int num = params[0]->c.integers.num_a;
+	if(num >= MAX_INTERRUPTS)
+	{
+		release_ref(params[1]);
+		params[1] = copy_datum(params[0], 0);
+		params[0] = NULL;
+		params[1]->c.integers.num_a = MAX_INTERRUPTS-1;
+		return 0;
+	}
+	REG_IME = IME_DISABLE;
+	if(irq_workers[num])
+		release_ref(irq_workers[num]);
+	irqSet(1<<num, handlerList[num]);
+	irq_workers[num] = params[1];
+	irq_programs[num] = entry->instance->def->program; //technically the worker could be from a different program than the one doing the registering, but it's doubtful
+	irq_instances[num].def = irq_programs[num]->defs->deflist;
+	irq_instances[num].caller_instance = NULL;
+	irq_instances[num].trans = NULL;
+	irq_instances[num].num_workers = irq_instances[num].num_wires = 0;
+	VIS_InitializeCriticalSection(inst.counter_lock);
+	REG_IME = IME_ENABLE;
+	params[1] = NULL;
+	return 0;
+}
+
+int vis_clear_handler(datum ** params, queue_entry * entry)
+{
+	int num = params[0]->c.integers.num_a;
+	if(num >= MAX_INTERRUPTS)
+	{
+		release_ref(params[1]);
+		params[1] = copy_datum(params[0], 0);
+		params[0] = NULL;
+		params[1]->c.integers.num_a = MAX_INTERRUPTS-1;
+		return 0;
+	}
+	REG_IME = IME_DISABLE;
+	if(irq_workers[num])
+		release_ref(irq_workers[num]);
+	irqClear(1<<num);
+	irq_workers[num] = NULL;
+	REG_IME = IME_ENABLE;
+	params[1] = NULL;
+	return 0;
+}
+
+
+void run_queued_irqs()
+{
+	int irq_queue_copy[MAX_INTERRUPTS];
+	int irq_queue_count_copy;
+	int i;
+	queue_entry entry;
+	datum * params[32];
+	entry.worker_num = 0;
+	//Could this result in missed interrupts or will they just be queued in hardware until I re-enable them?
+	REG_IME = IME_DISABLE;
+		irq_queue_count_copy = irq_queue_count;
+		memcpy(irq_queue_copy, irq_queue, sizeof(int) * irq_queue_count);
+		irq_queue_count = 0;
+	REG_IME = IME_ENABLE;
+	for(i = 0; i < irq_queue_count_copy; ++i)
+	{
+		params[0] = add_ref(irq_workers[irq_queue_copy[i]]);
+		params[1] = create_list(irq_programs[irq_queue_copy[i]]);
+		params[2] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, irq_programs[irq_queue_copy[i]]);
+		params[2]->c.integers.num_a = irq_queue_copy[i];
+		vis_list_append(params + 1, &entry);
+		entry.instance = &irq_instances[irq_queue_copy[i]];
+		entry.instance->in_progress_count = entry.instance->in_queue_count = 1000;
+		vis_worker_do(params, &entry);
+	}
+
+}
+
+const char ndsKeyLetters[15] = "ABESRLUD><XYMC";
+#define NDS_MAX_KEY_BITS	14
+
+int vis_held_keys(datum ** params, queue_entry * worker_entry)
+{
+	datum * workparams[3];
+	datum * yes;
+	char key_string[2] = " ";
+	int held,i;
+	scanKeys();
+	held = keysHeld();
+	workparams[0] = create_dict(worker_entry->instance->def->program);
+	yes = new_datum(BUILTIN_TYPE_YESNO, 2, 0, worker_entry->instance->def->program);
+	yes->c.integers.num_a = 1;
+	for(i = 0; i < NDS_MAX_KEY_BITS; ++i)
+		if(held & (1 << i))
+		{
+			key_string[0] = ndsKeyLetters[i];
+			workparams[1] = make_string(key_string, -1, worker_entry->instance->def->program);
+			workparams[2] = add_ref(yes);
+			vis_dict_set(workparams, worker_entry);
+		}
+	params[0] = workparams[0];
+	release_ref(yes);
+	return 0;
+}
+
+int vis_touch_position(datum ** params, queue_entry * worker_entry)
+{
+	touchPosition touchXY;
+	touchXY=touchReadXY();
+	params[0] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program);
+	params[1] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program);
+	params[0]->c.integers.num_a = touchXY.px;
+	params[1]->c.integers.num_a = touchXY.py;
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ds_main.c	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,52 @@
+/*---------------------------------------------------------------------------------
+
+	$Id: main.c,v 1.5 2007/10/23 00:46:29 wntrmute Exp $
+
+	Simple console print demo
+	-- dovoto
+
+---------------------------------------------------------------------------------*/
+#include <nds.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "saveload.h"
+#include "structs.h"
+#include "interp.h"
+
+//---------------------------------------------------------------------------------
+int main(void) {
+//---------------------------------------------------------------------------------
+	touchPosition touchXY;
+	program * prog;
+
+	irqInit();
+
+	videoSetMode(0);	//not using the main screen
+	videoSetModeSub(MODE_0_2D | DISPLAY_BG0_ACTIVE);	//sub bg 0 will be used to print text
+	vramSetBankC(VRAM_C_SUB_BG);
+
+	SUB_BG0_CR = BG_MAP_BASE(31);
+
+	BG_PALETTE_SUB[255] = RGB15(31,31,31);	//by default font will be rendered with color 255
+
+	//consoleInit() is a lot more flexible but this gets you up and running quick
+	consoleInitDefault((u16*)SCREEN_BASE_BLOCK_SUB(31), (u16*)CHAR_BASE_BLOCK_SUB(0), 16);
+
+	fatInitDefault();
+
+	prog = load_program("/program.vistxt");
+
+	interp_start(-1,TRUE, 0, NULL, prog);
+
+	while(1) {
+
+		touchXY=touchReadXY();
+		iprintf("\x1b[10;0HTouch x = %04X, %04X\n", touchXY.x, touchXY.px);
+		iprintf("Touch y = %04X, %04X\n", touchXY.y, touchXY.py);
+
+		swiWaitForVBlank();
+	}
+
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/extendlib.rhope	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,526 @@
+
+Val[in:out]
+{
+	out <- in
+}
+
+_Map[list,index,worker:out]
+{
+	newval <- [
+		[worker]Do[  
+			[()]Append[ [list]Index[index] ]
+		]
+	]Index[0]
+	
+	[list]Next[index]
+	{
+		out <- [_Map[list, ~, worker]]Set[index, newval]
+	}{
+		out <- [list]Set[index, newval]
+	}
+}
+
+Map[list,worker:out]
+{
+	[list]First
+	{
+		out <- _Map[list, ~, worker]
+	}{
+		out <- list
+	}
+}
+
+_Key Value Map[list,index,newlist,worker:out]
+{
+	[worker]Do[
+		[[()]Append[ [list]Index[index] ]]Append[index]
+	]
+	{
+		newval <- [~]Index[0]
+		newkey <- [~]Index[1]
+	}
+	
+	next <- [newlist]Set[newkey, newval]
+	
+	[list]Next[index]
+	{
+		out <- _Key Value Map[list, ~, next, worker]
+	}{
+		out <- Val[next]
+	}
+}
+
+New Like@List[in:out]
+{
+	out <- ()
+}
+
+New Like@Dictionary[in:out]
+{
+	out <- New@Dictionary[]
+}
+
+Key Value Map[list,worker:out]
+{
+	[list]First
+	{
+		out <- _Key Value Map[list, ~, New Like[list], worker]
+	}{
+		out <- New Like[list]
+	}
+}
+
+In[needle,haystack:found?]
+{
+	[haystack]Get DString[needle]
+	{
+		found? <- Yes
+	} {} {} {
+		found? <- No
+	}
+}
+
+Left Trim[string,trim:trimmed]
+{
+	If[ [[string]Length] > [0] ]
+	{
+		first,rest <- [string]Slice[1]
+		If[ [first]In[trim] ]
+		{
+			trimmed <- Left Trim[rest, trim]
+		}{
+			trimmed <- string
+		}
+	}{
+		trimmed <- string
+	}
+}
+
+Right Trim[string,trim:trimmed]
+{
+	If[ [[string]Length] > [0] ]
+	{
+		rest,last <- [string]Slice[ [[string]Length] - [1]]
+		If[ [last]In[trim] ]
+		{
+			trimmed <- Right Trim[rest, trim]
+		}{
+			trimmed <- string
+		}
+	}{
+		trimmed <- string
+	}
+}
+
+Trim[string,trim:trimmed]
+{
+	left <- Left Trim[string, trim]
+	trimmed <- Right Trim[left, trim]
+}
+
+Max[a,b:max]
+{
+	If[[a] > [b]]
+	{
+		max <- a
+	}{
+		max <- b
+	}
+}
+
+Count Substring[string,substring:out]
+{
+	out <- Max[[[[string]Split[substring]]Length] - [1], 0]
+}
+
+_Key Value Join[dict,key,key sep,val sep,string:out]
+{
+	new string <- [[[string]Append[key]]Append[key sep]]Append[ [dict]Index[key] ]
+	[dict]Next[key]
+	{
+		out <- _Key Value Join[dict, ~, key sep, val sep, [new string]Append[val sep]]
+	}{
+		out <- Val[new string]
+	}
+}
+
+Key Value Join[dict,key sep,val sep:out]
+{
+	[dict]First
+	{
+		out <- _Key Value Join[dict, ~, key sep, val sep, ""]
+	}{
+		out <- ""
+	}
+}
+
+_Combine[source,dest,key:out]
+{
+	new dest <- [dest]Set[key, [source]Index[key]]
+	[source]Next[key]
+	{
+		out <- _Combine[source, new dest, ~]
+	}{
+		out <- Val[new dest]
+	}
+}
+
+Combine[source,dest:out]
+{
+	[source]First
+	{
+		out <- _Combine[source, dest, ~]
+	}{
+		out <- dest
+	}
+}
+
+_Fold[list,index,current,worker:out]
+{
+	newval <- [
+		[worker]Do[  
+			[[[()]Append[ current ]]Append[ [list]Index[index] ]]Append[index]
+		]
+	]Index[0]
+	
+	[list]Next[index]
+	{
+		out <- _Fold[list, ~, newval, worker]
+	}{
+		out <- Val[newval]
+	}
+}
+
+Fold[worker,start,list:out]
+{
+	[list]First
+	{
+		out <- _Fold[list, ~, start, worker]
+	}{
+		out <- start
+	}
+}
+
+_Dict Split[dict,entry,index,keydelim:out]
+{
+	parts <- [entry]Split[keydelim]
+	out <- [dict]Set[[parts]Index[0],[parts]Index[1]]
+}
+
+Dict Split[string,keydelim,entrydelim:out]
+{
+	out <- Fold[["_Dict Split"]Set Input[3, keydelim], New@Dictionary[], [string]Split[entrydelim]] 
+}
+
+Previous@List[list,index:prev index,not found]
+{
+	prev <- [index] - [1]
+	If[[prev] < [0]]
+	{
+		not found <- list
+	}{
+		[list]Index[prev]
+		{
+			prev index <- Val[prev]
+		}{
+			prev index, not found <- [list]Previous[prev]
+		}
+	}
+}
+
+Last@List[list:out,not found]
+{
+	out, not found <- [list]Previous[[list]Length]
+}
+
+_Reverse Fold[list,index,start,worker:out]
+{
+	newval <- [
+		[worker]Do[  
+			[[[()]Append[ start ]]Append[ [list]Index[index] ]]Append[index]
+		]
+	]Index[0]
+	
+	[list]Previous[index]
+	{
+		out <- _Reverse Fold[list, ~, newval, worker]
+	}{
+		out <- Val[newval]
+	}
+}
+
+Reverse Fold[worker,start,list:out]
+{
+	[list]Last
+	{
+		out <- _Reverse Fold[list, ~, start, worker]
+	}{
+		out <- list
+	}
+}
+
+_Join[list,delim,current,index:out]
+{
+	[list]Next[index]
+	{
+		out <- _Join[list, delim, [[current]Append[delim]]Append[[list]Index[~]], ~]
+	}{
+		out <- current
+	}
+}
+
+Join[list,delim:out]
+{
+	[list]First
+	{
+		out <- _Join[list, delim, [list]Index[~], ~]
+	}{
+		out <- ""
+	}
+}
+
+Replace[string,find,replace:replaced]
+{
+	replaced <- [[string]Split[find]]Join[replace]
+}
+
+Concatenate[left,right:out]
+{
+	out <- Fold[["Append"]<String@Worker, left, right]
+}
+
+Starts With[thing,starts with:out]
+{
+	out <- [[thing]Slice[[starts with]Length]] = [starts with]
+}
+
+Ends With[thing,ends with:out]
+{
+	,compare <- [thing]Slice[ [[thing]Length] - [[ends with]Length] ]
+	out <- [compare] = [ends with]
+}
+
+As List@String[string:list]
+{
+	list <- [()]Append[string]
+}
+
+As List@List[in:out]
+{
+	out <- in
+}
+
+_Filter[list,index,worker,destlist:out]
+{
+	filter? <- [
+		[worker]Do[  
+			[()]Append[ [list]Index[index] ]
+		]
+	]Index[0]
+	If[filter?]
+	{
+		newlist <- [destlist]Append[[list]Index[index]]
+	}{
+		newlist <- destlist
+	}
+	
+	[list]Next[index]
+	{
+		out <- _Filter[list, ~, worker, newlist]
+	}{
+		out <- Val[newlist]
+	}
+}
+
+Filter[list,worker:out]
+{
+	[list]First
+	{
+		out <- _Filter[list, ~, worker, ()]
+	}{
+		out <- list
+	}
+}
+
+Pop@List[list:out]
+{
+	[list]Last
+	{
+		out <- [list]Remove[~]
+	}{
+		out <- list
+	}
+}
+
+Peek@List[list:out,empty]
+{
+	[list]Last
+	{
+		out <- [list]Index[~]
+	}{
+		empty <- list
+	}
+}
+
+Contains[haystack,needle:out]
+{
+	[haystack]Get DString[needle]
+	{
+		out <- Yes
+	} {} {} {
+		out <- No
+	}
+}
+
+_Find[haystack,needle,index:outindex,notfound]
+{
+	If[[[haystack]Index[index]] = [needle]]
+	{
+		outindex <- index
+	}{
+		[haystack]Next[index]
+		{
+			outindex,notfound <- _Find[haystack,needle,~]
+		}{
+			notfound <- needle
+		}	
+	}
+}
+
+Find[haystack,needle:index,not found]
+{
+	[haystack]First
+	{
+		index,not found <- _Find[haystack, needle, ~]
+	}{
+		not found <- needle
+	}
+
+}
+
+Get Pretty Print Value[value:print,index,print indent,done,out value]
+{
+	If[[Type Of[value]] = ["List"]]
+	{
+		out value <- value
+		list <- value
+		object <- value
+	}{
+		If[[Type Of[value]] = ["Dictionary"]]
+		{
+			out value <- value
+			list <- value
+			object <- value
+		}{
+			If[[Type Of[value]] = ["String"]]
+			{
+				out value <- value
+				print <- value
+				done <- 1
+			}{
+				If[[Type Of[value]] = ["Whole Number"]]
+				{
+					out value <- value
+					print <- value
+					done <- 1
+				}{
+					If[[Type Of[value]] = ["Yes No"]]
+					{
+						out value <- value
+						print <- value
+						done <- 1
+					}{
+						If[[Type Of[value]] = ["Real Number"]]
+						{
+							out value <- value
+							print <- value
+							done <- 1
+						}{
+							object <- value
+							fieldlist <- [Blueprint Of[value]]Get Fields
+							[fieldlist]First
+							{
+								list <- _Object to Dict[value, fieldlist, ~, New@Dictionary[]]
+								out value <- Val[list]
+							}{
+								out value <- value
+								done <- 1
+							}
+						}
+					}
+				}
+			}
+			
+		}
+	}
+	print <- Type Of[object]
+	index <- [list]First {}
+	{
+		print indent <- "{Empty}"
+	}
+	
+}
+
+Pretty Print Helper[list,tabs,index:out]
+{
+	newtabs <- [tabs]Append["    "]
+	print,new index,indented,done,value <- Get Pretty Print Value[[list]Index[index]]
+	Print[ [[[tabs]Append[index]]Append[": "]]Append[print] ]
+	{
+		done <- Pretty Print Helper[value,newtabs ,new index]
+		done <- Print[[newtabs]Append[indented]]
+		
+		Val[done]
+		{
+			[list]Next[index]
+			{
+				out <- Pretty Print Helper[list, tabs, ~]
+			}{
+				out <- 1
+			}
+		}
+	}
+	
+}
+
+Pretty Print[toprint,tabs:out]
+{
+	newtabs <- [tabs]Append["    "]
+	,index,indented,,value <- Get Pretty Print Value[toprint]
+	{
+		Print[[tabs]Append[~]]
+		{
+			Pretty Print Helper[value,newtabs ,index]
+			Print[[newtabs]Append[indented]]
+		}
+	}
+	out <- 1
+}
+
+_Object to Dict[object,field list,index,dict:out]
+{
+	field <- [field list]Index[index]
+	[object]Get Field[field]
+	{
+		nextdict <- [dict]Set[field, ~]
+	}{
+		nextdict <- dict
+	}
+	[field list]Next[index]
+	{
+		out <- _Object to Dict[object, field list, ~, nextdict]
+	}{
+		out <- Val[nextdict]
+	}
+}
+
+_Keys[list,val,key:out]
+{
+	out <- [list]Append[key]
+}
+
+Keys[container:out]
+{
+	out <- Fold["_Keys", New@List[], container]
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/extendlib.vistxt	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,690 @@
+
+Val(1,1)
+|:
+	(0) <- (0)
+:|
+
+Map Helper(3,1)
+|:
+	newval <- [
+		[worker(2)]Do[  
+			[New@List[]]Append[ [list(0)]Index[index(1)] ]
+		]
+	]Index[0]
+	
+	[list(0)]Next[index(1)]
+	|:
+		out(0) <- [Map Helper[list(0), ~, worker(2)]]Set[index(1), newval]
+	:||:
+		out(0) <- [list(0)]Set[index(1), newval]
+	:|
+:|
+
+Map(2,1)
+|:
+	[list(0)]First
+	|:
+		out(0) <- Map Helper[list(0), ~, worker(1)]
+	:||:
+		out(0) <- list(0)
+	:|
+:|
+
+New Like@List(1,1)
+|:
+	out(0) <- New@List[]	
+:|
+
+New Like@Dictionary(1,1)
+|:
+	out(0) <- New@Dictionary[]
+:|
+
+Key Value Map Helper(4,1)
+|:
+	[worker(3)]Do[  
+		[[New@List[]]Append[ [list(0)]Index[index(1)] ]]Append[index(1)]
+	]
+	|:
+		newval <- [~]Index[0]
+		newkey <- [~]Index[1]
+	:|
+	
+	next <- [newlist(2)]Set[newkey, newval]
+	
+	[list(0)]Next[index(1)]
+	|:
+		out(0) <- Key Value Map Helper[list(0), ~, next, worker(3)]
+	:||:
+		out(0) <- Val[next]
+	:|
+:|
+
+Key Value Map(2,1)
+|:
+	[list(0)]First
+	|:
+		out(0) <- Key Value Map Helper[list(0), ~, New Like[list(0)], worker(1)]
+	:||:
+		out(0) <- New Like[list(0)]
+	:|
+:|
+
+Dict Split Helper(4,1)
+|:
+	If[ [i(2)] < [[list(0)]Length@List] ]
+	|:
+		keyval <- Split@String[ [list(0)]Index@List[i(2)], keydelim(1) ]
+		key <- [keyval]Index@List[0]
+		val <- [keyval]Index@List[1]
+		HelpOut(0) <- Dict Split Helper[ list(0), keydelim(1), [i(2)] + [1], [dict(3)]Set@Dictionary[key, val] ]
+	:||:
+		HelpOut(0) <- dict(3)
+	:|
+:|
+
+Dict Split(3,1)
+|:
+	Out(0) <- Dict Split Helper[ [string(0)]Split@String[entrydelim(2)] , keydelim(1), 0, New@Dictionary[]]
+:|
+
+In Helper(2,1)
+|:
+	
+	,out(0) <- If[ [[haystack(1)]Length] > [0] ]
+	|:
+		[haystack(1)]Slice[ [needle(0)]Length ]
+		|:
+			out(0) <- If[ [needle(0)] = [~] ]
+			|:
+			:||:
+				[haystack(1)]Slice[1]
+				|: :|
+				|:
+					out(0) <- In Helper[needle(0), ~]
+				:|
+			:|
+		:|
+	:|
+:|
+
+In(2,1)
+|:
+	,out(0) <- If[ [[needle(0)]Length] > [0] ]
+	|:
+		out(0) <- In Helper[needle(0), haystack(1)]
+	:|
+:|
+
+Left Trim(2,1)
+|:
+	If[ [[string(0)]Length] > [0] ]
+	|:
+		first,rest <- [string(0)]Slice[1]
+		If[ [first]In[trim(1)] ]
+		|:
+			trimmed(0) <- Left Trim[rest, trim(1)]
+		:||:
+			trimmed(0) <- string(0)
+		:|
+	:||:
+		trimmed(0) <- string(0)
+	:|
+:|
+
+Right Trim(2,1)
+|:
+	If[ [[string(0)]Length] > [0] ]
+	|:
+		rest,last <- [string(0)]Slice[ [[string(0)]Length] - [1]]
+		If[ [last]In[trim(1)] ]
+		|:
+			trimmed(0) <- Right Trim[rest, trim(1)]
+		:||:
+			trimmed(0) <- string(0)
+		:|
+	:||:
+		trimmed(0) <- string(0)
+	:|
+:|
+
+Trim(2,1)
+|:
+	left <- Left Trim[string(0), trim(1)]
+	trimmed(0) <- Right Trim[left, trim(1)]
+:|
+
+Max(2,1)
+|:
+	If[[(0)] > [(1)]]
+	|:
+		(0) <- (0)
+	:||:
+		(0) <- (1)
+	:|
+:|
+
+Count Substring(2,1)
+|:
+	out(0) <- Max[[[[string(0)]Split[sub(1)]]Length] - [1], 0]
+:|
+
+KeyVal Helper(5,1)
+|:
+	new string <- [[[string(4)]Append[key(1)]]Append[key sep(2)]]Append[ [container(0)]Index[key(1)] ]
+	[list(0)]Next[index(1)]
+	|:
+		out(0) <- KeyVal Helper[container(0), ~, key sep(2), val sep(3), [new string]Append[val sep(3)]]
+	:||:
+		out(0) <- Val[new string]
+	:|
+:|
+
+Key Value Join(3,1)
+|:
+	[container(0)]First
+	|:
+		out(0) <- KeyVal Helper[container(0), ~, key sep(1), val sep(2), ""]
+	:||:
+		out(0) <- ""
+	:|
+:|
+
+Combine Helper(3,1)
+|:
+	new dest <- [dest(1)]Set[key(2), [source(0)]Index[key(2)]]
+	[source(0)]Next[key(2)]
+	|:
+		out(0) <- Combine Helper[source(0), new dest, ~]
+	:||:
+		out(0) <- Val[new dest]
+	:|
+:|
+
+Combine(2,1)
+|:
+	[source(0)]First
+	|:
+		out(0) <- Combine Helper[source(0), dest(1), ~]
+	:||:
+		out(0) <- dest(1)
+	:|
+:|
+
+Fold Helper(4,1)
+|:
+	newval <- [
+		[worker(3)]Do[  
+			[[[New@List[]]Append[ start(2) ]]Append[ [list(0)]Index[index(1)] ]]Append[index(1)]
+		]
+	]Index[0]
+	
+	[list(0)]Next[index(1)]
+	|:
+		out(0) <- Fold Helper[list(0), ~, newval, worker(3)]
+	:||:
+		out(0) <- Val[newval]
+	:|
+:|
+
+Fold(3,1)
+|:
+	[list(2)]First
+	|:
+		out(0) <- Fold Helper[list(2), ~, start(1), worker(0)]
+	:||:
+		out(0) <- start(1)
+	:|
+:|
+
+Previous@List(2,2)
+|:
+	prev <- [index(1)] - [1]
+	If[[prev] < [0]]
+	|:
+		not found(1) <- list(0)
+	:||:
+		[list(0)]Index[prev]
+		|:
+			out(0) <- Val[prev]
+		:||:
+			out(0), not found(1) <- [list(0)]Previous@List[prev]
+		:|
+	:|	
+:|
+
+Last@List(1,2)
+|:
+	out(0), not found(1) <- [list(0)]Previous@List[[list(0)]Length]
+:|
+
+Reverse Fold Helper(4,1)
+|:
+	newval <- [
+		[worker(3)]Do[  
+			[[[New@List[]]Append[ start(2) ]]Append[ [list(0)]Index[index(1)] ]]Append[index(1)]
+		]
+	]Index[0]
+	
+	[list(0)]Previous[index(1)]
+	|:
+		out(0) <- Reverse Fold Helper[list(0), ~, newval, worker(3)]
+	:||:
+		out(0) <- Val[newval]
+	:|
+:|
+
+Reverse Fold(3,1)
+|:
+	[list(2)]Last
+	|:
+		out(0) <- Reverse Fold Helper[list(2), ~, start(1), worker(0)]
+	:||:
+		out(0) <- start(1)
+	:|
+:|
+
+Join Helper(4,1)
+|:
+	[list(0)]Next[index(3)]
+	|:
+		out(0) <- Join Helper[list(0), delim(1), [[current(2)]Append[delim(1)]]Append[[list(0)]Index[~]], ~]
+	:||:
+		out(0) <- current(2)
+	:|
+:|
+
+Join(2,1)
+|:
+	[list(0)]First
+	|:
+		out(0) <- Join Helper[list(0), delim(1), [list(0)]Index[~], ~]
+	:||:
+		out(0) <- ""
+	:|
+:|
+
+Replace(3,1)
+|:
+	replaced(0) <- [[string(0)]Split[find(1)]]Join[replace(2)]	
+:|
+
+Concatenate(2,1)
+|:
+	out(0) <- Fold[["Append"]<String@Worker, left(0), right(1)]
+:|
+
+Serialize@String(1,1)
+|:
+	out(0) <- [[[[[string(0)]Replace["\\","\\\\"]]Replace[",","\\c"]]Replace["\n","\\n"]]Replace["{","\\l"]]Replace["}","\\r"]
+:|
+
+Unserialize@String(1,1)
+|:
+	out(0) <- [[[[[string(0)]Replace["\\c",","]]Replace["\\n","\n"]]Replace["\\l","{"]]Replace["\\r","}"]]Replace["\\\\","\\"]
+:|
+
+Serialize@List(1,1)
+|:
+	out(0) <- [["{"]Append[[Map[list(0), ["Serialize"]<String@Worker]]Join[","]]]Append["}"]
+:|
+
+Starts With(2,1)
+|:
+	out(0) <- [[thing(0)]Slice[ [starts with(1)]Length ]] = [starts with(1)]
+:|
+
+Ends With(2,1)
+|:
+	,compare <- [thing(0)]Slice[ [[thing(0)]Length] - [[ends with (1)]Length] ]
+	out(0) <- [compare] = [ends with(1)]
+:|
+
+Unserialize Helper(3,3)
+|:
+	current <- [parts(0)]Index[index(1)]
+	If[[current]Starts With["{"]]
+	|:
+		,first <- [current]Slice[1]
+		list entry, index, bracketnum <- Unserialize Helper[ [parts(0)]Set[index(1), first], index(1), New@List[]]
+		If[[bracketnum] = [0]]
+		|:
+			[parts(0)]Next[index]
+			|:
+				out(0), index(1), bracketnum(2) <- Unserialize Helper[parts(0), ~, [destlist(2)]Append[list entry]]
+			:||:
+				out(0) <- [destlist(2)]Append[list entry]
+				index(1) <- index(1)
+				bracketnum(2) <- 0
+			:|
+		:||:
+			out(0) <- [destlist(2)]Append[list entry]
+			index(1) <- Val[index]
+			bracketnum(2) <- [bracketnum] - [1]
+		:|
+	:||:
+		If[[current]Ends With["}"]]
+		|:
+			parts <- [current]Split["}"]
+			entry <- [parts]Index[0]
+			If[[[entry]Length] = [0]]
+			|:
+				out(0) <- destlist(2)
+			:||:
+				out(0) <- [destlist(2)]Append[ [entry]Unserialize@String ]
+			:|
+			bracketnum(2) <- [[parts]Length] - [2]
+			index(1) <- index(1)
+		:||:
+			[parts(0)]Next[index(1)]
+			|:
+				out(0), index(1), bracketnum(2) <- Unserialize Helper[parts(0), ~, [destlist(2)]Append[[current]Unserialize@String]]
+			:||:
+				out(0) <- [destlist(2)]Append[[current]Unserialize@String]
+				index(1) <- index(1)
+				bracketnum(2) <- 0
+			:|
+		:|
+	:|		
+:|
+
+Generic Unserialize(1,1)
+|:
+	parts <- [serialized(0)]Split[","]
+	[parts]First
+	|:
+		out(0) <- Unserialize Helper[parts, ~, New@List[]]
+	:||:
+		out(0) <- New@List[]
+	:|
+:|
+
+_Object to Dict(4,1)
+|:
+	field <- [field list(1)]Index[index(2)]
+	[object(0)]Get Field[field]
+	|:
+		nextdict <- [dict(3)]Set[field, ~]
+	:||:
+		nextdict <- dict(3)
+	:|
+	[field list(1)]Next[index(2)]
+	|:
+		out(0) <- _Object to Dict[object(0), field list(1), ~, nextdict]
+	:||:
+		out(0) <- Val[nextdict]
+	:|
+:|
+
+Get Pretty Print Value(1,5)
+|:
+	If[[Type Of[value(0)]] = ["List"]]
+	|:
+		value(4) <- value(0)
+		list <- value(0)
+		object <- value(0)
+	:||:
+		If[[Type Of[value(0)]] = ["Dictionary"]]
+		|:
+			value(4) <- value(0)
+			list <- value(0)
+			object <- value(0)
+		:||:
+			If[[Type Of[value(0)]] = ["String"]]
+			|:
+				value(4) <- value(0)
+				print(0) <- value(0)
+				done(3) <- 1
+			:||:
+				If[[Type Of[value(0)]] = ["Whole Number"]]
+				|:
+					value(4) <- value(0)
+					print(0) <- value(0)
+					done(3) <- 1
+				:||:
+					If[[Type Of[value(0)]] = ["Yes No"]]
+					|:
+						value(4) <- value(0)
+						print(0) <- value(0)
+						done(3) <- 1
+					:||:
+						If[[Type Of[value(0)]] = ["Real Number"]]
+						|:
+							value(4) <- value(0)
+							print(0) <- value(0)
+							done(3) <- 1
+						:||:
+							object <- value(0)
+							fieldlist <- [Blueprint Of[value(0)]]Get Fields
+							[fieldlist]First
+							|:
+								list <- _Object to Dict[value(0), fieldlist, ~, New@Dictionary[]]
+								value(4) <- Val[list]
+							:||:
+								value(4) <- value(0)
+								done(3) <- 1
+							:|
+						:|
+					:|
+				:|
+			:|
+			
+		:|
+	:|
+	print(0) <- Type Of[object]
+	index(1) <- [list]First |::|
+	|:
+		print indent(2) <- "{Empty}"
+	:|
+	
+:|
+
+Pretty Print Helper(3,1)
+|:
+	newtabs <- [tabs(1)]Append["    "]
+	print,index,indented,done,value <- Get Pretty Print Value[[list(0)]Index[index(2)]]
+	Print[ [[[tabs(1)]Append[index(2)]]Append[": "]]Append[print] ]
+	|:
+		done <- Pretty Print Helper[value,newtabs ,index]
+		done <- Print[[newtabs]Append[indented]]
+		
+		Val[done]
+		|:
+			[list(0)]Next[index(2)]
+			|:
+				out(0) <- Pretty Print Helper[list(0), tabs(1), ~]
+			:||:
+				out(0) <- 1
+			:|
+		:|
+	:|
+	
+:|
+
+Pretty Print(2,1)
+|:
+	newtabs <- [tabs(1)]Append["    "]
+	,index,indented,,value <- Get Pretty Print Value[toprint(0)]
+	|:
+		Print[[tabs(1)]Append[~]]
+		|:
+			Pretty Print Helper[value,newtabs ,index]
+			Print[[newtabs]Append[indented]]
+		:|
+	:|
+	out(0) <- 1
+:|
+
+As List@String(1,1)
+|:
+	out(0) <- [New@List[]]Append[string(0)]
+:|
+
+As List@List(1,1)
+|:
+	(0) <- (0)
+:|
+
+Check Starts(3,1)
+|:
+	If[ [prev(1)] = [""] ]
+	|:
+		If[ [string(0)]Starts With[el(2)] ]
+		|:
+			out(0) <- el(2)
+		:||:
+			out(0) <- prev(1)
+		:|
+	:||:
+		out(0) <- prev(1)
+	:|
+:|
+
+_Get DString@String(2,4)
+|:
+	If[ [[string(0)]Length] = [0]]
+	|:
+		nomatch(3) <- Yes
+		before delim(1) <- ""
+	:||:
+		match <- Fold[["Check Starts"]Set Input[0, string(0)], "", delims(1)]
+		If[ [match] = [""] ]
+		|:
+			first,rest <- [string(0)]Slice[1]
+			rest(0),before,delim(2),nomatch(3) <- _Get DString@String[rest, delims(1)]
+			before delim(1) <- [first]Append[before]
+		:||:
+			junk,rest(0) <- [string(0)]Slice[ [match]Length ]
+			before delim(1) <- ""
+			delim(2) <- Val[match]
+		:|
+	:|
+:|
+
+//Get DString@String(2,4)
+//|:
+//	delims <- [delim(1)]As List
+//	rest(0), before delim(1), delim(2), nomatch(3) <- _Get DString@String[string(0), delims]
+//:|
+
+Filter Helper(4,1)
+|:
+	filter? <- [
+		[worker(2)]Do[  
+			[New@List[]]Append[ [list(0)]Index[index(1)] ]
+		]
+	]Index[0]
+	If[filter?]
+	|:
+		newlist <- [newlist(3)]Append[[list(0)]Index[index(1)]]
+	:||:
+		newlist <- newlist(3)
+	:|
+	
+	[list(0)]Next[index(1)]
+	|:
+		out(0) <- Filter Helper[list(0), ~, worker(2), newlist]
+	:||:
+		out(0) <- Val[newlist]
+	:|
+:|
+
+Filter(2,1)
+|:
+	[list(0)]First
+	|:
+		out(0) <- Filter Helper[list(0), ~, worker(1), New@List[]]
+	:||:
+		out(0) <- list(0)
+	:|
+:|
+
+Pop@List(1,1)
+|:
+	[list(0)]Last
+	|:
+		out(0) <- [list(0)]Remove[~]
+	:||:
+		out(0) <- list(0)
+	:|
+:|
+
+Peek@List(1,2)
+|:
+	[list(0)]Last
+	|:
+		out(0) <- [list(0)]Index[~]
+	:||:
+		empty(1) <- list(0)
+	:|
+:|
+
+Contains(2,1)
+|:
+	[haystack(0)]Get DString[needle(1)]
+	|:
+		out(0) <- Yes
+	:| |::| |::| |:
+		out(0) <- No
+	:|
+:|
+
+_Find(3,2)
+|:
+	If[[[haystack(0)]Index[index(2)]] = [needle(1)]]
+	|:
+		index(0) <- index(2)
+	:||:
+		[haystack(0)]Next[index(2)]
+		|:
+			index(0),notfound(1) <- _Find[haystack(0),needle(1),~]
+		:||:
+			notfound(1) <- needle(1)
+		:|	
+	:|
+:|
+
+Find(2,2)
+|:
+	[haystack(0)]First
+	|:
+		index(0),not found(1) <- _Find[haystack(0), needle(1), ~]
+	:||:
+		not found(1) <- needle(1)
+	:|
+
+:|
+
+_Tail(3,1)
+|:
+	[list(0)]Next[current(1)]
+	|:
+		out(0) <- _Tail[list(0), ~, [newlist(2)]Append[[list(0)]Index[~]]]
+	:||:
+		out(0) <- newlist(2)
+	:|
+:|
+
+Tail(2,1)
+|:
+	newlist <- [list(0)]New Like
+	[list(0)]Index[start(1)]
+	|:
+		out(0) <- _Tail[list(0), start(1), [newlist]Append[~]]
+	:||:
+		out(0) <- Val[newlist]
+	:|
+:|
+
+_Keys(3,1)
+|:
+	out(0) <- [list(0)]Append[key(2)]
+:|
+
+Keys(1,1)
+|:
+	out(0) <- Fold["_Keys", New@List[], container(0)]
+:|
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fib.rhope	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,30 @@
+/*
+	This example program contains a naive implementation of the Fibonacci function
+	While this isn't a particular fast way to implement the Fibonacci function it does parallize nicely
+*/
+
+
+//Here we define a worker Fib with one input named 'n' and one output named 'out'
+Fib[n:out]
+{
+	//The If worker is one way to conditionally execute a piece of code
+	If[[n] < [2]]
+	{
+		//This line will execute if [n] < [2] evaluates to Yes
+		out <- 1	
+	}{
+		//This line will execute if [n] < [2] evaluates to No
+		//All Worker calls can be expressed in infix, postfix, or prefix notation
+		//So [n]-[1] is the same as -[n,1] and [n,1]-
+		out <- [Fib[[n]-[1]]] + [Fib[[n]-[2]]]
+	}
+}
+
+Main[args]
+{
+	//Here we get the first command line argument and convert it to a number
+	//Yes I realize this is incredibly ugly looking
+	n <- <String@Whole Number[[args]Index[1]]
+	//Call our Fib worker and Print the result to the terminal
+	Print[Fib[n]]
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/file.c	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,543 @@
+#include "structs.h"
+#include "datum.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int vis_file_from_string(datum ** inputlist, queue_entry * worker_entry)
+{
+	datum * output;
+	file_data * file;
+	output = new_datum(BUILTIN_TYPE_FILE, 1, sizeof(file_data), worker_entry->instance->def->program);
+	file = output->c.generic.data;
+	file->shared = malloc(sizeof(shared_file) + inputlist[0]->c.generic.len-1);
+	strcpy(file->shared->name, inputlist[0]->c.generic.data);
+	DEBUGPRINTF("File from string name: %s\n", file->shared->name);
+	release_ref(inputlist[0]);
+	file->shared->status = FILE_NOSIZE;
+	VIS_InitializeCriticalSection(file->shared->lock);
+	file->shared->ref_count = 1;
+	file->offset = 0;
+	inputlist[0] = output;
+	return 0;
+}
+
+void vis_file_read_open_check(file_data * file)
+{
+	switch(file->shared->status)
+	{
+		case FILE_NOSIZE:
+		case FILE_CLOSED:
+			DEBUGPUTS("File is closed, opening...\n");
+			DEBUGPRINTF("File name: %s\n", file->shared->name);
+			file->shared->file = fopen(file->shared->name, "rb");
+			if(!file->shared->file)
+			{
+				file->shared->status = FILE_CANT_OPEN;
+				file->shared->size = 0;
+				break;
+			}
+			if(file->shared->status == FILE_NOSIZE)
+			{
+				DEBUGPUTS("Getting file size.\n");
+				fseek(file->shared->file, 0, SEEK_END);
+				file->shared->size = ftell(file->shared->file);
+				DEBUGPRINTF("File size: %d.\n", file->shared->size);
+			}
+				
+			file->shared->status = FILE_READ;
+			break;
+		default://file is already open
+			break;
+	}
+	DEBUGPRINTF("Seeking to %d\n", file->offset);
+	if(file->shared->file)
+		fseek(file->shared->file, file->offset, SEEK_SET);
+	DEBUGPUTS("Done.\n");
+}
+
+int vis_file_get_fstring(datum ** inputlist, queue_entry * worker_entry)
+{
+	file_data * file;
+	datum * output = new_datum(BUILTIN_TYPE_STRING, 1, inputlist[1]->c.integers.num_a+1, worker_entry->instance->def->program);
+	inputlist[0] = copy_datum(inputlist[0], 0);
+	if(inputlist[1]->c.integers.num_a > 0)
+	{
+		file = (file_data *)inputlist[0]->c.generic.data;
+		VIS_EnterCriticalSection(file->shared->lock);
+			vis_file_read_open_check(file);
+			fread(output->c.generic.data,1,inputlist[1]->c.integers.num_a, file->shared->file);
+		VIS_LeaveCriticalSection(file->shared->lock);
+		file->offset += inputlist[1]->c.integers.num_a;
+	}
+	((char *)output->c.generic.data)[inputlist[1]->c.integers.num_a] = '\0';
+	release_ref(inputlist[1]);
+	inputlist[1] = output;
+	return 0;
+}
+#define	FILE_SEARCH_BUFFER_SIZE	512
+
+typedef struct bufferlist
+{
+	char buffer[FILE_SEARCH_BUFFER_SIZE];
+	int index;
+	struct bufferlist * next;
+} bufferlist;
+
+int vis_file_get_dstring(datum ** inputlist, queue_entry * worker_entry)
+{
+	BOOL found = FALSE;
+	bufferlist buffers;
+	bufferlist * current, *temp,*temp2;
+	int i,j,k,startk;
+	int found_entry;
+	int string_offset;
+	int search_offset;
+	bufferlist * search_start;
+	int search_start_offset;
+	int *search_offsets;
+	bufferlist ** search_starts;
+	int *search_start_offsets;
+	int read_bytes;
+	
+	list_data * list;
+	file_data * file;
+	
+	inputlist[0] = copy_datum(inputlist[0], 0);
+	file = (file_data *)inputlist[0]->c.generic.data;
+	buffers.next = NULL;
+	DEBUGPUTS("Entering critical section.\n");
+	VIS_EnterCriticalSection(file->shared->lock);
+		if(file->offset >= file->shared->size)
+		{
+	VIS_LeaveCriticalSection(file->shared->lock);
+			release_ref(inputlist[0]);
+			release_ref(inputlist[1]);
+			inputlist[0] = inputlist[1] = inputlist[2] = NULL;
+			inputlist[3] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, worker_entry->instance->def->program);
+			datum_set_yesno(inputlist[3], 1);
+			return 0;
+		}
+		if(inputlist[1]->company->type_id == BUILTIN_TYPE_LIST)
+		{
+			
+			list = ((list_data *)inputlist[1]->c.generic.data);
+			DEBUGPRINTF("Delimeter input is a list with %d entries.\n", list->num_entries);
+			search_offsets = malloc(sizeof(int) * (list->num_entries));
+			DEBUGPRINTF("Allocated %d bytes.\n", sizeof(int) * (list->num_entries));
+			search_starts = malloc(sizeof(bufferlist *) * (list->num_entries));
+			DEBUGPRINTF("Allocated %d bytes.\n", sizeof(bufferlist *) * (list->num_entries));
+			search_start_offsets = malloc(sizeof(int) * (list->num_entries));
+			DEBUGPRINTF("Allocated %d bytes.\n", sizeof(int) * (list->num_entries));
+			for(i = 0; i < list->num_entries; ++i)
+			{
+				DEBUGPRINTF("Setting search_offsets[%d] = 0.\n", i);
+				search_offsets[i] = 0;
+			}
+		}
+		search_offset = 0;
+		current = &buffers;
+		current->index = 0;
+	
+		DEBUGPUTS("In critical section.\n");
+		vis_file_read_open_check(file);
+		DEBUGPUTS("File open.");
+		while(!found && !feof(file->shared->file))
+		{
+			DEBUGPRINTF("Reading %d bytes from file\n", FILE_SEARCH_BUFFER_SIZE);
+			read_bytes = fread(current->buffer, 1, FILE_SEARCH_BUFFER_SIZE, file->shared->file);
+			DEBUGPRINTF("fread read %d bytes\n", read_bytes);
+			for(i = 0; i < read_bytes && !found; ++i)
+			{
+				DEBUGPRINTF("Checking character #%d (%c)\n", i, current->buffer[i]);
+				switch(inputlist[1]->company->type_id)
+				{
+				case BUILTIN_TYPE_WHOLE:
+					if((int)current->buffer[i] == inputlist[1]->c.integers.num_a)
+					{
+						found = TRUE;
+						search_offset = 1;
+						search_start = current;
+						search_start_offset = i;
+					}
+					break;
+				case BUILTIN_TYPE_STRING:
+					if(current->buffer[i] == ((char *)inputlist[1]->c.generic.data)[search_offset])
+					{
+						if(search_offset == 0)
+						{
+							search_start = current;
+							search_start_offset = i;
+						}
+						++search_offset;
+						if(search_offset == (inputlist[1]->c.generic.len-1))
+							found = TRUE;
+					}
+					else
+					{
+						if(search_offset > 0)
+						{
+							current = search_start;
+							i = search_start_offset;
+						}
+						search_offset = 0;
+					}
+					break;
+				case BUILTIN_TYPE_LIST:
+					for(j = 0; j < list->num_entries; ++j)
+					{
+						DEBUGPRINTF("Testing list entry %d against character %d in buffer %d\n", j, i, current->index);
+						if(list->entries[j]->company->type_id == BUILTIN_TYPE_WHOLE && (int)current->buffer[i] == list->entries[j]->c.integers.num_a)
+						{
+							DEBUGPUTS("Matched whole number entry.\n");
+							found = TRUE;
+							found_entry = j;
+							search_offset = 1;
+							search_start = current;
+							search_start_offset = i;
+							break;
+						}
+						else if(list->entries[j]->company->type_id == BUILTIN_TYPE_STRING)
+						{
+							DEBUGPUTS("String entry.\n");
+							if(current->buffer[i] == ((char *)list->entries[j]->c.generic.data)[search_offsets[j]])
+							{
+								DEBUGPRINTF("%c in buffer matches character #%d in entry.\n", current->buffer[i], search_offsets[j]);
+								if(search_offsets[j] == 0)
+								{
+									search_starts[j] = current;
+									search_start_offsets[j] = i;
+								}
+								++search_offsets[j];
+								if(search_offsets[j] == (list->entries[j]->c.generic.len-1))
+								{
+									DEBUGPUTS("Entire string matched.\n");
+									found = TRUE;
+									found_entry = j;
+									search_offset = search_offsets[j];
+									search_start = search_starts[j];
+									search_start_offset = search_start_offsets[j];
+									break;
+								}
+							}
+							else if(search_offsets[j] > 0)
+							{
+								DEBUGPRINTF("%c in bufer does not match character #%d in entry.\n", current->buffer[i], search_offsets[j]);
+								temp = search_starts[j];
+								search_offsets[j] = 0;
+								startk = search_start_offsets[j];
+								while(temp && !found)
+								{
+									DEBUGPRINTF("Scanning block %d for possible missed match from %d to %d.\n", temp->index, startk, (temp == current ? i : FILE_SEARCH_BUFFER_SIZE)-1);
+									for(k = startk; k < (temp == current ? i : FILE_SEARCH_BUFFER_SIZE); ++k)
+									{
+										if(temp->buffer[k] == ((char *)list->entries[j]->c.generic.data)[search_offsets[j]])
+										{
+											if(!search_offsets[j])
+											{
+												search_starts[j] = temp;
+												search_start_offsets[j] = k;
+											}
+											++search_offsets[j];
+											if(search_offset == (list->entries[j]->c.generic.len-1))
+											{
+												found = TRUE;
+												found_entry = j;
+												search_start = search_starts[j];
+												search_start_offset = search_start_offsets[j];
+											}
+										}
+										else
+										{
+											if(search_offsets[j] > 0)
+											{
+												temp = search_starts[j];
+												k = search_start_offsets[j];
+											}
+											search_offsets[j] = 0;
+										}
+									}
+									startk = 0;
+									temp = temp->next;
+								}
+								
+							}
+							else
+								search_offsets[j] = 0;
+							
+						}
+					}
+					break;
+				}
+			}
+			if(!found && !feof(file->shared->file))
+			{
+				current->next = malloc(sizeof(bufferlist));
+				DEBUGPRINTF("Allocated next buffer at %X (%d bytes)\n", current->next, sizeof(bufferlist));
+				current->next->index = current->index+1;
+				current->next->next = NULL;
+				current = current->next;
+			}
+		}
+	VIS_LeaveCriticalSection(file->shared->lock);
+	if(inputlist[1]->company->type_id == BUILTIN_TYPE_LIST)
+	{
+		VIS_FREE(search_offsets, "Get DString@File, search offsets");
+		VIS_FREE(search_starts, "Get DString@File, search starts");
+		VIS_FREE(search_start_offsets, "Get DString@File, search start offsets");
+	}
+	if(found)
+	{
+		DEBUGPUTS("Found a delimeter");
+		if(inputlist[1]->company->type_id == BUILTIN_TYPE_LIST)
+		{
+			inputlist[2] = add_ref(list->entries[found_entry]);
+			release_ref(inputlist[1]);
+		}
+		else
+			inputlist[2] = inputlist[1];
+		inputlist[3] = NULL;
+	}
+	else
+	{
+		DEBUGPUTS("Didn't find a delimeter");
+		release_ref(inputlist[1]);
+		inputlist[2] = NULL;
+		inputlist[3] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, worker_entry->instance->def->program);
+		datum_set_yesno(inputlist[3], 0);
+	}
+	//Does this need to be here still or was it just working around another bug?
+	if(search_start_offset < 0)
+		search_start_offset = 0;
+	if(!found) {
+		search_start = current;
+		search_start_offset = i;
+	}
+	if(found)
+	{
+		inputlist[1] = new_datum(BUILTIN_TYPE_STRING, 1, FILE_SEARCH_BUFFER_SIZE * current->index + search_start_offset+1, worker_entry->instance->def->program);
+		//file->offset += FILE_SEARCH_BUFFER_SIZE * current->index + search_start_offset + search_offset;
+		file->offset += FILE_SEARCH_BUFFER_SIZE * search_start->index + search_start_offset + search_offset;
+	}
+	else
+	{
+		inputlist[1] = new_datum(BUILTIN_TYPE_STRING, 1, FILE_SEARCH_BUFFER_SIZE * current->index + read_bytes+1, worker_entry->instance->def->program);
+		file->offset += FILE_SEARCH_BUFFER_SIZE * current->index + read_bytes;
+	}
+	temp = &buffers;
+	string_offset = 0;
+	while(temp)
+	{
+		DEBUGPRINTF("Copying from index %d to offset %X\n", temp->index, string_offset);
+		if(temp == search_start)
+		{
+			//if(found)
+			//{
+				temp->buffer[search_start_offset] = '\0';
+				memcpy(((char *)inputlist[1]->c.generic.data)+string_offset, temp->buffer, search_start_offset);
+				string_offset += search_start_offset;
+			/*}
+			else
+			{
+				memcpy(((char *)inputlist[1]->c.generic.data)+string_offset, temp->buffer, i);
+				string_offset += i;
+			}*/
+			break;
+		}
+		else
+		{
+			memcpy(((char *)inputlist[1]->c.generic.data)+string_offset, temp->buffer, FILE_SEARCH_BUFFER_SIZE);
+			string_offset += FILE_SEARCH_BUFFER_SIZE;
+		}
+		if(temp != &buffers)
+		{
+			temp2 = temp->next;
+			VIS_FREE(temp, "Get DString@File, buffer node");
+			temp = temp2;
+		}
+		else
+			temp = temp->next;
+	}
+	while(temp)
+	{
+		if(temp != &buffers)
+		{
+			temp2 = temp->next;
+			DEBUGPRINTF("Freeing %X\n", temp);
+			VIS_FREE(temp, "Get DString@File, buffer node");
+			temp = temp2;
+		}
+		else
+			temp = temp->next;
+	}
+	((char *)inputlist[1]->c.generic.data)[string_offset] = '\0';
+	DEBUGPRINTF("Output string: %s\n", inputlist[1]->c.generic.data);
+	return 0;
+}
+
+int vis_file_get_byte(datum ** inputlist, queue_entry * worker_entry)
+{
+	file_data * file;
+	BOOL eof;
+	char num;
+	
+	inputlist[0] = copy_datum(inputlist[0], 0);
+	file = (file_data *)inputlist[0]->c.generic.data;
+	VIS_EnterCriticalSection(file->shared->lock);
+		if(!(eof = (file->offset >= file->shared->size)))
+		{
+			vis_file_read_open_check(file);
+			fread(&num,sizeof(char),1, file->shared->file);
+		}
+	VIS_LeaveCriticalSection(file->shared->lock);
+	if(eof)
+	{
+		release_ref(inputlist[0]);
+		inputlist[0] = inputlist[1] = NULL;
+		inputlist[2] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, worker_entry->instance->def->program);
+		datum_set_yesno(inputlist[2], 1);
+	}
+	else
+	{
+		inputlist[1] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program);
+		inputlist[1]->c.integers.num_a = num;
+		inputlist[2] = NULL;
+		file->offset += sizeof(char);
+	}
+	return 0;
+}
+
+int vis_file_get_word(datum ** inputlist, queue_entry * worker_entry)
+{
+	file_data * file;
+	BOOL eof;
+	short num;
+
+	inputlist[0] = copy_datum(inputlist[0], 0);
+	file = (file_data *)inputlist[0]->c.generic.data;
+	VIS_EnterCriticalSection(file->shared->lock);
+		if(!(eof = (file->offset >= file->shared->size)))
+		{
+			vis_file_read_open_check(file);
+			fread(&num,sizeof(short),1, file->shared->file);
+		}
+	VIS_LeaveCriticalSection(file->shared->lock);
+	if(eof)
+	{
+		release_ref(inputlist[0]);
+		inputlist[0] = inputlist[1] = NULL;
+		inputlist[2] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, worker_entry->instance->def->program);
+		datum_set_yesno(inputlist[2], 1);
+	}
+	else
+	{
+		inputlist[1] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program);
+		inputlist[1]->c.integers.num_a = num;
+		inputlist[2] = NULL;
+		file->offset += sizeof(short);
+	}
+	return 0;
+}
+
+int vis_file_get_long(datum ** inputlist, queue_entry * worker_entry)
+{
+	file_data * file;
+	BOOL eof;
+	long num;
+	
+	inputlist[0] = copy_datum(inputlist[0], 0);
+	file = (file_data *)inputlist[0]->c.generic.data;
+	VIS_EnterCriticalSection(file->shared->lock);
+		if(!(eof = (file->offset >= file->shared->size)))
+		{
+			vis_file_read_open_check(file);
+			fread(&num,sizeof(long),1, file->shared->file);
+		}
+	VIS_LeaveCriticalSection(file->shared->lock);
+	if(eof)
+	{
+		release_ref(inputlist[0]);
+		inputlist[0] = inputlist[1] = NULL;
+		inputlist[2] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, worker_entry->instance->def->program);
+		datum_set_yesno(inputlist[2], 1);
+	}
+	else
+	{
+		inputlist[1] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program);
+		inputlist[1]->c.integers.num_a = num;
+		inputlist[2] = NULL;
+		file->offset += sizeof(long);
+	}
+	return 0;
+}
+
+void vis_file_write_open_check(file_data * file)
+{
+	switch(file->shared->status)
+	{
+		case FILE_READ:
+			fclose(file->shared->file);
+		case FILE_NOSIZE:
+		case FILE_CLOSED:
+			DEBUGPUTS("File is closed, opening...\n");
+			DEBUGPRINTF("File name: %s\n", file->shared->name);
+			file->shared->file = fopen(file->shared->name, "r+b");
+			if(!file->shared->file)
+				file->shared->file = fopen(file->shared->name,"w+b");
+			if(!file->shared->file)
+			{
+				file->shared->status = FILE_CANT_OPEN;
+				file->shared->size = 0;
+				break;
+			}
+			if(file->shared->status == FILE_NOSIZE)
+			{
+				DEBUGPUTS("Getting file size.\n");
+				fseek(file->shared->file, 0, SEEK_END);
+				file->shared->size = ftell(file->shared->file);
+				DEBUGPRINTF("File size: %d.\n", file->shared->size);
+			}
+				
+			file->shared->status = FILE_WRITE;
+			break;
+		default://file is already open
+			break;
+	}
+	DEBUGPRINTF("Seeking to %d\n", file->offset);
+	if(file->shared->file)
+		fseek(file->shared->file, file->offset, SEEK_SET);
+	DEBUGPUTS("Done.\n");
+}
+
+int vis_file_put_string(datum ** inputlist, queue_entry * worker_entry)
+{
+	file_data * file;
+	int written;
+	inputlist[0] = copy_datum(inputlist[0], 0);
+	file = ((file_data *)inputlist[0]->c.generic.data);
+	VIS_EnterCriticalSection(file->shared->lock);
+		vis_file_write_open_check(file);
+		written = fwrite(inputlist[1]->c.generic.data,1,inputlist[1]->c.generic.len-1,file->shared->file);
+		file->offset += written;
+		if(file->offset > file->shared->size)
+			file->shared->size = file->offset;
+	VIS_LeaveCriticalSection(file->shared->lock);
+	release_ref(inputlist[1]);
+	return 0;
+}
+
+int vis_file_length(datum ** inputlist, queue_entry * worker_entry)
+{
+	file_data * file;
+	int written;
+	int size;
+	file = ((file_data *)inputlist[0]->c.generic.data);
+	VIS_EnterCriticalSection(file->shared->lock);
+		vis_file_read_open_check(file);
+		size = file->shared->size;
+	VIS_LeaveCriticalSection(file->shared->lock);
+	release_ref(inputlist[0]);
+	inputlist[0] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program);
+	inputlist[0]->c.integers.num_a = size;
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/framework.rhope	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,750 @@
+Import webserver.rhope
+
+Framework Handler[con,path,request type,queryvars,headers,handler,title,use session]
+{
+	page <- New@Page[title, path, use session, queryvars, headers]
+	out list <- [handler]Do[ [[New@List[]]Append[page]]Append[path] ]
+	handler page <- [out list]Index[0]
+	If[[request type] = ["POST"]]
+	{
+		final page <- Process POST[handler page, con, headers]
+	}{
+		final page <- Val[handler page]
+	}
+	string,out headers <- [final page]Render
+	
+	[HTTP OK[con, Get Content Type[".html"], [string]Length, out headers]
+	]Put String[string]
+}
+
+Handler Fixer[handler:out]
+{
+	If[[Type Of[handler]] = ["List"]]
+	{
+		out <- [[["Framework Handler"]Set Input[5, [handler]Index[0]]]Set Input[6, [handler]Index[1]]]Set Input[7, [handler]Index[2]]
+	}{
+		out <- handler
+	}
+}
+
+Start Web[handlers]
+{
+	Print["Starting Rhope Web Server"]
+	Init Sessions[]
+	{ Listen on Port[80,["Connection Start"]Set Input[1, Map[handlers,"Handler Fixer"]]] }
+	Wait Forever[]
+}
+
+Get Class[container:class]
+{
+	If[[[[container]Class >>]Length] > [0]]
+	{
+		class <- [[" class=\""]Append[[container]Class >>]]Append["\""]
+	}{
+		class <- ""
+	}
+}
+
+Blueprint Web Event
+{
+	Event Name
+	Origin
+	Data
+}
+
+New@Web Event[name,origin,data:out]
+{
+	out <- [[[Build["Web Event"]]Event Name <<[name]]Origin <<[origin]]Data <<[data]	
+}
+
+Blueprint Web Container
+{
+	Tag Name
+	Class
+	Propagate Events
+	Children
+	Handlers
+	Named Children
+	Session
+	Use Session
+}
+
+New@Web Container[class:out]
+{
+	out <- [[[[[[[Build["Web Container"]
+	]Tag Name <<["div"]
+	]Class <<[class]
+	]Propagate Events <<[No]
+	]Children <<[New@List[]]
+	]Named Children <<[New@Dictionary[]]
+	]Handlers <<[New@Dictionary[]]
+	]Use Session <<[No]
+}
+
+Name@Web Container[cont:out,none]
+{
+	none <- cont
+}
+	
+Render Child[start,container:out]
+{
+	out <- [start]Append[[container]Render]
+}
+
+Set Session@Web Container[container,session:out]
+{
+	out <- [
+				[
+					[container]Use Session <<[Yes]
+				]Session <<[session]
+			]Children <<[ Map[ [container]Children >>, ["Set Session"]Set Input[1, session] ] ]
+}
+
+Set Handler@Web Container[container,event name,handler:out]
+{
+	out <- [container]Handlers <<[ [[container]Handlers >>	]Set[event name, handler] ]
+}
+
+Render@Web Container[container:out,headers]
+{
+	out <- [[[[[[["<"]Append[ [container]Tag Name >> ]
+		]Append[Get Class[container]]
+		]Append[">\n\t"]
+		]Append[Fold[["Render Child"]<String@Worker, "", [container]Children >>]]
+		]Append["\n</"]
+		]Append[ [container]Tag Name >> ]
+		]Append[">\n"]
+}
+
+Container Event Handler[container,events,index:cont,out events]
+{
+	event <- [events]Index[index]
+	[[container]Handlers >>]Index[ [event]Event Name >>]
+	{
+		result list <- [~]Do[
+				[[New@List[]]Append[container]]Append[event]
+		]
+		new container <- [result list]Index[0]
+		[result list]Index[1]
+		{
+			out events <- [result events]Append[~]
+		}{
+			out events <- Val[result events]
+		}
+	}{
+		new container <- container
+		out events <- Val[result events]
+	}
+	
+	[events]Next[index]
+	{
+		cont, result events <- Container Event Handler[new container, events, ~]
+	}{
+		cont <- Val[new container]
+		result events <- New@List[]
+	}
+}
+
+Container Postback Helper[container,post data,index,events:out,out events]
+{
+	,current events <- [[[container]Children >>]Index[index]]Postback[post data]
+	{
+		new container <- [container]Children <<[[[container]Children >>]Set[index, ~]]
+	}
+	combined events <- Concatenate[events, current events]
+	[[new container]Children >>]Next[index]
+	{
+		out, out events <- Container Postback Helper[new container, post data, ~, combined events]
+	}{
+		[combined events]First
+		{
+			out, newevents <- Container Event Handler[new container, combined events, ~]
+			out events <- Concatenate[combined events, newevents]
+		}{
+			out <- Val[new container]
+			out events <- Val[combined events]
+		}
+	}
+}
+
+Postback@Web Container[container,post data:out,events]
+{
+	[[container]Children >>]First
+	{
+		out, postback events <- Container Postback Helper[container, post data, ~, New@List[]]
+		If[[container]Propagate Events >>]
+		{
+			events <- Val[postback events]
+		}{
+			events <- New@List[]
+		}
+	}{
+		out <- container
+		events <- New@List[]
+	}
+}
+	
+Add Child[cont,child:out]
+{
+	If[[cont]Use Session >>]
+	{
+		prepped child <- [child]Set Session[[cont]Session >>]
+	}{
+		prepped child <- Val[child]
+	}
+	with child <- [cont]Children <<[ [[cont]Children >>]Append[prepped child] ]
+	
+	[prepped child]Name
+	{
+		out <- [with child]Named Children <<[ [[with child]Named Children >>]Set[~, [[[with child]Children >>]Length] - [1]] ]
+	}{
+		out <- Val[with child]
+	}
+}
+
+Get Child By Name[container,name:out,not found]
+{
+	,not found <- [[container]Named Children >>]Index[name]
+	{
+		out <- [[container]Children >>]Index[~]
+	}
+}
+	
+Blueprint Page
+{
+	Title
+	URL
+	CSS
+	Children
+	Named Children
+	Handlers
+	Use Session
+	Session
+	Session ID
+}
+
+Set Handler@Page[container,event name,handler:out]
+{
+	out <- [container]Handlers <<[ [[container]Handlers >>	]Set[event name, handler] ]
+}
+	
+New@Page[title,url,use session,queryvars,headers:out]
+{
+	page <- [[[[[[[Build["Page"]
+	]Title <<[title]
+	]URL <<[url]
+	]CSS <<[[New@List[]]Append["/default.css"]]
+	]Children <<[New@List[]]
+	]Named Children <<[New@Dictionary[]]
+	]Handlers <<[New@Dictionary[]]
+	]Use Session <<[use session]
+
+	If[use session]
+	{
+		Load@Session[queryvars, headers]
+		{
+			out <- [[page]Session <<[~]]Session ID <<[ [~]Session ID>>]
+		}
+	}{
+		out <- Val[page]
+	}
+}
+
+Get Action@Page[page:out]
+{
+	If[[page]Use Session>>]
+	{	
+		[[page]Session >>]Get Link Params
+		{
+			out <- [[[page]URL >>]Append["?"]]Append[~]
+		}{
+			out <- [page]URL >>
+		}
+	}{
+		out <- [page]URL >>
+	}
+}
+	
+Render@Page[page:out,headers]
+{
+	out <- [[[[[[["<html>\n\t<head>\n\t\t<title>"]Append[[page]Title >>]
+		]Append["</title>\n\t\t<link rel=\"stylesheet\" href=\""]
+		]Append[[[page]CSS >>]Join["\">\n\t\t<link rel=\"stylesheet\" href=\""]]
+		]Append["\">\n\t</head>\n\t<body>\n\t<form method=\"POST\" action=\""]
+		]Append[[[page]Get Action]Append["\">\n"]]
+		]Append[Fold[["Render Child"]<String@Worker, "", [page]Children >>]]
+		]Append["\t</form>\n\t</body>\n</html>"]
+	If[[page]Use Session>>]
+	{
+		headers <- [[page]Session >>]Finalize[New@Dictionary[]]
+	}{
+		headers <- New@Dictionary[]
+	}
+}
+
+Clear Children[page:out]
+{
+	out <- [[page]Children <<[New@List[]]]Named Children <<[New@Dictionary[]]
+}
+
+Set@Page[page,key,val:out]
+{
+	out <- [page]Session <<[ [[page]Session >>]Set[key, val] ]
+}
+
+Index@Page[page,key:out,not found]
+{
+	out,not found <- [[page]Session >>]Index[key]
+}
+
+First@Page[page:first,not found]
+{
+	first,not found <- [[page]Session >>]First
+}
+
+Next@Page[page,last:next,not found]
+{
+	next,not found <- [[page]Session >>]Next[last]	
+}
+
+Add CSS@Page[page,css:out]
+{
+	out <- [page]CSS <<[ [[page]CSS >>]Append[css] ]
+}
+
+Clear CSS@Page[page:out]
+{
+	out <- [page]CSS <<[New@List[]]	
+}
+
+Decode Helper Decode[list,destlist,index:out]
+{
+	code,rest <- [[list]Index[index]]Slice[2]
+	newlist <- [destlist]Set[index, [[""]Put Byte[From Hex@Whole Number[code]]]Append[rest]]
+	[list]Next[index]
+	{
+		out <- Decode Helper Straight[list, newlist, ~]
+	}{
+		out <- Val[newlist]
+	}
+}
+
+Decode Helper Straight[list,destlist,index:out]
+{
+	newlist <- [destlist]Set[index, [list]Index[index]]
+	[list]Next[index]
+	{
+		out <- Decode Helper Decode[list, newlist, ~]
+	}{
+		out <- Val[newlist]
+	}
+}
+
+URL Decode[val:out]
+{
+	parts <- [val]Split["%"]
+	[parts]First
+	{
+		out <- [Decode Helper Straight[parts, New@List[], ~]]Join[""]
+	}{
+		out <- val
+	}
+}
+
+URL Encode Path[string:out]
+{
+	out <- [[[[string]Replace["%","%25"]]Replace[" ","%20"]]Replace["/","%2F"]]Replace["?","%3F"]
+}
+
+Decode Pair[val,key:oval,okey]
+{
+	oval <- URL Decode[val]
+	okey <- URL Decode[key]
+}
+
+Process POST[page,con,headers:out]
+{
+	[con]Get FString[[headers]Index["Content-Length"]] {}
+	{
+		post string <- [~]Replace["+"," "]
+	}
+	post data <- Key Value Map[Dict Split[post string, "=", "&"], ["Decode Pair"]<String@Worker]
+	out <- [page]Postback[post data]
+}
+
+Postback@Page[page,post data:out,events]
+{
+	[[page]Children >>]First
+	{
+		out, events <- Container Postback Helper[page, post data, ~, New@List[]]
+	}{
+		out <- page
+	}
+	events <- New@List[]
+}
+	
+Blueprint Web Text
+{
+	Text
+	Enclosing Tag
+}
+	
+New@Web Text[text,tag:out]
+{
+	out <- [[Build["Web Text"]]Text <<[text]]Enclosing Tag <<[tag]
+}
+
+Name@Web Text[text:out,none]
+{
+	none <- text
+}
+
+Escape HTML Text[string:out]
+{
+	out <- [[[string]Replace["&","&amp;"]]Replace["<", "&lt;"]]Replace[">", "&gt;"]
+}
+	
+Render@Web Text[text:out,headers]
+{
+	processed text <- [Escape HTML Text[[text]Text >>]]Replace["\n","<br>\n\t"]
+	If[[[[text]Enclosing Tag >>]Length] = [0]]
+	{
+		out <- Val[processed text]
+	}{
+		out <- [[[["<"]Append[[text]Enclosing Tag >>]]Append[">"]]Append[processed text]]Append[[["</"]Append[[text]Enclosing Tag >>]]Append[">"]]
+	}
+}
+
+Postback@Web Text[text,post data:out,events]
+{
+	out <- text
+	events <- New@List[]
+}
+
+Set Session@Web Text[text,session:out]
+{
+	out <- session
+}
+
+Render@String[string:out,headers]
+{
+	out <- [New@Web Text[string,""]]Render	
+}
+
+Name@String[string:out,none]
+{
+	none <- string
+}
+
+Postback@String[in,post data:out,events]
+{
+ 	out <- in
+ 	events <- New@List[]
+}
+
+Set Session@String[in,session:out]
+{
+	out <- in
+}
+
+Blueprint Web Field
+{
+	Name
+	Value
+	Type
+	Class
+}
+
+Name@Web Field[field:name,none]
+{
+	name <- [field]Name >>	
+}
+
+New@Web Field[name,value,type:out]
+{
+	out <- [[[[Build["Web Field"]]Name <<[name]]Value <<[value]]Type <<[type]]Class <<[""]
+}
+
+Set Session@Web Field[in,session:out]
+{
+	out <- in
+}
+
+Render@Web Field[field:out,headers]
+{
+	If[[[field]Type >>] = ["multiline"]]
+	{
+		out <- [[[[[["<textarea name=\""]Append[[field]Name >>]]Append["\""]]Append[Get Class[field]]]Append[">"]]Append[[field]Value >>]]Append["</textarea>"]
+	}{
+		out <- [[[[[[[["<input type=\""]Append[[field]Type >>]]Append["\" name=\""]]Append[[field]Name >>]]Append["\""]]Append[Get Class[field]]]Append[" value=\""]]Append[[field]Value >>]]Append["\">"]
+	}
+	
+}
+
+Postback@Web Field[field,post data:out,event]
+{
+	[post data]Index[[field]Name >>]
+	{
+		out <- [field]Value <<[~]
+
+		If[[[field]Value >>] = [~]] 
+		{
+			event <- New@List[]
+		}{
+			event <- [New@List[]]Append[ New@Web Event["change", [field]Name >>, [field]Value >>] ]
+		}
+	}{
+		out <- field
+		event <- New@List[]
+	}
+}
+
+Blueprint Web Button
+{
+	Name
+	Label
+	Class
+}
+
+New@Web Button[name,label:out]
+{
+	out <- [[[Build["Web Button"]]Name <<[name]]Label <<[label]]Class <<[""]	
+}
+
+Name@Web Button[button:name,none]
+{
+	name <- [button]Name >>
+}
+
+Set Session@Web Button[in,session:out]
+{
+	out <- in
+}
+
+Postback@Web Button[button,post data:out,events]
+{
+	out <- button
+	[post data]Index[[button]Name >>]
+	{
+		events <- [New@List[]]Append[ New@Web Event["click", [button]Name >>, 0] ]
+	}{
+		events <- New@List[]
+	}
+}
+
+Render@Web Button[button:out,headers]
+{
+	out <- [[[[[["<input type=\"submit\" name=\""]Append[[button]Name >>]]Append["\""]]Append[Get Class[button]]]Append[" value=\""]]Append[[button]Label >>]]Append["\">"]
+}
+
+Blueprint Session
+{
+	Session ID
+	IP Address
+	Use Cookies
+	Data
+}
+
+Get Unique ID[:out] uses Session
+{
+	out <- [[[::ID]<Whole Number@String]Append["_"]]Append[Random[]]
+	::ID <- [::ID]+[1]
+}
+
+New@Session[:out]
+{
+	out <- [[[Build["Session"]]Session ID <<[Get Unique ID[]]]Use Cookies <<[No]]Data <<[New@Dictionary[]]
+}
+
+Load@Session[queryvars,headers:out] uses Session
+{
+	,checkquery <- [headers]Index["Cookie"]
+	{
+		parts <- Dict Split[~, "=", "; "]
+		,checkquery <- [parts]Index["session_id"]
+		{
+			,checkquery <- [::Sessions]Index[~]
+			{
+				out <- [~]Use Cookies <<[Yes]
+			}
+		}
+	}
+	
+	
+	Val[checkquery]
+	{
+		,makenew <- [queryvars]Index["session_id"]
+		{
+			out, makenew <- [::Sessions]Index[~]
+		}
+	}
+	
+	Val[makenew]
+	{
+		out <- New@Session[]
+	}
+}
+
+Get Link Params@Session[session:out,no params]
+{
+	If[[session]Use Cookies >>]
+	{
+		no params <- No
+	}{
+		out <- ["session_id="]Append[[session]Session ID >>]
+	}
+}
+
+Set@Session[session,key,val:out]
+{
+	out <- [session]Data <<[ [[session]Data >>]Set[key, val] ]
+}
+
+Index@Session[session,key:out,not found]
+{
+	out,not found <- [[session]Data >>]Index[key]
+}
+
+First@Session[session:first,not found]
+{
+	first,not found <- [[session]Data >>]First
+}
+
+Next@Session[session,last:next,not found]
+{
+	next,not found <- [[session]Data >>]Next[last]	
+}
+
+Init Sessions[:out] uses Session
+{
+	::ID <- 1
+	::Sessions <- New@Dictionary[]
+	out <- 0
+}
+
+Finalize@Session[session,headers:out headers] uses Session
+{
+	::Sessions <- [::Sessions]Set[[session]Session ID >>, session]
+	out headers <- [headers]Set["Set-Cookie", ["session_id="]Append[[session]Session ID >>]]
+}
+
+Blueprint Web Link
+{
+	Text
+	Target
+	Class
+	Query Params
+}
+
+New@Web Link[text,target:out]
+{
+	out <- [[[[Build["Web Link"]]Text <<[text]]Target <<[target]]Class <<[""]]Query Params <<[New@Dictionary[]]	
+}
+	
+
+With Session@Web Link[text,target,session:out]
+{
+	New@Web Link[text, target]
+	{
+		out <- [~]Query Params <<[[[~]Query Params >>]Set["session_id", [session]Session ID >>]]
+	}
+}
+
+Render@Web Link[link:out,headers]
+{
+	[[link]Query Params>>]First
+	{
+		queryvars <- ["?"]Append[Key Value Join[[link]Query Params>>, "=","&"]]
+	}{
+		queryvars <- ""
+	}
+	out <- [[[[[[["<a href=\""]Append[[link]Target>>]]Append[queryvars]]Append["\""]
+				]Append[Get Class[link]]]Append[">"]]Append[Escape HTML Text[[link]Text>>]]]Append["</a>"]
+}
+
+Postback@Web Link[in,post data:out,events]
+{
+	out <- in
+	events <- New@List[]	
+}
+
+Name@Web Link[link:name,none]
+{
+	none <- link
+}
+
+Set Session@Web Link[link,session:out]
+{
+	If[[[[link]Target >>]Slice[7]] = ["http://"]]
+	{
+		out <- link
+	}{
+		If[[session]Use Cookies >>]
+		{
+			out <- link
+		}{
+			out <- [link]Query Params <<[[[link]Query Params >>]Set["session_id", [session]Session ID>>]]
+		}
+	}
+}
+
+Blueprint Web Table
+{
+	Headers
+	Data
+}
+
+New@Web Table[headers,data:out]
+{
+	out <- [[Build["Web Table"]]Headers <<[headers]]Data <<[data]
+}
+
+Name@Web Table[link:name,none]
+{
+	none <- link
+}
+
+Set Session@Web Table[in,session:out]
+{
+	out <- in
+}
+
+Postback@Web Table[table,post data:out,events]
+{
+	out <- table
+	events <- ()
+}
+
+Make Header Row[string,header:out]
+{
+	out <- [[[string]Append["\t\t\t<th>"]]Append[header]]Append["</th>\n"]
+}
+
+Get Header Row@Web Table[table:out]
+{
+	If[[[[table]Headers >>]Length] > [0]]
+	{
+		out <- [Fold[["Make Header Row"]<String@Worker, "\t\t<tr>\n", [table]Headers >>]]Append["\t\t</tr>\n"]
+	}{
+		out <- ""
+	}
+}
+
+Make Table Cell[string,cell:out]
+{
+	out <- [[[string]Append["\t\t\t<td>"]]Append[[cell]Render]]Append["</td>\n"]
+}
+
+Make Table Row[string,row:out]
+{
+	out <- [Fold[["Make Table Cell"]<String@Worker, [string]Append["\t\t<tr>\n"], row]]Append["\t\t</tr>"]
+}
+
+Render@Web Table[table:out,headers]
+{
+	out <- [
+				[
+					["\t<table>\n"]Append[[table]Get Header Row]
+				]Append[ Fold[["Make Table Row"]<String@Worker, "", [table]Data >>] ]
+			]Append["\t</table>\n"]
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/framework.vistxt	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,761 @@
+Import webserver.vistxt
+
+Framework Handler(8,0)
+|:
+	page <- New@Page[title(6), path(1), use session(7), queryvars(3), headers(4)]
+	out list <- [handler(5)]Do[ [[New@List[]]Append[page]]Append[path(1)] ]
+	handler page <- [out list]Index[0]
+	If[[request type(2)] = ["POST"]]
+	|:
+		final page <- Process POST[handler page, con(0), headers(4)]
+	:||:
+		final page <- Val[handler page]
+	:|
+	string,headers <- [final page]Render
+	
+	[HTTP OK[client(0), Get Content Type[".html"], [string]Length, headers]
+	]Put String[string]
+:|
+
+Handler Fixer(1,1)
+|:
+	If[[Type Of[handler(0)]] = ["List"]]
+	|:
+		out(0) <- [[["Framework Handler"]Set Input[5, [handler(0)]Index[0]]]Set Input[6, [handler(0)]Index[1]]]Set Input[7, [handler(0)]Index[2]]
+	:||:
+		out(0) <- handler(0)
+	:|
+:|
+
+Start Web(1,0)
+|:
+	Print["Starting Rhope Web Server"]
+	Listen on Port[80,["Connection Start"]Set Input[1, Map[handlers(0),"Handler Fixer"]]]
+	Wait Forever[]
+:|
+
+Get Class(1,1)
+|:
+	If[[[[container(0)]Class >>]Length] > [0]]
+	|:
+		class(0) <- [[" class=\""]Append[[container(0)]Class >>]]Append["\""]
+	:||:
+		class(0) <- ""
+	:|
+:|
+
+Company Web Event
+|:
+	Event Name
+	Origin
+	Data
+:|
+
+New@Web Event(3,1)
+|:
+	out(0) <- [[[Build["Web Event"]]Event Name <<[name(0)]]Origin <<[origin(1)]]Data <<[data(2)]	
+:|
+
+Company Web Container
+|:
+	Tag Name
+	Class
+	Propagate Events
+	Children
+	Handlers
+	Named Children
+	Session
+	Use Session
+:|
+
+New@Web Container(1,1)
+|:
+	out(0) <- [[[[[[[Build["Web Container"]
+	]Tag Name <<["div"]
+	]Class <<[class(0)]
+	]Propagate Events <<[No]
+	]Children <<[New@List[]]
+	]Named Children <<[New@Dictionary[]]
+	]Handlers <<[New@Dictionary[]]
+	]Use Session <<[No]
+:|
+
+Name@Web Container(1,2)
+|:
+	none(1) <- cont(0)
+:|
+	
+Render Child(2,1)
+|:
+	out(0) <- [start(0)]Append[[container(1)]Render]
+:|
+
+Set Session@Web Container(2,1)
+|:
+	out(0) <- [
+				[
+					[container(0)]Use Session <<[Yes]
+				]Session <<[session(1)]
+			]Children <<[ Map[ [container(0)]Children >>, ["Set Session"]Set Input[1, session(1)] ] ]
+:|
+
+Set Handler@Web Container(3,1)
+|:
+	out(0) <- [container(0)]Handlers <<[ [[container(0)]Handlers >>	]Set[event name(1), handler(2)] ]
+:|
+
+Render@Web Container(1,2)
+|:
+	out(0) <- [[[[[[["<"]Append[ [container(0)]Tag Name >> ]
+		]Append[Get Class[container(0)]]
+		]Append[">\n\t"]
+		]Append[Fold[["Render Child"]<String@Worker, "", [container(0)]Children >>]]
+		]Append["\n</"]
+		]Append[ [container(0)]Tag Name >> ]
+		]Append[">\n"]
+:|
+
+Container Event Handler(2,2)
+|:
+	event <- [events(1)]Index[index(2)]
+	[[container(0)]Handlers >>]Index[ [event]Event Name >>]
+	|:
+		result list <- [~]Do[
+				[[New@List[]]Append[container(0)]]Append[event]
+		]
+		new container <- [result list]Index[0]
+		[result list]Index[1]
+		|:
+			events(1) <- [result events]Append[~]
+		:||:
+			events(1) <- Val[result events]
+		:|
+	:||:
+		new container <- container(0)
+		events(1) <- Val[result events]
+	:|
+	
+	[events(1)]Next[index(2)]
+	|:
+		cont(0), result events <- Container Event Handler[new container, events(1), ~]
+	:||:
+		cont(0) <- Val[new container]
+		result events <- New@List[]
+	:|
+:|
+
+Container Postback Helper(4,2)
+|:
+	,current events <- [[[container(0)]Children >>]Index[index(2)]]Postback[post data(1)]
+	|:
+		new container <- [container(0)]Children <<[[[container(0)]Children >>]Set[index(2), ~]]
+	:|
+	events <- Concatenate[events(3), current events]
+	[[new container]Children >>]Next[index(2)]
+	|:
+		out(0), events(1) <- Container Postback Helper[new container, post data(1), ~, events]
+	:||:
+		[events]First
+		|:
+			out(0), newevents <- Container Event Handler[new container, events, ~]
+			events(1) <- Concatenate[events, newevents]
+		:||:
+			out(0) <- Val[new container]
+			events(1) <- Val[events]
+		:|
+	:|
+:|
+
+Postback@Web Container(2,2)
+|:
+	[[container(0)]Children >>]First
+	|:
+		out(0), events <- Container Postback Helper[container(0), post data(1), ~, New@List[]]
+		If[[container(0)]Propagate Events >>]
+		|:
+			events(1) <- Val[events]
+		:||:
+			events(1) <- New@List[]
+		:|
+	:||:
+		out(0) <- container(0)
+		events(1) <- New@List[]
+	:|
+:|
+	
+Add Child(2,1)
+|:
+	If[[cont(0)]Use Session >>]
+	|:
+		child <- [child(1)]Set Session[[cont(0)]Session >>]
+	:||:
+		child <- Val[child(1)]
+	:|
+	with child <- [cont(0)]Children <<[ [[cont(0)]Children >>]Append[child] ]
+	
+	[child]Name
+	|:
+		out(0) <- [with child]Named Children <<[ [[with child]Named Children >>]Set[~, [[[with child]Children >>]Length] - [1]] ]
+	:||:
+		out(0) <- Val[with child]
+	:|
+:|
+
+Get Child By Name(2,2)
+|:
+	,not found(1) <- [[container(0)]Named Children >>]Index[name(1)]
+	|:
+		out(0) <- [[container(0)]Children >>]Index[~]
+	:|
+:|
+	
+Company Page
+|:
+	Title
+	URL
+	CSS
+	Children
+	Named Children
+	Handlers
+	Use Session
+	Session
+	Session ID
+:|
+
+Set Handler@Page(3,1)
+|:
+	out(0) <- [container(0)]Handlers <<[ [[container(0)]Handlers >>	]Set[event name(1), handler(2)] ]
+:|
+	
+New@Page(5,1)
+|:
+	page <- [[[[[[[Build["Page"]
+	]Title <<[title(0)]
+	]URL <<[url(1)]
+	]CSS <<[[New@List[]]Append["/default.css"]]
+	]Children <<[New@List[]]
+	]Named Children <<[New@Dictionary[]]
+	]Handlers <<[New@Dictionary[]]
+	]Use Session <<[use session(2)]
+	If[use session(2)]
+	|:
+		Load@Session[queryvars(3), headers(4)]
+		|:
+			out(0) <- [[page]Session <<[~]]Session ID <<[ [~]Session ID>>]
+		:|
+	:||:
+		out(0) <- Val[page]
+	:|
+:|
+
+Get Action@Page(1,1)
+|:
+	If[[page(0)]Use Session>>]
+	|:	
+		[[page(0)]Session >>]Get Link Params
+		|:
+			out(0) <- [[[page(0)]URL >>]Append["?"]]Append[~]
+		:||:
+			out(0) <- [page(0)]URL >>
+		:|
+	:||:
+		out(0) <- [page(0)]URL >>
+	:|
+:|
+	
+Render@Page(1,2)
+|:
+	out(0) <- [[[[[[["<html>\n\t<head>\n\t\t<title>"]Append[[page(0)]Title >>]
+		]Append["</title>\n\t\t<link rel=\"stylesheet\" href=\""]
+		]Append[[[page(0)]CSS >>]Join["\">\n\t\t<link rel=\"stylesheet\" href=\""]]
+		]Append["\">\n\t</head>\n\t<body>\n\t<form method=\"POST\" action=\""]
+		]Append[[[page(0)]Get Action]Append["\">\n"]]
+		]Append[Fold[["Render Child"]<String@Worker, "", [page(0)]Children >>]]
+		]Append["\t</form>\n\t</body>\n</html>"]
+	If[[page(0)]Use Session>>]
+	|:
+		headers(1) <- [[page(0)]Session >>]Finalize[New@Dictionary[]]
+	:||:
+		headers(1) <- New@Dictionary[]
+	:|
+:|
+
+Clear Children(1,1)
+|:
+	out(0) <- [[page(0)]Children <<[New@List[]]]Named Children <<[New@Dictionary[]]
+:|
+
+Set@Page(3,1)
+|:
+	out(0) <- [page(0)]Session <<[ [[page(0)]Session >>]Set[key(1), val(2)] ]
+:|
+
+Index@Page(2,2)
+|:
+	out(0),not found(1) <- [[page(0)]Session >>]Index[key(1)]
+:|
+
+First@Page(1,2)
+|:
+	first(0),not found(1) <- [[page(0)]Session >>]First
+:|
+
+Next@Page(2,2)
+|:
+	next(0),not found(1) <- [[page(0)]Session >>]Next[last(1)]	
+:|
+
+Add CSS@Page(1,1)
+|:
+	out(0) <- [page(0)]CSS <<[ [[page(0)]CSS >>]Append[css(1)] ]
+:|
+
+Clear CSS@Page(1,1)
+|:
+	out(0) <- [page(0)]CSS <<[New@List[]]	
+:|
+
+Decode Helper Decode(3,1)
+|:
+	code,rest <- [[list(0)]Index[index(2)]]Slice[2]
+	newlist <- [destlist(1)]Set[index(2), [[""]Put Byte[From Hex@Whole Number[code]]]Append[rest]]
+	[list(0)]Next[index(2)]
+	|:
+		out(0) <- Decode Helper Decode[list(0), newlist, ~]
+	:||:
+		out(0) <- Val[newlist]
+	:|
+:|
+
+Decode Helper Straight(3,1)
+|:
+	newlist <- [destlist(1)]Set[index(2), [list(0)]Index[index(2)]]
+	[list(0)]Next[index(2)]
+	|:
+		out(0) <- Decode Helper Decode[list(0), newlist, ~]
+	:||:
+		out(0) <- Val[newlist]
+	:|
+:|
+
+URL Decode(1,1)
+|:
+	parts <- [val(0)]Split["%"]
+	[parts]First
+	|:
+		val(0) <- [Decode Helper Straight[parts, New@List[], ~]]Join[""]
+	:||:
+		val(0) <- val(0)
+	:|
+:|
+
+URL Encode Path(1,1)
+|:
+	out(0) <- [[[[string(0)]Replace["%","%25"]]Replace[" ","%20"]]Replace["/","%2F"]]Replace["?","%3F"]
+:|
+
+Decode Pair(2,2)
+|:
+	val(0) <- URL Decode[val(0)]
+	key(1) <- URL Decode[key(1)]
+:|
+
+Process POST(3,1)
+|:
+	[con(1)]Get FString[[headers(2)]Index["Content-Length"]] |::|
+	|:
+		post string <- [~]Replace["+"," "]
+	:|
+	post data <- Key Value Map[Dict Split[post string, "=", "&"], ["Decode Pair"]<String@Worker]
+	out(0) <- [page(0)]Postback[post data]
+:|
+
+Postback@Page(2,2)
+|:
+	[[container(0)]Children >>]First
+	|:
+		out(0), events(1) <- Container Postback Helper[container(0), post data(1), ~, New@List[]]
+	:||:
+		page(0) <- page(0)
+	:|
+	events(1) <- New@List[]
+:|
+	
+Company Web Text
+|:
+	Text
+	Enclosing Tag
+:|
+	
+New@Web Text(2,1)
+|:
+	out(0) <- [[Build["Web Text"]]Text <<[text(0)]]Enclosing Tag <<[tag(1)]
+:|
+
+Name@Web Text(1,2)
+|:
+	none(1) <- text(0)
+:|
+
+Escape HTML Text(1,1)
+|:
+	out(0) <- [[[string(0)]Replace["&","&amp;"]]Replace["<", "&lt;"]]Replace[">", "&gt;"]
+:|
+	
+Render@Web Text(1,2)
+|:
+	processed text <- [Escape HTML Text[[text(0)]Text >>]]Replace["\n","<br>\n\t"]
+	If[[[[text(0)]Enclosing Tag >>]Length] = [0]]
+	|:
+		out(0) <- Val[processed text]
+	:||:
+		out(0) <- [[[["<"]Append[[text(0)]Enclosing Tag >>]]Append[">"]]Append[processed text]]Append[[["</"]Append[[text(0)]Enclosing Tag >>]]Append[">"]]
+	:|
+:|
+
+Postback@Web Text(2,2)
+|:
+	out(0) <- in(0) 
+	events(1) <- New@List[]
+:|
+
+Set Session@Web Text(2,1)
+|:
+	(0) <- (0)
+:|
+
+Render@String(1,2)
+|:
+	out(0) <- [New@Web Text[string(0),""]]Render	
+:|
+
+Name@String(1,2)
+|:
+	none(1) <- string(0)
+:|
+
+Postback@String(2,2)
+|:
+ 	out(0) <- in(0)
+ 	events(1) <- New@List[]
+:|
+
+Set Session@String(2,1)
+|:
+	(0) <- (0)
+:|
+
+Company Web Field
+|:
+	Name
+	Value
+	Type
+	Class
+:|
+
+Name@Web Field(1,2)
+|:
+	name(0) <- [field(0)]Name >>	
+:|
+
+New@Web Field(3,1)
+|:
+	out(0) <- [[[[Build["Web Field"]]Name <<[name(0)]]Value <<[value(1)]]Type <<[type(2)]]Class <<[""]
+:|
+
+Set Session@Web Field(2,1)
+|:
+	(0) <- (0)
+:|
+
+Render@Web Field(1,2)
+|:
+	If[[[field(0)]Type >>] = ["multiline"]]
+	|:
+		out(0) <- [[[[[["<textarea name=\""]Append[[field(0)]Name >>]]Append["\""]]Append[Get Class[field(0)]]]Append[">"]]Append[[field(0)]Value >>]]Append["</textarea>"]
+	:||:
+		out(0) <- [[[[[[[["<input type=\""]Append[[field(0)]Type >>]]Append["\" name=\""]]Append[[field(0)]Name >>]]Append["\""]]Append[Get Class[field(0)]]]Append[" value=\""]]Append[[field(0)]Value >>]]Append["\">"]
+	:|
+	
+:|
+
+Postback@Web Field(2,2)
+|:
+	[post data(1)]Index[[field(0)]Name >>]
+	|:
+		out(0) <- [field(0)]Value <<[~]
+
+		If[[[field(0)]Value >>] = [~]] 
+		|:
+			event(1) <- New@List[]
+		:||:
+			event(1) <- [New@List[]]Append[ New@Web Event["change", [field(0)]Name >>, [field(0)]Value >>] ]
+		:|
+	:||:
+		out(0) <- field(0)
+		event(1) <- New@List[]
+	:|
+:|
+
+Company Web Button
+|:
+	Name
+	Label
+	Class
+:|
+
+New@Web Button(2,1)
+|:
+	out(0) <- [[[Build["Web Button"]]Name <<[name(0)]]Label <<[label(1)]]Class <<[""]	
+:|
+
+Name@Web Button(1,2)
+|:
+	name(0) <- [button(0)]Name >>
+:|
+
+Set Session@Web Button(2,1)
+|:
+	(0) <- (0)
+:|
+
+Postback@Web Button(2,2)
+|:
+	out(0) <- button(0)
+	[post data(1)]Index[[button(0)]Name >>]
+	|:
+		events(1) <- [New@List[]]Append[ New@Web Event["click", [button(0)]Name >>, 0] ]
+	:||:
+		events(1) <- New@List[]
+	:|
+:|
+
+Render@Web Button(1,2)
+|:
+	out(0) <- [[[[[["<input type=\"submit\" name=\""]Append[[field(0)]Name >>]]Append["\""]]Append[Get Class[button(0)]]]Append[" value=\""]]Append[[button(0)]Label >>]]Append["\">"]
+:|
+
+Company Session
+|:
+	Session ID
+	IP Address
+	Use Cookies
+	Data
+:|
+
+Get Unique ID(0,1) uses Session
+|:
+	out(0) <- [[[::ID]<Whole Number@String]Append["_"]]Append[Random[]]
+	::ID <- [::ID]+[1]
+:|
+
+New@Session(0,1)
+|:
+	out(0) <- [[[Build["Session"]]Session ID <<[Get Unique ID[]]]Use Cookies <<[No]]Data <<[New@Dictionary[]]
+:|
+
+Load@Session(2,1) uses Session
+|:
+	,checkquery <- [headers(1)]Index["Cookie"]
+	|:
+		parts <- Dict Split[~, "=", "; "]
+		,checkquery <- [parts]Index["session_id"]
+		|:
+			,checkquery <- [::Sessions]Index[~]
+			|:
+				out(0) <- [~]Use Cookies <<[Yes]
+			:|
+		:|
+	:|
+	
+	
+	checkquery
+	|:
+		,makenew <- [queryvars(0)]Index["session_id"]
+		|:
+			out(0), makenew <- [::Sessions]Index[~]
+		:|
+	:|
+	
+	makenew
+	|:
+		out(0) <- New@Session[]
+	:|
+:|
+
+Get Link Params@Session(1,2)
+|:
+	If[[session(0)]Use Cookies >>]
+	|:
+		no params(1) <- No
+	:||:
+		out(0) <- ["session_id="]Append[[session(0)]Session ID >>]
+	:|
+:|
+
+Set@Session(3,1)
+|:
+	out(0) <- [session(0)]Data <<[ [[session(0)]Data >>]Set[key(1), val(2)] ]
+:|
+
+Index@Session(2,2)
+|:
+	out(0),not found(1) <- [[session(0)]Data >>]Index[key(1)]
+:|
+
+First@Session(1,2)
+|:
+	first(0),not found(1) <- [[session(0)]Data >>]First
+:|
+
+Next@Session(2,2)
+|:
+	next(0),not found(1) <- [[session(0)]Data >>]Next[last(1)]	
+:|
+
+Init Session Store(0,1)
+|:
+	Init Store["Session"]
+	out(0) <- 0
+:|
+
+Set Session Store(0,0) uses Session
+|:
+	::ID <- 1
+	::Sessions <- New@Dictionary[]
+:|
+
+Init Sessions(0,1)
+|:
+	Init Session Store[] |:
+	Set Session Store[] :|
+	out(0) <- 0
+:|
+
+Finalize@Session(2,1) uses Session
+|:
+	::Sessions <- [::Sessions]Set[[session(0)]Session ID >>, session(0)]
+	out headers(0) <- [headers(1)]Set["Set-Cookie", ["session_id="]Append[[session(0)]Session ID >>]]
+:|
+
+Company Web Link
+|:
+	Text
+	Target
+	Class
+	Query Params
+:|
+
+New@Web Link(2,1)
+|:
+	out(0) <- [[[[Build["Web Link"]]Text <<[text(0)]]Target <<[target(1)]]Class <<[""]]Query Params <<[New@Dictionary[]]	
+:|
+	
+
+With Session@Web Link(3,1)
+|:
+	New@Web Link[text(0), target(1)]
+	|:
+		out(0) <- [~]Query Params <<[[[~]Query Params >>]Set["session_id", [session(2)]Session ID >>]]
+	:|
+:|
+
+Render@Web Link(1,2)
+|:
+	[[link(0)]Query Params>>]First
+	|:
+		queryvars <- ["?"]Append[Key Value Join[[link(0)]Query Params>>, "=","&"]]
+	:||:
+		queryvars <- ""
+	:|
+	out(0) <- [[[[[[["<a href=\""]Append[[link(0)]Target>>]]Append[queryvars]]Append["\""]
+				]Append[Get Class[link(0)]]]Append[">"]]Append[Escape HTML Text[[link(0)]Text>>]]]Append["</a>"]
+:|
+
+Postback@Web Link(2,2)
+|:
+	out(0) <- in(0)
+	events(1) <- New@List[]	
+:|
+
+Name@Web Link(1,2)
+|:
+	none(1) <- link(0)
+:|
+
+Set Session@Web Link(2,1)
+|:
+	If[[[[link(0)]Target >>]Slice[7]] = ["http://"]]
+	|:
+		out(0) <- link(0)
+	:||:
+		If[[session(1)]Use Cookies >>]
+		|:
+			out(0) <- link(0)
+		:||:
+			out(0) <- [link(0)]Query Params <<[[[link(0)]Query Params >>]Set["session_id", [session(1)]Session ID>>]]
+		:|
+	:|
+:|
+
+Company Web Table
+|:
+	Headers
+	Data
+:|
+
+New@Web Table(2,1)
+|:
+	out(0) <- [[Build["Web Table"]]Headers <<[headers(0)]]Data <<[data(1)]
+:|
+
+Name@Web Table(1,2)
+|:
+	none(1) <- link(0)
+:|
+
+Set Session@Web Table(2,1)
+|:
+	(0) <- (0)
+:|
+
+Postback@Web Table(2,2)
+|:
+	(0) <- (0)
+	(1) <- {}
+:|
+
+Make Header Row(2,1)
+|:
+	out(0) <- [[[string(0)]Append["\t\t\t<th>"]]Append[header(1)]]Append["</th>\n"]
+:|
+
+Get Header Row@Web Table(1,1)
+|:
+	If[[[[table(0)]Headers >>]Length] > [0]]
+	|:
+		out(0) <- [Fold[["Make Header Row"]<String@Worker, "\t\t<tr>\n", [table(0)]Headers >>]]Append["\t\t</tr>\n"]
+	:||:
+		out(0) <- ""
+	:|
+:|
+
+Make Table Cell(2,1)
+|:
+	out(0) <- [[[string(0)]Append["\t\t\t<td>"]]Append[[cell(1)]Render]]Append["</td>\n"]
+:|
+
+Make Table Row(2,1)
+|:
+	out(0) <- [Fold[["Make Table Cell"]<String@Worker, [string(0)]Append["\t\t<tr>\n"], row(1)]]Append["\t\t</tr>"]
+:|
+
+Render@Web Table(1,2)
+|:
+	out(0) <- [
+				[
+					["\t<table>\n"]Append[[table(0)]Get Header Row]
+				]Append[ Fold[["Make Table Row"]<String@Worker, "", [table(0)]Data >>] ]
+			]Append["\t</table>\n"]
+:|
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hello.rhope	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,11 @@
+/*
+	This is the classic "Hello World" program in Rhope
+*/
+
+//All programs in Rhope must have a Main worker
+//This is where execution of a Rhope program begins
+Main[]
+{
+	//The Print worker prints a line of text to the terminal
+	Print["Hello Rhope Programming!"]
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/interp.c	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,4102 @@
+#ifdef WIN32
+	#include <windows.h>
+	#include <winsock.h>
+	#include <crtdbg.h>
+#else
+#ifdef SYLLABLE
+	#include <unistd.h>
+	#include <atheos/threads.h>
+#else
+	#ifdef NINTENDO_DS
+		#include <nds.h>
+	#else
+		#include <unistd.h>
+		#include <pthread.h>
+	#endif
+#endif
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "mt19937ar.h"
+#include "interp.h"
+#include "vis_threading.h"
+#include "datum.h"
+#include "parser.h"
+#include "saveload.h"
+
+#ifdef TEXT_FILE_DEBUG
+	FILE * debugfile;
+#endif
+char debugbuffer[1024];
+
+//extern HWND	hWnd;
+extern char new_name_buf[256];
+extern int buf_size;
+
+int lock_fail_counter;
+int lock_counter;
+
+VIS_CRITICAL_SECTION(data_lock)
+VIS_CRITICAL_SECTION(worker_queue_lock)
+VIS_CRITICAL_SECTION(randlock)
+VIS_Event(queue_add_event)
+
+int program_count=1;
+VIS_CRITICAL_SECTION(program_count_lock)
+
+//#define	ENABLE_PROFILING	1
+
+#ifdef	ENABLE_PROFILING
+
+__int64	vis_profile_start_times[NUM_PROFS];
+__int64 vis_profile_running_total[NUM_PROFS];
+int	vis_profile_counts[NUM_PROFS];
+
+__declspec(naked)
+unsigned __int64 __cdecl rdtsc(void)
+{
+   __asm
+   {
+      rdtsc
+      ret       ; return value at EDX:EAX
+   }
+}
+
+
+#define PROF_INIT_CUSTOM			0
+#define	PROF_WORKER_THREAD			1
+#define	PROF_PROCESS_WORKER			2
+#define	PROF_CLEANUP_CUSTOM 		3
+#define	PROF_SUB_CALLBACK			4
+#define	PROF_CLEANUP_RELEASE_REFS	5
+#define	PROF_CLEANUP_CHECK			6
+#define	PROF_CLEANUP_FREELISTS		7
+#define	PROF_PROCESS_OUTPUTS		8
+#define	PROF_OPT_PREP_INPUT			9
+#define	PROF_RUN_OPT				10
+#define	PROF_ADDQUEUE				11
+#define	PROF_ADDQUEUE_MALLOC		12
+#define	PROF_OPT_LOOP				13
+#define	PROF_EXECUTE_WORKER			14
+#define	PROF_EXECUTE_OTHER			15
+#define	PROF_PREP_MAGIC				16
+#define	PROF_CONVERT_INPUTS			17
+#define	PROF_EXECUTE_CUSTOM			18
+#define	PROF_EXECUTE_BUILTIN		19
+#define	PROF_EMPTYFUNC				20
+#define	PROF_NOCODE					21
+#define	PROF_LESSERWHOLE			22
+#define	PROF_EQUALWHOLE				23
+#define	PROF_PARTIAL_EXEC			24
+#define	PROF_ADDWHOLE				25
+#define	PROF_FULL_EXEC				26
+#define PROF_OPT_EXEC_USER			27
+#define PROF_OPT_EXEC_BUILT			28
+#define PROF_VIRTUAL_DECODE			27
+#define PROF_VIRTUAL_EXECUTE		28
+
+
+/*#define VIS_PROFILE_START(index)	vis_profile_start_times[index] = rdtsc()
+#define	VIS_PROFILE_END(index)		vis_profile_running_total[index] += (rdtsc()-vis_profile_start_times[index]); ++vis_profile_counts[index]
+
+#else
+
+#define VIS_PROFILE_START(index)
+#define	VIS_PROFILE_END(index)*/
+
+#endif
+
+queue_entry * worker_queue;
+queue_section first_section;
+queue_section * current_section;
+int queue_start;
+int queue_len;
+
+BOOL execute_active=FALSE;
+
+char text_buf[256];
+int text_buf_size;
+VIS_CRITICAL_SECTION(text_buf_lock)
+
+#ifdef WIN32
+	WSADATA wsa_data;
+	#ifdef GUI_LIB
+		char errorbuffer[1024];
+	#endif
+#endif
+
+
+worker_instance * main_instance;
+
+//company companylist[40];
+//int num_companies=0;
+
+datum * global_store_dict;
+VIS_CRITICAL_SECTION(global_store_lock);
+
+
+int empty_func(datum ** a, queue_entry * worker_entry)
+{
+	return 0;
+}
+
+worker_impl empty_test = empty_func;
+/*
+ void set_in_child(worker_def * parent, int worker_num, BOOL * in_child, BOOL value, int exclude_worker)
+{
+	int j,i = parent->workerlist[worker_num].wire_down_lookup;
+	if(exclude_worker >= 0 && exclude_worker == worker_num)
+		return;
+	in_child[worker_num] = value;
+	while(parent->wirelist[j=parent->workers_to_wires_down[i]].start_worker == worker_num && j >= 0)
+		set_in_child(parent, parent->wirelist[j].end_worker, in_child, value);
+}
+
+void build_child_worker(worker_def * parent, int worker_num, int output_num)
+{
+	int i,j, num_child_workers, num_child_wires, child_def;
+	BOOL * in_child = malloc(sizeof(BOOL)* parent->num_workers);
+	int * child_offsets = malloc(sizeof(int) * parent->num_workers);
+	for(i = 0; i < parent->num_workers; ++i)
+	{
+		in_child[i] = FALSE;
+		child_offsets[i] = -1;
+	}
+	i = parent->workerlist[worker_num].wire_down_lookup;
+	while(parent->wirelist[j=parent->workers_to_wires_down[i]].start_worker == worker_num && j >= 0)
+	{
+		if(parent->wirelist[j].output_num == output_num)
+			set_in_child(parent, parent->wirelist[j].end_worker, in_child, TRUE,-1);
+	}
+	i = parent->workerlist[worker_num].wire_down_lookup;
+	while(parent->wirelist[j=parent->workers_to_wires_down[i]].start_worker == worker_num && j >= 0)
+	{
+		if(parent->wirelist[j].output_num != output_num)
+			set_in_child(parent, parent->wirelist[j].end_worker, in_child, FALSE,-1);
+	}
+	for(i = 0; i < parent->num_workers; ++i)
+	{
+		if(i != worker_num && (parent->workerlist[i].type == 4 || (parent->workerlist[i].type == 2 && !in_child[i])))
+			set_in_child(parent, i, in_child, FALSE);
+	}
+	for(i = 0; i < parent->num_workers; ++i)
+	{
+		if(in_child[i])
+			child_offests[i] = num_child_workers++;
+	}
+	for(i = 0; i < parent->num_wires; ++i)
+	{
+		if(in_child[parent->wirelist[i].start_worker] || in_child[parent->wirelist[i].end_worker])
+			++num_child_wires;
+	}
+	child_def = num_defs++;//needs lock or atomic incrememnt
+	deflist[child_def].workerlist = malloc(sizeof(worker)*num_child_workers);
+	deflist[child_def].wirelist = malloc(sizeof(wire)*num_child_wires);
+	for(i = 0; i < parent->num_workers; ++i)
+	{
+		if(in_child[i])
+			deflist[child_def].workerlist[child_offests[i]] = parent->workerlist[i];
+	}
+} */
+
+#define MAX_TRACE_DEPTH	40
+
+void print_stack_trace(worker_instance * stack_instance)
+{
+	int i = 0;
+	ERRORPUTS("Stack trace:\n");
+	while(stack_instance && i < MAX_TRACE_DEPTH)
+	{
+		ERRORPRINTF("%s\n", stack_instance->def->name);
+		stack_instance = stack_instance->caller_instance;
+		++i;
+	}
+	if(stack_instance)
+	{
+		ERRORPUTS("Stack trace aborted after 40 entries\n");
+	}
+}
+
+void check_tail(worker_def * def)
+{
+	custom_worker * worker = def->implement_func;
+	int i,j,k,endworker;
+	BOOL can_tail, outputs_handled[32];
+	for(i = 0; i < worker->num_workers; ++i)
+	{
+		if(worker->workerlist[i].type == WORKER)
+		{
+			can_tail = TRUE;
+			for(j = 0; j < def->num_outputs; ++j)
+				outputs_handled[j] = FALSE;
+			j = worker->workerlist[i].wire_down_lookup;
+			while((k=worker->workers_to_wires_down[j]) >= 0 && worker->wirelist[k].start_worker == i)
+			{
+				endworker = worker->wirelist[k].end_worker;
+				if(worker->workerlist[endworker].type != OUTPUT || worker->workerlist[endworker].io_num != worker->wirelist[k].output_num)
+				{
+					can_tail = FALSE;
+					break;
+				}
+				else
+					outputs_handled[worker->wirelist[k].output_num] = TRUE;
+				++j;
+			}
+			if(can_tail)
+			{
+				for(j = 0; j < def->num_outputs; ++j)
+					if(!outputs_handled[j])
+					{
+						can_tail = FALSE;
+						break;
+					}
+				if(can_tail)
+					if(worker->workerlist[i].value_index == def)
+						worker->workerlist[i].type = TAIL_RECURSE;
+					else if(!def->num_stores)
+						worker->workerlist[i].type = TAIL_CALL;
+			}
+		}
+	}
+}
+
+BOOL method_match(char * name, char * method_name)
+{
+	int i = 0;
+	while(name[i] != '\0' && method_name[i] != '@' && method_name[i] != '\0')
+	{
+		if(name[i] != method_name[i])
+			return FALSE;
+		++i;
+	}
+	if(name[i] != '\0' || method_name[i] != '@')
+		return FALSE;
+	return TRUE;
+}
+
+worker_def * find_method(int type, char * name, int num_inputs, program * prog)
+{
+	int i;
+	worker_def * output = NULL;
+	company * companylist = prog->companylist;
+	VIS_EnterCriticalSection(companylist[type].lock);
+	for(i = 0; i < companylist[type].num_methods; ++i)
+	{
+		//DEBUGPRINTF( "Checking method %s(%d,%d)\n", companylist[type].methodlist[i]->name, companylist[type].methodlist[i]->num_inputs, companylist[type].methodlist[i]->num_outputs);
+		if(companylist[type].methodlist[i]->num_inputs == num_inputs && method_match(name, companylist[type].methodlist[i]->name))
+		{
+			DEBUGPRINTF( "Found method: %s\n", companylist[type].methodlist[i]->name);
+			output = companylist[type].methodlist[i];
+			break;
+		}
+	}
+	VIS_LeaveCriticalSection(companylist[type].lock);
+	return output;
+}
+
+worker_def * find_method_noinputcheck(int type, char * name, program * prog)
+{
+	int i;
+	worker_def * output = NULL;
+	company * companylist = prog->companylist;
+	VIS_EnterCriticalSection(companylist[type].lock);
+	for(i = 0; i < companylist[type].num_methods; ++i)
+	{
+		//DEBUGPRINTF( "Checking method %s(%d,%d)\n", companylist[type].methodlist[i]->name, companylist[type].methodlist[i]->num_inputs, companylist[type].methodlist[i]->num_outputs);
+		if(method_match(name, companylist[type].methodlist[i]->name))
+		{
+			DEBUGPRINTF( "Found method: %s\n", companylist[type].methodlist[i]->name);
+			output = companylist[type].methodlist[i];
+			break;
+		}
+	}
+	VIS_LeaveCriticalSection(companylist[type].lock);
+	return output;
+}
+
+worker_def * find_converter_method(int totype, int fromtype, program * prog)
+{
+	int i;
+	company * companylist = prog->companylist;
+	DEBUGPRINTF( "Finding converter from %s to %s\n", companylist[fromtype].name, companylist[totype].name);
+	//DEBUGPRINTF( "Num methods %d\n", companylist[totype].num_methods);
+	for(i = 0; i < companylist[totype].num_methods; ++i)
+	{
+		//DEBUGPRINTF("methodlist[i]: %X\n", companylist[totype].methodlist[i]);
+		DEBUGPRINTF( "Checking method %s\n", companylist[totype].methodlist[i]->name);
+		
+		if(companylist[totype].methodlist[i]->name[0] == '<' && method_match(companylist[fromtype].name, companylist[totype].methodlist[i]->name+1))
+		{
+			DEBUGPRINTF( "Found Method %s\n", companylist[totype].methodlist[i]->name);
+			
+			return companylist[totype].methodlist[i];
+		}
+	}
+	return NULL;
+}
+
+worker_instance *  init_custom_worker_type(int aworker, worker_instance * caller, worker_def * def, instance_callback callback, void * callback_data, datum ** params, int type)
+{
+	int i, workerlist_size, j, add_index_count=0;
+	int add_index[32];
+	datum * work_params[32];
+	datum * temp_params[3];
+	global_store * store;
+	worker_instance * instance;
+	BOOL release_params = TRUE;
+	def_make_lookup(def);
+	workerlist_size = sizeof(worker_instance_data)*(def->implement_func->num_workers);
+	//DEBUGPRINTF("workerlist_size: %d * %d = %d, wirelist_size: %d * %d = %d.\n", sizeof(worker_instance_data), def->implement_func->num_workers, workerlist_size, sizeof(wire_instance_data), def->implement_func->num_wires, sizeof(wire_instance_data)*(def->implement_func->num_wires));
+	//DEBUGPRINTF("Before malloc(%d)\n",sizeof(worker_instance) + workerlist_size + sizeof(wire_instance_data)*(def->implement_func->num_wires));
+	if(type == TAIL_RECURSE || type == TAIL_CALL)
+	{
+		VIS_EnterCriticalSection(caller->counter_lock);
+			if(caller->in_progress_count <= 1 && !caller->in_queue_count)
+			{
+		VIS_LeaveCriticalSection(caller->counter_lock);
+				instance = caller;
+				for(i = 0; i < instance->num_workers; ++i)
+				{
+					if(instance->def->implement_func->workerlist[i].type != WORKER && instance->def->implement_func->workerlist[i].type != TAIL_RECURSE && instance->def->implement_func->workerlist[i].type != TAIL_CALL && instance->workerlist[i].value)
+						release_ref(instance->workerlist[i].value);
+					if(instance->workerlist[i].ready_count && instance->workerlist[i].ready_count < (instance->def->implement_func->workerlist[i].num_inputs + (instance->def->implement_func->workerlist[i].null_input ? 1 : 0)))
+					{
+						DEBUGPRINTF("Freeing params for worker number %d, ready_count: %d, num_inputs: %d, null_input: %d, instance: %X\n", i, instance->workerlist[i].ready_count,instance->def->implement_func->workerlist[i].num_inputs, instance->def->implement_func->workerlist[i].null_input, instance);
+						for(j = 0; j <= instance->def->implement_func->workerlist[i].num_inputs; ++j)
+						{
+							DEBUGPRINTF("Releasing param %d of worker %d\n", j, i);
+							release_ref(instance->workerlist[i].params[j]);
+						}
+					}
+				}
+				for(i = 0; i < def->num_inputs; ++i)
+					work_params[i] = params[i];
+				params = work_params;
+				if(type == TAIL_RECURSE)
+				{
+					instance->in_progress_count = 0;
+					//TODO: adjust profile counter?
+					goto init_workerlist;
+				}
+				else
+				{
+					aworker = instance->worker_in_caller;
+					callback = instance->callback;
+					callback_data = instance->callback_data;
+					caller = instance->caller_instance;
+					VIS_DeleteCriticalSection(instance->counter_lock);
+					free(instance);
+				}
+			}
+			else
+			{
+		VIS_LeaveCriticalSection(caller->counter_lock);
+			}
+	}
+				
+			
+	instance = MALLOC(sizeof(worker_instance) + workerlist_size/* + sizeof(wire_instance_data)*(def->implement_func->num_wires) */,"instance");
+
+	//DEBUGPRINTF("malloc returned %X.\n", instance);
+	VIS_PROFILE_START(PROF_INIT_CUSTOM);
+	//DEBUGPRINTF("init_custom_worker, instance: %X\n", instance);
+#ifdef USER_PROFILE
+	QueryPerformanceCounter(&(instance->start));
+#endif
+	instance->def = def;
+	instance->num_workers = def->implement_func->num_workers;
+	instance->workerlist = (worker_instance_data *)(((char *)instance) + sizeof(worker_instance));//malloc(sizeof(worker_instance_data)*(def->implement_func->num_workers));
+	//DEBUGPRINTF("workerlist at %X\n", instance->workerlist);
+	
+	/*instance->num_wires = def->implement_func->num_wires;
+	instance->wirelist = (wire_instance_data *)(((char *)(instance->workerlist)) + workerlist_size);//malloc(sizeof(wire_instance_data)*(def->implement_func->num_wires));
+	DEBUGPRINTF("wirelist at %X\n", instance->wirelist);*/
+	
+	
+	instance->callback = callback;
+	instance->worker_in_caller = aworker;
+	instance->callback_data = callback_data;
+	instance->caller_instance = caller;
+	VIS_InitializeCriticalSection(instance->counter_lock);
+	instance->in_progress_count = 0;
+	instance->in_queue_count = 0;
+	
+	if(def->num_stores)
+	{
+		instance->trans = MALLOC(sizeof(transaction) + sizeof(global_store_use) *(def->num_stores - 1),"transaction");
+		VIS_EnterCriticalSection(global_store_lock);
+			for(i = 0; i < def->num_stores; ++i)
+			{
+				temp_params[0] = add_ref(global_store_dict);
+				temp_params[1] = make_string(def->uses_stores[i], -1, def->program);
+				vis_dict_index(temp_params, NULL);
+				if(!temp_params[0])
+				{
+					printf("Error: Global store %s is not initialized\n", def->uses_stores[i]);
+					DEBUGPRINTF("Error: Global store %s is not initialized\n", def->uses_stores[i]);
+					VIS_LeaveCriticalSection(global_store_lock);
+					return NULL;
+				}
+				instance->trans->stores[i].store = temp_params[0]->c.generic.data;
+				instance->trans->stores[i].instance_data = instance->trans->stores[i].begin_data = add_ref(instance->trans->stores[i].store->data);
+				VIS_InitializeCriticalSection(instance->trans->stores[i].lock);
+				//Is this really necessary?
+				release_ref(temp_params[0]);
+			}
+		VIS_LeaveCriticalSection(global_store_lock);
+		instance->trans->num_stores = def->num_stores;
+		if((def->transaction_flags & TRANSACTION_WRITE) && (def->transaction_flags & TRANSACTION_TYPE_MASK) == TRANSACTION_RETRY)
+		{
+			release_params = FALSE;
+			for(i = 0; i < def->num_inputs; ++i)
+				instance->trans->params[i] = params[i];
+		}
+	} else {
+		instance->trans = NULL;
+	}
+	
+
+init_workerlist:	
+	//DEBUGPUTS("init worker values\n");
+	for(i = 0; i < instance->num_workers; ++i)
+	{
+//		DEBUGPRINTF("InitializeCriticalSection on workerlist[%d].worker_lock (%X)\n", i, &(instance->workerlist[i].worker_lock));
+		VIS_InitializeCriticalSection(instance->workerlist[i].worker_lock);
+		//DEBUGPUTS("ready_count = 0\n");
+		instance->workerlist[i].ready_count = 0;
+		if(def->implement_func->workerlist[i].type == INPUT && params)
+			instance->workerlist[i].value = add_ref(params[def->implement_func->workerlist[i].io_num]);
+		else //if(def->implement_func->workerlist[i].type != 2)
+			instance->workerlist[i].value = NULL;
+		//DEBUGPRINTF("instance->workerlist[%d].value = %X\n", i, instance->workerlist[i].value);
+		for(j = 0; j <= def->implement_func->workerlist[i].num_inputs; ++j)
+			instance->workerlist[i].params[j] = NULL;
+		//DEBUGPRINTF("num_inputs: %d, null_input: %d\n", def->implement_func->workerlist[i].num_inputs, def->implement_func->workerlist[i].null_input);
+
+		//There's still a potential race condition here, but it's unlikely to occur except on a system with an insane number of cores/processors
+		//and only on custom workers that have more than 32 items that will be initially ready
+		if(!def->implement_func->workerlist[i].num_inputs && !def->implement_func->workerlist[i].null_input)
+		{
+			DEBUGPRINTF("adding worker %s(%d) to queue\n", def->implement_func->workerlist[i].name, i);
+			add_index[add_index_count++] = i;
+			if(add_index_count == 32)
+			{
+				add_multiple(add_index, add_index_count, instance);
+				add_index_count = 0;
+			}
+			//add_queue(i,instance);
+		}
+	}
+
+	if(params)
+	{
+		if(release_params)
+		{
+			//DEBUGPUTS("release params\n");
+			for(i = 0; i < def->num_inputs; ++i)
+				release_ref(params[i]);
+		}
+	}
+	if(add_index_count > 0)
+		add_multiple(add_index, add_index_count, instance);
+	VIS_PROFILE_END(PROF_INIT_CUSTOM);
+
+	return instance;
+}
+
+worker_instance *  init_custom_worker(int aworker, worker_instance * caller, worker_def * def, instance_callback callback, void * callback_data, datum ** params)
+{
+	return init_custom_worker_type(aworker, caller, def, callback, callback_data, params, WORKER);
+}
+
+void cleanup_check(queue_entry aworker)
+{
+	char msg[256];
+	VIS_EnterCriticalSection(aworker.instance->counter_lock);
+		--(aworker.instance->in_progress_count);
+		DEBUGPRINTF( "Cleanup Check on %s<%d>:%X, in_progress: %d, in_queue: %d\n", aworker.instance->def->name, aworker.instance->worker_in_caller, aworker.instance, aworker.instance->in_progress_count,aworker.instance->in_queue_count);
+		
+		if(aworker.instance->in_progress_count == 0 && aworker.instance->in_queue_count == 0)
+		{
+	VIS_LeaveCriticalSection(aworker.instance->counter_lock);
+			cleanup_custom_worker(aworker.instance, aworker.worker_num);
+		}
+		else
+		{
+	VIS_LeaveCriticalSection(aworker.instance->counter_lock);
+		}
+}
+
+void cleanup_custom_worker(worker_instance * instance, int worker_num)
+{
+	BOOL do_commit = TRUE;
+	int i,j;
+	queue_entry incaller;
+	global_store * store;
+	#ifdef USER_PROFILE
+		LARGE_INTEGER end;
+		LARGE_INTEGER duration;
+	#endif
+	if(instance->trans)
+	{
+		if(instance->def->transaction_flags & TRANSACTION_WRITE)
+		{
+			VIS_EnterCriticalSection(global_store_lock);
+				if((instance->def->transaction_flags & TRANSACTION_TYPE_MASK) != TRANSACTION_FORCE)
+				{
+					for(i = 0; i < instance->trans->num_stores; ++i)
+					{
+						if(instance->trans->stores[i].begin_data != instance->trans->stores[i].store->data)
+						{
+							do_commit = FALSE;
+							break;
+						}
+					}
+				}
+				if(do_commit)
+				{
+					for(i = 0; i < instance->trans->num_stores; ++i)
+					{
+						release_ref(instance->trans->stores[i].store->data);
+						instance->trans->stores[i].store->data = instance->trans->stores[i].instance_data;
+					}
+				}
+			VIS_LeaveCriticalSection(global_store_lock);
+			if(!do_commit)//retry transaction
+			{
+				for(i = 0; i < instance->trans->num_stores; ++i)
+					release_ref(instance->trans->stores[i].instance_data);
+				puts("retrying transaction");
+				init_custom_worker(instance->worker_in_caller, instance->caller_instance, instance->def, instance->callback, instance->callback_data, instance->trans->params);
+			}
+			else if((instance->def->transaction_flags & TRANSACTION_TYPE_MASK) == TRANSACTION_RETRY)
+				for(i = 0; i < instance->def->num_inputs; ++i)
+					release_ref(instance->trans->params[i]);
+		}
+		else
+		{
+			for(i = 0; i < instance->trans->num_stores; ++i)
+				release_ref(instance->trans->stores[i].instance_data);
+		}
+		VIS_FREE(instance->trans, "transaction");
+	}
+	VIS_PROFILE_START(PROF_CLEANUP_CUSTOM);
+	DEBUGPRINTF("Cleaning up custom worker: %s:%X\n", instance->def->name, instance);
+	
+	VIS_PROFILE_START(PROF_SUB_CALLBACK);
+	if(instance->callback && do_commit)
+		instance->callback(instance->caller_instance, instance->worker_in_caller, instance, instance->callback_data);
+	//DEBUGPUTS("About to release refs\n");
+	VIS_PROFILE_END(PROF_SUB_CALLBACK);
+	VIS_PROFILE_START(PROF_CLEANUP_RELEASE_REFS);
+	/*for(i = 0; i < instance->def->implement_func->num_wires; ++i)
+	{
+		if(instance->wirelist[i].data)
+		{
+			DEBUGPRINTF("release_ref on wire %d\n", i);
+			
+			release_ref(instance->wirelist[i].data);
+		}
+	}*/
+	for(i = 0; i < instance->num_workers; ++i)
+	{
+		if(instance->def->implement_func->workerlist[i].type != WORKER && instance->def->implement_func->workerlist[i].type != TAIL_RECURSE && instance->def->implement_func->workerlist[i].type != TAIL_CALL && instance->workerlist[i].value)
+		{
+			DEBUGPRINTF( "release_ref on worker %d in instance %X\n", i, instance);
+			release_ref(instance->workerlist[i].value);
+		}
+		if(instance->workerlist[i].ready_count && instance->workerlist[i].ready_count < (instance->def->implement_func->workerlist[i].num_inputs + (instance->def->implement_func->workerlist[i].null_input ? 1 : 0)))
+		{
+			DEBUGPRINTF("Freeing params for worker number %d, ready_count: %d, num_inputs: %d, null_input: %d, instance: %X\n", i, instance->workerlist[i].ready_count,instance->def->implement_func->workerlist[i].num_inputs, instance->def->implement_func->workerlist[i].null_input, instance);
+			for(j = 0; j <= instance->def->implement_func->workerlist[i].num_inputs; ++j)
+			{
+				DEBUGPRINTF("Releasing param %d of worker %d\n", j, i);
+				release_ref(instance->workerlist[i].params[j]);
+			}
+		}
+		VIS_DeleteCriticalSection(instance->workerlist[i].worker_lock);
+	}
+	VIS_PROFILE_END(PROF_CLEANUP_RELEASE_REFS);
+	VIS_DeleteCriticalSection(instance->counter_lock);
+	//DEBUGPUTS("freeing lists\n");
+	#ifdef USER_PROFILE
+		if(do_commit)
+		{
+			QueryPerformanceCounter(&end);
+			duration.QuadPart = end.QuadPart - instance->start.QuadPart;
+			VIS_EnterCriticalSection(instance->def->lock);
+				instance->def->total.QuadPart += duration.QuadPart;
+				++instance->def->count;
+				if(duration.QuadPart > instance->def->worst.QuadPart)
+					instance->def->worst.QuadPart = duration.QuadPart;
+			VIS_LeaveCriticalSection(instance->def->lock);
+		}
+	#endif
+	/*VIS_PROFILE_START(PROF_CLEANUP_FREELISTS);
+	free(instance->workerlist);
+	free(instance->wirelist);
+	VIS_PROFILE_END(PROF_CLEANUP_FREELISTS);*/
+	VIS_PROFILE_START(PROF_CLEANUP_CHECK);
+	if(instance->caller_instance && do_commit)
+	{
+		incaller.worker_num = instance->worker_in_caller;
+		incaller.instance = instance->caller_instance;
+		DEBUGPUTS("Calling cleanup_check on parent\n");
+		cleanup_check(incaller);
+	}
+	if(do_commit && instance->callback == main_callback)
+		release_program_ref(instance->def->program);
+	VIS_PROFILE_END(PROF_CLEANUP_CHECK);
+	VIS_PROFILE_START(PROF_CLEANUP_FREELISTS);
+	VIS_FREE(instance, "worker instance");
+	VIS_PROFILE_END(PROF_CLEANUP_FREELISTS);
+	VIS_PROFILE_END(PROF_CLEANUP_CUSTOM);
+}
+/*
+void worker_complete(queue_entry aworker)
+{
+	int i,j;
+	wire * wirelist;
+	int * workers_to_wires_down;
+	VIS_PROFILE_START(PROF_WORKER_COMPLETE);
+	DEBUGPUTS("worker_complete()\n");
+	
+	
+	i = aworker.instance->def->implement_func->workerlist[aworker.worker_num].wire_down_lookup;
+	wirelist = aworker.instance->def->implement_func->wirelist;
+	workers_to_wires_down = aworker.instance->def->implement_func->workers_to_wires_down;
+	while(wirelist[j=workers_to_wires_down[i]].start_worker == aworker.worker_num && j >= 0)
+	{
+		if(aworker.instance->wirelist[j].data)
+		{
+			DEBUGPRINTF("end_worker: %d, wirelist[%d].data = %X\n", wirelist[j].end_worker, j, aworker.instance->wirelist[j].data);
+				add_if_ready(wirelist[j].end_worker, aworker.instance);
+		}
+		++i;
+	}
+	DEBUGPUTS("worker_complete done\n");
+	VIS_PROFILE_END(PROF_WORKER_COMPLETE);
+}*/
+
+void process_outputs(datum ** params, int aworker, worker_instance * instance)
+{
+	BOOL flag=FALSE;
+	int i,j;
+	worker_def * def = instance->def;
+	//custom_worker *implement_func = def->implement_func;
+	wire * def_wires = def->implement_func->wirelist;
+	worker * def_workers = def->implement_func->workerlist;
+	VIS_PROFILE_START(PROF_PROCESS_OUTPUTS);
+	DEBUGPRINTF("Process outputs for worker %d in instance %X\n", aworker, instance);
+	DEBUGPRINTF("Num_inputs: %d, num_outputs: %d\n", def_workers[aworker].num_inputs, def_workers[aworker].num_outputs);
+	if(def_workers[aworker].num_outputs && instance->workerlist)
+	{
+		//DEBUGPRINTF("num_outputs: %d\n", def_workers[aworker].num_outputs);
+		i = def_workers[aworker].wire_down_lookup;
+		while((j=def->implement_func->workers_to_wires_down[i]) >= 0 && def_wires[j].start_worker == aworker)
+		{
+			//DEBUGPRINTF("Checking output: %d\n", def_wires[j].output_num);
+			DEBUGPRINTF("output[%d] = %X\n", def_wires[j].output_num, params[def_wires[j].output_num]);
+			DEBUGPRINTF("wire leads to worker %d, instance->workerlist: %X\n", def_wires[j].end_worker, instance->workerlist);
+			VIS_EnterCriticalSection(instance->workerlist[def_wires[j].end_worker].worker_lock);
+				if(params[def_wires[j].output_num] && !instance->workerlist[def_wires[j].end_worker].params[def_wires[j].input_num+1])
+				{
+					//DEBUGPRINTF( "add_ref on output %d\n", def_wires[j].output_num);
+					instance->workerlist[def_wires[j].end_worker].params[def_wires[j].input_num+1]=add_ref(params[def_wires[j].output_num]);
+					//DEBUGPRINTF("Ready count was: %d, ", instance->workerlist[def_wires[j].end_worker].ready_count);
+					++instance->workerlist[def_wires[j].end_worker].ready_count;
+					DEBUGPRINTF("Ready count is now: %d\n", instance->workerlist[def_wires[j].end_worker].ready_count);
+					DEBUGPRINTF("num inputs: %d, null input: %d\n", instance->def->implement_func->workerlist[def_wires[j].end_worker].num_inputs, instance->def->implement_func->workerlist[def_wires[j].end_worker].null_input);
+					if(instance->workerlist[def_wires[j].end_worker].ready_count >= (instance->def->implement_func->workerlist[def_wires[j].end_worker].num_inputs + (instance->def->implement_func->workerlist[def_wires[j].end_worker].null_input ? 1 : 0)))
+					{
+						//DEBUGPUTS("flag = true\n");
+						flag = TRUE;
+						instance->workerlist[def_wires[j].end_worker].ready_count=0;
+					}
+				}
+			VIS_LeaveCriticalSection(instance->workerlist[def_wires[j].end_worker].worker_lock);
+			if(flag)
+			{
+				DEBUGPUTS("add_queue\n");
+				add_queue(def_wires[j].end_worker, instance);
+				//add_if_ready(def_wires[j].end_worker, instance);
+				flag = FALSE;
+			}
+			++i;
+		}
+		//DEBUGPUTS("releasing refs\n");
+		
+		for(i = 0; i < def_workers[aworker].num_outputs; ++i)
+			release_ref(params[i]);
+	}
+	VIS_PROFILE_END(PROF_PROCESS_OUTPUTS);
+}
+
+void main_callback(worker_instance * junkinst, int junk, worker_instance * main_instance, void * data)
+{
+	//MessageBox(NULL, "Main Callback", "Visuality Debug", MB_OK);
+	VIS_EnterCriticalSection(program_count_lock);
+		--program_count;
+		if(program_count <= 0)
+		{
+			execute_active = FALSE;
+			VIS_SetEvent(queue_add_event);
+		}
+	VIS_LeaveCriticalSection(program_count_lock);
+	if(data)
+		release_ref((datum *)data);
+}
+
+void sub_callback(worker_instance * caller_instance, int caller_workernum, worker_instance * done_instance, void * data)
+{
+	int i;
+	queue_entry incaller;
+	datum * params[32];
+	worker_def * def = done_instance->def;
+	custom_worker * implement_func = def->implement_func;
+
+	incaller.worker_num = caller_workernum;
+	incaller.instance = caller_instance;
+	for(i = 0; i < def->num_outputs; ++i)
+		params[i] = NULL;
+	for(i = 0; i < implement_func->num_workers; ++i)
+	{
+		if(implement_func->workerlist[i].type == 4)
+		{
+			if(!params[implement_func->workerlist[i].io_num])
+			{
+				params[implement_func->workerlist[i].io_num] = done_instance->workerlist[i].value;
+				DEBUGPRINTF("Output[%d] = %X\n", implement_func->workerlist[i].io_num, done_instance->workerlist[i].value);
+				done_instance->workerlist[i].value = NULL;
+			}
+		}
+	}
+	process_outputs(params, caller_workernum, caller_instance);
+	//worker_complete(incaller);
+}
+
+void pack_list_sub_callback(worker_instance * caller_instance, int caller_workernum, worker_instance * done_instance, void * data)
+{
+	int i;
+	queue_entry incaller;
+	datum * params[32];
+	datum * workparams[2];
+	
+	incaller.worker_num = caller_workernum;
+	incaller.instance = caller_instance;
+	for(i = 0; i < done_instance->def->num_outputs; ++i)
+		params[i] = NULL;
+	for(i = 0; i < done_instance->def->implement_func->num_workers; ++i)
+	{
+		if(done_instance->def->implement_func->workerlist[i].type == 4)
+		{
+			if(!params[done_instance->def->implement_func->workerlist[i].io_num])
+			{
+				params[done_instance->def->implement_func->workerlist[i].io_num] = done_instance->workerlist[i].value;
+				done_instance->workerlist[i].value = NULL;
+			}
+		}
+	}
+	workparams[0] = create_list(done_instance->def->program);
+	for(i = 0; i < done_instance->def->num_outputs; ++i)
+	{
+		workparams[1] = params[i];
+		vis_list_append(workparams, NULL);
+	}
+	process_outputs(workparams, caller_workernum, caller_instance);
+	//worker_complete(incaller);
+}
+
+void transaction_sub_callback(worker_instance * caller_instance, int caller_workernum, worker_instance * done_instance, void * data)
+{
+	int i;
+	
+	pack_list_sub_callback(caller_instance, caller_workernum, done_instance, NULL);
+}
+
+int global_argc;
+char ** global_argv;
+int spin_counter;
+
+void prep_program(program * prog)
+{
+	defchunk * current;
+	int i,j;
+	make_lookup_arrays(prog);
+	current = prog->defs;
+	while(current)
+	{
+		for(i = 0; i < current->num_defs; ++i)
+		{
+			#ifdef USER_PROFILE
+				current->deflist[i].count = 0;
+				current->deflist[i].total.QuadPart = 0;
+				current->deflist[i].worst.QuadPart = 0;
+				VIS_InitializeCriticalSection(current->deflist[i].lock);
+			#endif // USER_PROFILE
+			//DEBUGPRINTF("Checking worker %s with type %X\n", current->deflist[i].name, current->deflist[i].type);
+			if(current->deflist[i].type & USER_FLAG && (current->deflist[i].type & TYPE_MASK) == WORKER_TYPE)
+			{
+				//DEBUGPRINTF("Checking for constants in worker %s\n", current->deflist[i].name);
+				for(j = 0; j < current->deflist[i].implement_func->num_workers; ++j)
+					if(current->deflist[i].implement_func->workerlist[j].type == CONSTANT)
+					{
+						//current->deflist[i].implement_func->workerlist[j].value_index = (int)(get_constant(current->deflist[i].implement_func->workerlist[j].name,-1, initial_prog));
+						//DEBUGPRINTF("Set value_index for constant to %X in worker %s at index %d\n", current->deflist[i].implement_func->workerlist[j].value_index, current->deflist[i].name, j); 
+					}
+					else if(current->deflist[i].implement_func->workerlist[j].type == WORKER || current->deflist[i].implement_func->workerlist[j].type == TAIL_CALL || current->deflist[i].implement_func->workerlist[j].type == TAIL_RECURSE)
+					{
+						current->deflist[i].implement_func->workerlist[j].num_inputs = ((worker_def *)current->deflist[i].implement_func->workerlist[j].value_index)->num_inputs;
+						current->deflist[i].implement_func->workerlist[j].num_outputs = ((worker_def *)current->deflist[i].implement_func->workerlist[j].value_index)->num_outputs;
+					}
+					else
+						current->deflist[i].implement_func->workerlist[j].value_index = 0;
+				//DEBUGPRINTF("optimize %d\n", i);
+			#ifdef ENABLE_OPT
+				optimize(current->deflist + i);
+			#endif
+			}
+		}
+		current = current->next;
+	}
+}
+
+void interp_start(int num_threads, BOOL use_this_thread, int argc, char ** argv, program * initial_prog)
+{
+	defchunk * current;
+	datum * params[2];
+	int i, junk,create_threads,j;
+	#ifdef USER_PROFILE
+		LARGE_INTEGER frequency;
+	#endif
+	lock_fail_counter = 0;
+	lock_counter = 0;
+	spin_counter = 0;
+	
+	#ifdef WIN32
+		//_CrtSetDbgFlag(_CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_CHECK_CRT_DF | _CRTDBG_ALLOC_MEM_DF);
+		WSAStartup(MAKEWORD(1, 1), &wsa_data);
+	#endif
+	VIS_InitializeCriticalSection(randlock);
+
+	DEBUGPUTS("interp_start\n");
+#ifdef ENABLE_PROFILING
+	for(i = 0; i < NUM_PROFS; ++i)
+	{
+		vis_profile_running_total[i] = 0;
+		vis_profile_counts[i] = 0;
+	}
+	VIS_PROFILE_START(PROF_EMPTYFUNC);
+	empty_test(NULL,NULL);
+	VIS_PROFILE_END(PROF_EMPTYFUNC);
+	VIS_PROFILE_START(PROF_NOCODE);
+	VIS_PROFILE_END(PROF_NOCODE);
+#endif
+	global_argc  = argc;
+	global_argv = argv;
+	init_sync_primitives();
+	init_datum_storage();
+	init_global_storage(initial_prog);
+	//init queue
+	current_section = &first_section;
+	DEBUGPRINTF("current_section = %X, &current_section = %X\n", current_section, &current_section);
+	worker_queue = current_section->entries;
+	current_section->last = NULL;
+	current_section->next = NULL;
+	queue_start = queue_len = 0;
+//	deflist[0].num_workers = num_workers;
+//	deflist[0].num_wires = num_wires;
+	prep_program(initial_prog);
+	//MessageBox(NULL, "Before fopen", "visdbg", MB_OK);
+	init_genrand(time(NULL));
+	
+	execute_active = TRUE;
+	DEBUGPUTS("Before init_custom_worker on Main\n");
+	params[0] = create_list(initial_prog);
+	for(i = 0; i < argc; ++i)
+	{
+		params[1] = make_string(argv[i], -1, initial_prog);
+		vis_list_append(params, NULL);
+	}
+	main_instance = init_custom_worker(-1, NULL, initial_prog->defs->deflist, main_callback, NULL, params);
+	
+	//num_datum = 0;
+	#if	COMPILE_THREADS > 0
+	create_threads = COMPILE_THREADS;
+	if(num_threads > 0)
+		create_threads = num_threads;
+	if(use_this_thread)
+		--create_threads;
+
+	for(i = 0; i < create_threads; ++i)
+	{
+		#ifdef WIN32
+			CreateThread(NULL, 0, worker_thread, NULL, 0, &junk);
+		#else
+		#ifdef SYLLABLE
+			resume_thread(spawn_thread("vis_worker", worker_thread, 1, 0, NULL));
+		#else
+			pthread_t pid;
+			pthread_create(&pid, NULL, worker_thread, NULL);
+		#endif
+		#endif
+	}
+	if(use_this_thread)
+		worker_thread(NULL);
+	#else
+		worker_thread(NULL);
+	#endif
+#ifdef ENABLE_PROFILING
+	for(i = 0; i < NUM_PROFS; ++i)
+		printf("%d:\t%f,\tcount: %d,\taverage: %f\n", i, (double)vis_profile_running_total[i], vis_profile_counts[i], ((double)vis_profile_running_total[i])/((double)vis_profile_counts[i]));
+#endif
+
+#ifdef USER_PROFILE
+	printf("%-33s%12s%7s%15s%12s\n\n", "Worker", "Total", "Count", "Average", "Worst");
+	current = initial_prog->defs;
+	while(current)
+	{
+		for(i = 0; i < current->num_defs; ++i)
+		{
+			if(current->deflist[i].count > 0)
+			{
+				printf("%-33s%12.0f%7d%15.2f%12.0f\n", current->deflist[i].name, (double)current->deflist[i].total.QuadPart, current->deflist[i].count, (double)current->deflist[i].total.QuadPart / (double)current->deflist[i].count, (double)current->deflist[i].worst.QuadPart);
+			}
+		}
+		current = current->next;
+	}
+	QueryPerformanceFrequency(&frequency);
+	printf("%.0f ticks per second\n", (double)frequency.QuadPart);
+#endif
+	interp_stop();
+}
+
+void interp_stop()
+{
+	int i;
+	execute_active = FALSE;
+	close_sync_primitives();
+//	Doesn't make sense in the context of multiple programs
+//	cleanup_custom_worker(main_instance);
+#ifdef WIN32
+	WSACleanup();
+#endif
+#ifdef TEXT_FILE_DEBUG
+	fclose(debugfile);
+#endif
+}
+	
+extern 
+void init_sync_primitives()
+{
+	int i;
+	DEBUGPUTS("Initializing data_lock\n");
+	VIS_InitializeCriticalSection(data_lock);
+	DEBUGPUTS("Initializing worker_queue_lock\n");
+	VIS_InitializeCriticalSection(worker_queue_lock);
+	DEBUGPUTS("Initializing text_buf_lock\n");
+	VIS_InitializeCriticalSection(text_buf_lock);
+#ifdef SYLLABLE
+	DEBUGPUTS("vis_window_init\n");
+	vis_window_init();
+#endif
+	VIS_CreateEvent(queue_add_event);//No security parameter, auto reset, starts signaled, no name
+	
+}
+
+void close_sync_primitives()
+{
+	int i;
+	VIS_DeleteCriticalSection(data_lock);
+	VIS_DeleteCriticalSection(worker_queue_lock);
+	VIS_DestroyEvent(queue_add_event);
+
+}
+
+void init_global_storage(program * prog)
+{
+	VIS_InitializeCriticalSection(global_store_lock);
+	global_store_dict = create_dict(prog);
+}
+
+void add_multiple(int * data, int num, worker_instance * instance)
+{
+	int i, index;
+	queue_section * temp;
+	DEBUGPRINTF( "Adding %d workers\n", num);
+	
+	VIS_EnterCriticalSection(instance->counter_lock);
+		instance->in_queue_count += num;
+	VIS_LeaveCriticalSection(instance->counter_lock);
+	VIS_EnterCriticalSection(worker_queue_lock);
+		for(i = 0; i < num; ++i)
+		{
+			if(queue_len >= QUEUE_SIZE)
+			{
+				if(current_section->next)
+				{
+					//DEBUGPUTS("Moving to next queue_section\n");
+					current_section = current_section->next;
+				}
+				else
+				{
+					//DEBUGPUTS("Allocating new queue_section\n");
+					VIS_PROFILE_START(PROF_ADDQUEUE_MALLOC);
+					temp = MALLOC(sizeof(queue_section),"queue section");
+					VIS_PROFILE_END(PROF_ADDQUEUE_MALLOC);
+					temp->last = current_section;
+					temp->next = NULL;
+					current_section->next = temp;
+					current_section = temp;
+				}
+				worker_queue = current_section->entries;
+				queue_start = queue_len = 0;
+			}
+			if(queue_start+queue_len < QUEUE_SIZE)
+				index = queue_start+queue_len;
+			else
+				index = queue_start+queue_len-QUEUE_SIZE;
+			worker_queue[index].worker_num=data[i];
+			worker_queue[index].instance = instance;
+			++queue_len;
+		}
+	VIS_LeaveCriticalSection(worker_queue_lock);
+	//DEBUGPUTS("SetEvent\n");
+	VIS_SetEvent(queue_add_event);
+}
+
+void requeue(int data, worker_instance * instance)
+{
+	add_queue(data, instance);
+	VIS_EnterCriticalSection(instance->counter_lock);
+		--(instance->in_progress_count);
+	VIS_LeaveCriticalSection(instance->counter_lock);
+}
+
+void add_queue(int data, worker_instance * instance)
+{
+	int index;
+	queue_section * temp;
+	VIS_PROFILE_START(PROF_ADDQUEUE);
+	VIS_EnterCriticalSection(instance->counter_lock);
+		++(instance->in_queue_count);
+	VIS_LeaveCriticalSection(instance->counter_lock);
+	VIS_EnterCriticalSection(worker_queue_lock);
+		if(queue_len >= QUEUE_SIZE)
+		{
+			if(current_section->next)
+			{
+				//DEBUGPUTS("Moving to next queue_section\n");
+				current_section = current_section->next;
+			}
+			else
+			{
+				//DEBUGPUTS("Allocating new queue_section\n");
+				VIS_PROFILE_START(PROF_ADDQUEUE_MALLOC);
+				temp = MALLOC(sizeof(queue_section),"queue section");
+				VIS_PROFILE_END(PROF_ADDQUEUE_MALLOC);
+				temp->last = current_section;
+				temp->next = NULL;
+				current_section->next = temp;
+				current_section = temp;
+			}
+			worker_queue = current_section->entries;
+			queue_start = queue_len = 0;
+		}
+		else if(queue_len == 0)
+		{
+			VIS_SetEvent(queue_add_event);
+			//DEBUGPUTS("SetEvent\n");
+		}
+			
+		if(queue_start+queue_len < QUEUE_SIZE)
+			index = queue_start+queue_len;
+		else
+			index = queue_start+queue_len-QUEUE_SIZE;
+		worker_queue[index].worker_num=data;
+		worker_queue[index].instance = instance;
+		++queue_len;
+		
+	VIS_LeaveCriticalSection(worker_queue_lock);
+	VIS_PROFILE_END(PROF_ADDQUEUE);
+}
+
+/**
+* Retrieves a ready worker from the queue
+*/
+queue_entry get_queue()
+{
+	queue_entry data;
+	queue_section * temp;
+	//DEBUGPUTS("Begin get_queue()\n");
+	
+	VIS_EnterCriticalSection(worker_queue_lock);
+		while(!queue_len && execute_active)
+		{
+			//DEBUGPUTS("Queue empty, resetting event\n");
+			VIS_ResetEvent(queue_add_event);
+			VIS_LeaveCriticalSection(worker_queue_lock);
+			//DEBUGPUTS("Waiting for queue_add_event\n");
+			VIS_WaitEvent(queue_add_event);
+#ifdef NINTENDO_DS
+			//TODO make the processor sleep while waiting for IRQs
+			if(irq_queue_count > 0)
+				run_queued_irqs();
+#endif
+			VIS_EnterCriticalSection(worker_queue_lock);
+		}
+		if(queue_len > 0)
+		{
+			data = worker_queue[queue_start];
+			//DEBUGPRINTF( "Next worker in queue: %d\n", data.worker_num);
+			//DEBUGPRINTF("data.instance: %X, data.instance->workerlist: %X\n", data.instance, data.instance->workerlist);
+			/*VIS_EnterCriticalSection(data.instance->workerlist[data.worker_num].worker_lock);
+				DEBUGPUTS("Adjusting ready_count");
+				data.instance->workerlist[data.worker_num].ready_count=0;
+			VIS_LeaveCriticalSection(data.instance->workerlist[data.worker_num].worker_lock);*/
+			++queue_start;
+			--queue_len;
+			//DEBUGPUTS("Adjusted ready count.\n");
+			//DEBUGPRINTF("current_section: %X\n", current_section);
+			if(queue_len == 0 && current_section->last)
+			{
+				if(current_section->next != NULL)
+				{
+					//DEBUGPUTS("Freeing current_section->next.\n");
+					VIS_FREE(current_section->next, "ready queue node");
+					current_section->next = NULL;
+				}
+				current_section = current_section->last;
+				worker_queue = current_section->entries;
+				queue_start = 0;
+				queue_len = QUEUE_SIZE;
+			}
+			else if(queue_start == QUEUE_SIZE)
+				queue_start = 0;
+		}
+		else
+		{
+			//DEBUGPUTS("Queue empty\n");
+			data.worker_num = -2;
+		}
+	VIS_LeaveCriticalSection(worker_queue_lock);
+	//DEBUGPUTS("Left worker_queue_lock\n");
+	//MessageBox(NULL,"AfterLeave","visdbg",MB_OK);
+	if(data.worker_num >= 0)
+	{
+		VIS_EnterCriticalSection(data.instance->counter_lock);
+			//DEBUGPUTS("Adjusting in_queue/in_progress counts.\n");
+			--(data.instance->in_queue_count);
+			++(data.instance->in_progress_count);
+			DEBUGPRINTF( "Counts for %s<%d> Instance:%X after get_queue: in_queue: %d in_progress: %d\n",data.instance->def->name, data.instance->worker_in_caller, data.instance, data.instance->in_queue_count, data.instance->in_progress_count);
+			
+		VIS_LeaveCriticalSection(data.instance->counter_lock);
+	}
+	//DEBUGPUTS("End get_queue()\n");
+	
+	return data;
+}
+
+void def_make_lookup(worker_def * def)
+{
+	int i, j, upoffset, offset;
+	VIS_EnterCriticalSection(def->implement_func->lock);
+		if(def->implement_func->dirty)
+		{
+			upoffset = offset = 0;
+			for(i = 0; i < def->implement_func->num_workers; ++i)
+			{
+				def->implement_func->workerlist[i].wire_down_lookup=offset;
+				def->implement_func->workerlist[i].wire_up_lookup=upoffset;
+				for(j = 0; j < def->implement_func->num_wires; ++j)
+				{
+					if(def->implement_func->wirelist[j].start_worker == i)
+						def->implement_func->workers_to_wires_down[offset++]=j;
+					if(def->implement_func->wirelist[j].end_worker == i)
+						def->implement_func->workers_to_wires_up[upoffset++]=j;
+				}
+				//Clear tail call info
+				if(def->implement_func->workerlist[i].type == TAIL_CALL || def->implement_func->workerlist[i].type == TAIL_RECURSE)
+					def->implement_func->workerlist[i].type = WORKER;
+			}
+			def->implement_func->workers_to_wires_down[offset]=-1;
+			def->implement_func->workers_to_wires_up[upoffset]=-1;
+			check_tail(def);
+			def->implement_func->dirty = FALSE;
+		}
+	VIS_LeaveCriticalSection(def->implement_func->lock);
+}
+
+/**
+* Generates lookup array to ease navigation between workers
+*/
+void make_lookup_arrays(program * prog)
+{
+	int i,j,k, offset, upoffset;
+	worker_def * deflist;
+	defchunk * current = prog->defs;
+	while(current)
+	{
+		deflist = current->deflist;
+		for(k = 0; k < current->num_defs; ++k)
+		{
+			if(deflist[k].type & USER_FLAG && (deflist[k].type & TYPE_MASK) == WORKER_TYPE)
+				def_make_lookup(deflist + k);
+		}
+		current = current->next;
+	}
+}
+extern char _end_bss[];
+void initpredefworkers(program * prog)
+{
+	int current_def = 1;
+	int current_company = 0;
+	int current_method;
+	int comp_room;
+	company * this_comp;
+	worker_def * aworker;
+	create_company(prog, "Any Type", 0, 0, FALSE);
+	create_company(prog, "Yes No", 0, 0, FALSE);
+	
+	aworker = create_worker(prog, "Print", 1, 1, WORKER_TYPE);
+	aworker->implement_func = (custom_worker *)vis_print;
+	aworker->input_types[0] = BUILTIN_TYPE_STRING;
+	
+	aworker = create_worker(prog, "Random", 0, 1, WORKER_TYPE);
+	aworker->implement_func = (custom_worker *)vis_random;
+	
+	aworker = create_worker(prog, "Build", 1, 1, WORKER_TYPE);
+	aworker->implement_func = (custom_worker *)vis_build;
+	aworker->input_types[0] = BUILTIN_TYPE_STRING;
+
+	aworker = create_worker(prog, "End", 1, 0, WORKER_TYPE);
+	aworker->implement_func = (custom_worker *)vis_end;
+	aworker->input_types[0] = ANY_TYPE;
+	
+	create_worker(prog, "Append", 2, 1, MAGIC_TYPE);
+	create_worker(prog, "+", 2, 1, MAGIC_TYPE);
+	create_worker(prog, "-", 2, 1, MAGIC_TYPE);
+	create_worker(prog, "*", 2, 1, MAGIC_TYPE);
+	create_worker(prog, "/", 2, 1, MAGIC_TYPE);
+	create_worker(prog, ">", 2, 1, MAGIC_TYPE);
+	create_worker(prog, "<", 2, 1, MAGIC_TYPE);
+	create_worker(prog, "=", 2, 1, MAGIC_TYPE);
+
+	aworker = create_worker(prog, "Get Input", 0, 1, WORKER_TYPE);
+	aworker->implement_func = (custom_worker *)vis_getinput;
+	
+	aworker = create_worker(prog, "If",1, 2, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_if;
+	aworker->input_types[0] = BUILTIN_TYPE_YESNO;
+	
+	aworker = create_worker(prog, "Type Of",1, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_type_of;
+	aworker->input_types[0] = ANY_TYPE;
+	
+	aworker = create_worker(prog, "Init Store",1, 0, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)init_global_store;
+	aworker->input_types[0] = BUILTIN_TYPE_STRING;
+	
+	aworker = create_worker(prog, "Wait Forever", 0, 0, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_wait_forever;
+
+#ifdef NINTENDO_DS
+	aworker = create_worker(prog, "Register Handler", 2, 1, WORKER_TYPE);
+	aworker->implement_func = (custom_worker *)vis_register_handler;
+	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
+	aworker->input_types[1] = BUILTIN_TYPE_WORKER;
+
+	aworker = create_worker(prog, "Clear Handler", 1, 1, WORKER_TYPE);
+	aworker->implement_func = (custom_worker *)vis_clear_handler;
+	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
+
+	aworker = create_worker(prog, "Held Keys", 0, 1, WORKER_TYPE);
+	aworker->implement_func = (custom_worker *)vis_held_keys;
+
+	aworker = create_worker(prog, "Touch Position", 0, 2, WORKER_TYPE);
+	aworker->implement_func = (custom_worker *)vis_touch_position;
+#endif
+	
+	current_method = 0;
+	//strcpy(companylist[current_company].name, "String");
+#ifdef SEGA
+	this_comp = create_company(prog, "String", 6, 0, FALSE);
+#else
+	this_comp = create_company(prog, "String", 7, 0, FALSE);
+#endif
+	aworker = create_worker(prog, "<Whole Number@String",1, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_inttostring;
+	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
+	//add_method(this_comp, aworker);
+
+#ifndef SEGA
+	
+	aworker = create_worker(prog, "<Real Number@String",1, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_realtostring;
+	aworker->input_types[0] = BUILTIN_TYPE_REAL;
+	//add_method(this_comp, aworker);
+#endif
+	
+	aworker = create_worker(prog, "=@String",2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_stringequal;
+	aworker->input_types[0] = BUILTIN_TYPE_STRING;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "<Yes No@String",1, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_yesnotostring;
+	aworker->input_types[0] = BUILTIN_TYPE_YESNO;
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, ">@String",2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_greaterstring;
+	aworker->input_types[0] = BUILTIN_TYPE_STRING;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "<@String",2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_lesserstring;
+	aworker->input_types[0] = BUILTIN_TYPE_STRING;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "Append@String",2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_append;
+	aworker->input_types[0] = BUILTIN_TYPE_STRING;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "Split@String",2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_string_split;
+	aworker->input_types[0] = BUILTIN_TYPE_STRING;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+	
+	aworker = create_worker(prog, "Get Raw@String",2, 2, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_string_get_raw;
+	aworker->input_types[0] = BUILTIN_TYPE_STRING;
+	aworker->input_types[1] = ANY_TYPE;
+	
+	aworker = create_worker(prog, "Put Raw@String",2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_string_put_raw;
+	aworker->input_types[0] = BUILTIN_TYPE_STRING;
+	aworker->input_types[1] = ANY_TYPE;
+
+	aworker = create_worker(prog, "Slice@String",2, 2, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_string_slice;
+	aworker->input_types[0] = BUILTIN_TYPE_STRING;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+
+	aworker = create_worker(prog, "Reverse@String",1, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_string_reverse;
+	aworker->input_types[0] = BUILTIN_TYPE_STRING;
+	
+	aworker = create_worker(prog, "Length@String",1, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_string_length;
+	aworker->input_types[0] = BUILTIN_TYPE_STRING;
+	
+	aworker = create_worker(prog, "Put Byte@String",2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_string_put_byte;
+	aworker->input_types[0] = BUILTIN_TYPE_STRING;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+	
+	aworker = create_worker(prog, "Get DString@String",2, 4, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_string_get_dstring;
+	aworker->input_types[0] = BUILTIN_TYPE_STRING;
+	aworker->input_types[1] = ANY_TYPE;
+	
+	current_method = 0;
+	this_comp = create_company(prog, "Whole Number", 6, 0, FALSE);
+	aworker = create_worker(prog, "<String@Whole Number",1, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_stringtoint;
+	aworker->input_types[0] = BUILTIN_TYPE_STRING;
+	
+	aworker = create_worker(prog, "From Hex@Whole Number",1, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_whole_fromhex;
+	aworker->input_types[0] = BUILTIN_TYPE_STRING;
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "=@Whole Number",2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_wholeequal;
+	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, ">@Whole Number",2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_greaterint;
+	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "<@Whole Number",2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_lesserint;
+	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "+@Whole Number", 2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_whole_add;
+	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "-@Whole Number", 2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_whole_subtract;
+	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+	
+	aworker = create_worker(prog, "*@Whole Number", 2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_whole_mult;
+	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "/@Whole Number", 2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_whole_div;
+	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+
+	aworker = create_worker(prog, "&@Whole Number", 2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_whole_and;
+	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+
+	aworker = create_worker(prog, "|@Whole Number", 2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_whole_or;
+	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+
+	aworker = create_worker(prog, "LShift@Whole Number", 2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_whole_lsh;
+	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+
+	aworker = create_worker(prog, "RShift@Whole Number", 2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_whole_rsh;
+	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+
+	//add_method(this_comp, aworker);
+	
+	current_method = 0;
+	this_comp = create_company(prog, "Real Number", 6, 0, FALSE);//<string, =, >, <, +, -
+	aworker = create_worker(prog, "<String@Real Number", 1, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_stringtoreal;
+	aworker->input_types[0] = BUILTIN_TYPE_STRING;
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "=@Real Number", 2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_realequal;
+	aworker->input_types[0] = BUILTIN_TYPE_REAL;
+	aworker->input_types[1] = BUILTIN_TYPE_REAL;
+
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, ">@Real Number", 2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_greaterreal;
+	aworker->input_types[0] = BUILTIN_TYPE_REAL;
+	aworker->input_types[1] = BUILTIN_TYPE_REAL;
+
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "<@Real Number", 2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_lesserreal;
+	aworker->input_types[0] = BUILTIN_TYPE_REAL;
+	aworker->input_types[1] = BUILTIN_TYPE_REAL;
+
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "+@Real Number", 2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_real_add;
+	aworker->input_types[0] = BUILTIN_TYPE_REAL;
+	aworker->input_types[1] = BUILTIN_TYPE_REAL;
+
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "-@Real Number", 2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_real_subtract;
+	aworker->input_types[0] = BUILTIN_TYPE_REAL;
+	aworker->input_types[1] = BUILTIN_TYPE_REAL;
+	
+	aworker = create_worker(prog, "/@Real Number", 2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_real_div;
+	aworker->input_types[0] = BUILTIN_TYPE_REAL;
+	aworker->input_types[1] = BUILTIN_TYPE_REAL;
+
+	//add_method(this_comp, aworker);
+	
+	current_method = 0;
+	this_comp = create_company(prog, "List", 7, 1, FALSE);//Index, Append, Swap, Insert, Remove, Set, Length, New
+	comp_room = add_comp_room(this_comp, "Length", 0, 0, ROOM_NO_ACCESS, ROOM_LONG);
+	
+	aworker = create_worker(prog, "Index@List", 2, 2, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_list_index;
+	aworker->input_types[0] = BUILTIN_TYPE_LIST;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "Append@List", 2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_list_append;
+	aworker->input_types[0] = BUILTIN_TYPE_LIST;
+	aworker->input_types[1] = ANY_TYPE;
+
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "Swap@List",3, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_list_swap;
+	aworker->input_types[0] = BUILTIN_TYPE_LIST;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+	aworker->input_types[2] = BUILTIN_TYPE_WHOLE;
+
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "Insert@List",3, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_list_insert;
+	aworker->input_types[0] = BUILTIN_TYPE_LIST;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+	aworker->input_types[2] = ANY_TYPE;
+
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "Remove@List", 2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_list_remove;
+	aworker->input_types[0] = BUILTIN_TYPE_LIST;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "Set@List",3, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_list_set;
+	aworker->input_types[0] = BUILTIN_TYPE_LIST;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+	aworker->input_types[2] = ANY_TYPE;
+
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "Length@List", 1, 1, WORKER_TYPE);
+	aworker->implement_func = (custom_worker *)vis_list_length;
+	aworker->input_types[0] = BUILTIN_TYPE_LIST;
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "New@List",0, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_list_new;
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "First@List", 1, 2, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_list_first;
+	aworker->input_types[0] = BUILTIN_TYPE_LIST;
+	
+	aworker = create_worker(prog, "Next@List", 2, 2, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_list_next;
+	aworker->input_types[0] = BUILTIN_TYPE_LIST;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+	
+	current_method = 0;
+	this_comp = create_company(prog, "Dictionary", 5, 0, FALSE);//Index, Swap, Remove, Set, Length, New
+	aworker = create_worker(prog, "Index@Dictionary", 2, 2, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_dict_index;
+	aworker->input_types[0] = BUILTIN_TYPE_DICT;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "Swap@Dictionary",3, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_dict_swap;
+	aworker->input_types[0] = BUILTIN_TYPE_DICT;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+	aworker->input_types[2] = BUILTIN_TYPE_STRING;
+
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "Remove@Dictionary", 2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_dict_remove;
+	aworker->input_types[0] = BUILTIN_TYPE_DICT;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "Set@Dictionary",3, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_dict_set;
+	aworker->input_types[0] = BUILTIN_TYPE_DICT;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+	aworker->input_types[2] = ANY_TYPE;
+	
+	aworker = create_worker(prog, "Length@Dictionary", 1, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_dict_length;
+	aworker->input_types[0] = BUILTIN_TYPE_DICT;
+
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "New@Dictionary",0, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_dict_new;
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "First@Dictionary", 1, 2, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_dict_first;
+	aworker->input_types[0] = BUILTIN_TYPE_DICT;
+	
+	aworker = create_worker(prog, "Next@Dictionary", 2, 2, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_dict_next;
+	aworker->input_types[0] = BUILTIN_TYPE_DICT;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+
+	current_method = 0;
+#ifdef SEGA
+	this_comp = create_company(prog, "File", 0, 0, FALSE);
+#else
+	
+	this_comp = create_company(prog, "File", 7, 0, FALSE);//<String, Get FString, Get DString, Get Byte, Get Word, Get Long, Put String
+	aworker = create_worker(prog, "<String@File", 1, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_file_from_string;
+	aworker->input_types[0] = BUILTIN_TYPE_STRING;
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "Get FString@File", 2, 2, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_file_get_fstring;
+	aworker->input_types[0] = BUILTIN_TYPE_FILE;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "Get DString@File", 2, 4, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_file_get_dstring;
+	aworker->input_types[0] = BUILTIN_TYPE_FILE;
+	aworker->input_types[1] = ANY_TYPE;
+
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "Get Byte@File", 1, 3, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_file_get_byte;
+	aworker->input_types[0] = BUILTIN_TYPE_FILE;
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "Get Word@File", 1, 3, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_file_get_word;
+	aworker->input_types[0] = BUILTIN_TYPE_FILE;
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "Get Long@File", 1, 3, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_file_get_long;
+	aworker->input_types[0] = BUILTIN_TYPE_FILE;
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "Put String@File", 2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_file_put_string;
+	aworker->input_types[0] = BUILTIN_TYPE_FILE;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+	
+	aworker = create_worker(prog, "Length@File", 1, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_file_length;
+	aworker->input_types[0] = BUILTIN_TYPE_FILE;
+
+	//add_method(this_comp, aworker);
+#endif
+	
+	current_method = 0;
+	
+	this_comp = create_company(prog, "Worker", 3, 0, FALSE);//<String, Do, Later: methods for manipulating 
+	
+	aworker = create_worker(prog, "<String@Worker", 1, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_worker_from_string;
+	aworker->input_types[0] = BUILTIN_TYPE_STRING;
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "Do@Worker", 2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_worker_do;
+	aworker->input_types[0] = BUILTIN_TYPE_WORKER;
+	aworker->input_types[1] = BUILTIN_TYPE_LIST;
+	
+	aworker = create_worker(prog, "Set Input@Worker", 3, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_worker_setinput;
+	aworker->input_types[0] = BUILTIN_TYPE_WORKER;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+	aworker->input_types[2] = ANY_TYPE;
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "Add Worker Call@Worker", 2, 2, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_worker_add_worker_call;
+	aworker->input_types[0] = BUILTIN_TYPE_WORKER;
+	aworker->input_types[1] = BUILTIN_TYPE_WORKER;
+	
+	aworker = create_worker(prog, "Add Wire@Worker", 5, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_worker_add_wire;
+	aworker->input_types[0] = BUILTIN_TYPE_WORKER;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+	aworker->input_types[2] = BUILTIN_TYPE_WHOLE;
+	aworker->input_types[3] = BUILTIN_TYPE_WHOLE;
+	aworker->input_types[4] = BUILTIN_TYPE_WHOLE;
+	
+	aworker = create_worker(prog, "Add Constant@Worker", 2, 2, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_worker_add_constant;
+	aworker->input_types[0] = BUILTIN_TYPE_WORKER;
+	aworker->input_types[1] = ANY_TYPE;
+	
+	aworker = create_worker(prog, "Add Input@Worker", 3, 2, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_worker_add_input;
+	aworker->input_types[0] = BUILTIN_TYPE_WORKER;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+	aworker->input_types[2] = BUILTIN_TYPE_WHOLE;
+	
+	aworker = create_worker(prog, "Add Output@Worker", 3, 2, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_worker_add_output;
+	aworker->input_types[0] = BUILTIN_TYPE_WORKER;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+	aworker->input_types[2] = BUILTIN_TYPE_WHOLE;
+	
+	aworker = create_worker(prog, "Add Object Get@Worker", 2, 2, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_worker_add_objectget;
+	aworker->input_types[0] = BUILTIN_TYPE_WORKER;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+	
+	aworker = create_worker(prog, "Add Object Set@Worker", 2, 2, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_worker_add_objectset;
+	aworker->input_types[0] = BUILTIN_TYPE_WORKER;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+	
+	aworker = create_worker(prog, "Add Global Get@Worker", 3, 2, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_worker_add_globalget;
+	aworker->input_types[0] = BUILTIN_TYPE_WORKER;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+	aworker->input_types[2] = BUILTIN_TYPE_STRING;
+	
+	aworker = create_worker(prog, "Add Global Set@Worker", 3, 2, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_worker_add_globalset;
+	aworker->input_types[0] = BUILTIN_TYPE_WORKER;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+	aworker->input_types[2] = BUILTIN_TYPE_STRING;
+	
+	aworker = create_worker(prog, "Clear@Worker", 1, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_worker_clear;
+	aworker->input_types[0] = BUILTIN_TYPE_WORKER;
+	
+	aworker = create_worker(prog, "Uses@Worker", 2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_worker_uses;
+	aworker->input_types[0] = BUILTIN_TYPE_WORKER;
+	aworker->input_types[1] = BUILTIN_TYPE_LIST;
+	
+	aworker = create_worker(prog, "Set IO Counts@Worker", 3, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_worker_setio_counts;
+	aworker->input_types[0] = BUILTIN_TYPE_WORKER;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+	aworker->input_types[2] = BUILTIN_TYPE_WHOLE;
+	
+	aworker = create_worker(prog, "New@Worker", 1, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_worker_new;
+	aworker->input_types[0] = BUILTIN_TYPE_STRING;
+	
+#ifdef GUI_LIB
+	current_method = 0;
+	
+	this_comp = create_company(prog, "Window", 3, 0, FALSE);
+	
+	aworker = create_worker(prog, "New@Window", 3, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_window_new;
+	aworker->input_types[0] = BUILTIN_TYPE_STRING;
+	aworker->input_types[1] = BUILTIN_TYPE_REAL;
+	aworker->input_types[2] = BUILTIN_TYPE_REAL;
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "Add Widget@Window", 5, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_window_add_widget;
+	aworker->input_types[0] = BUILTIN_TYPE_WINDOW;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+	aworker->input_types[2] = ANY_TYPE;
+	aworker->input_types[3] = BUILTIN_TYPE_REAL;
+	aworker->input_types[4] = BUILTIN_TYPE_REAL;
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "Show@Window", 3, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_window_show;
+	aworker->input_types[0] = BUILTIN_TYPE_WINDOW;
+	aworker->input_types[1] = BUILTIN_TYPE_REAL;
+	aworker->input_types[2] = BUILTIN_TYPE_REAL;
+	//add_method(this_comp, aworker);
+	
+	current_method = 0;
+	this_comp = create_company(prog, "Screen Window", 3, 0, FALSE);
+	
+	aworker = create_worker(prog, "Get Value@Screen Window", 2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_window_get_value;
+	aworker->input_types[0] = BUILTIN_TYPE_WINDOW_SHOWN;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "Set Value@Screen Window", 3, 0, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_window_set_value;
+	aworker->input_types[0] = BUILTIN_TYPE_WINDOW_SHOWN;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+#ifdef SYLLABLE
+	aworker->input_types[2] = ANY_TYPE;
+#else
+	aworker->input_types[2] = BUILTIN_TYPE_STRING;
+#endif
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "Wait Close@Screen Window", 1, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_window_wait_close;
+	aworker->input_types[0] = BUILTIN_TYPE_WINDOW_SHOWN;
+	//add_method(this_comp, aworker);
+
+#ifdef SYLLABLE
+	aworker = create_worker(prog, "Add Widget@Screen Window", 5, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_window_shown_addwidget;
+	aworker->input_types[0] = BUILTIN_TYPE_WINDOW_SHOWN;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+	aworker->input_types[2] = ANY_TYPE;
+	aworker->input_types[3] = BUILTIN_TYPE_REAL;
+	aworker->input_types[4] = BUILTIN_TYPE_REAL;
+#endif
+	
+	current_method = 0;
+	create_company(prog, "Button", 2, 0, FALSE);
+	
+	aworker = create_worker(prog, "New@Button", 3, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_button_new;
+	aworker->input_types[0] = BUILTIN_TYPE_STRING;
+	aworker->input_types[1] = BUILTIN_TYPE_REAL;
+	aworker->input_types[2] = BUILTIN_TYPE_REAL;
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "Set Handler@Button", 3, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_button_set_handler;
+	aworker->input_types[0] = BUILTIN_TYPE_BUTTON;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+	aworker->input_types[2] = BUILTIN_TYPE_WORKER;
+	//add_method(this_comp, aworker);
+	
+	current_method = 0;
+	create_company(prog, "Input Box", 2, 0, FALSE);
+		
+	aworker = create_worker(prog, "New@Input Box", 3, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_inputbox_new;
+	aworker->input_types[0] = BUILTIN_TYPE_STRING;
+	aworker->input_types[1] = BUILTIN_TYPE_REAL;
+	aworker->input_types[2] = BUILTIN_TYPE_REAL;
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "Set Type@Input Box", 2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_inputbox_settype;
+	aworker->input_types[0] = BUILTIN_TYPE_INPUTBOX;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+	//add_method(this_comp, aworker);
+	
+#endif
+#ifndef NO_NET
+	this_comp = create_company(prog, "Net Client", 3, 0, FALSE);
+	aworker = create_worker(prog, "New@Net Client", 2, 1, WORKER_TYPE);
+	aworker->implement_func =(custom_worker *)net_client_new;
+	aworker->input_types[0] = BUILTIN_TYPE_STRING;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+	
+	aworker = create_worker(prog, "Put String@Net Client", 2, 2, WORKER_TYPE);
+	aworker->implement_func = (custom_worker *)net_client_put_string;
+	aworker->input_types[0] = BUILTIN_TYPE_NETCLIENT;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+	
+	aworker = create_worker(prog, "Get FString@Net Client", 2, 3, WORKER_TYPE);
+	aworker->implement_func = (custom_worker *)net_client_get_fstring;
+	aworker->input_types[0] = BUILTIN_TYPE_NETCLIENT;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+	
+	aworker = create_worker(prog, "Get DString@Net Client", 2, 4, WORKER_TYPE);
+	aworker->implement_func = (custom_worker *)net_client_get_dstring;
+	aworker->input_types[0] = BUILTIN_TYPE_NETCLIENT;
+	aworker->input_types[1] = ANY_TYPE;
+	
+	aworker = create_worker(prog, "Put Raw@Net Client", 2, 2, WORKER_TYPE);
+	aworker->implement_func = (custom_worker *)net_client_put_raw;
+	aworker->input_types[0] = BUILTIN_TYPE_NETCLIENT;
+	aworker->input_types[1] = ANY_TYPE;
+	
+	aworker = create_worker(prog, "Get Raw@Net Client", 2, 3, WORKER_TYPE);
+	aworker->implement_func = (custom_worker *)net_client_get_raw;
+	aworker->input_types[0] = BUILTIN_TYPE_NETCLIENT;
+	aworker->input_types[1] = ANY_TYPE;
+	
+	aworker = create_worker(prog, "Listen on Port", 2, 0, WORKER_TYPE);
+	aworker->implement_func = (custom_worker *)vis_net_listenport;
+	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
+	aworker->input_types[1] = BUILTIN_TYPE_WORKER;
+#endif
+
+	create_company(prog, "Global Store", 0, 0, FALSE);
+	
+	create_company(prog, "Program", 5, 0, FALSE);
+	
+	aworker = create_worker(prog, "New@Program", 0, 1, WORKER_TYPE);
+	aworker->implement_func = (custom_worker *)vis_program_new;
+	
+	aworker = create_worker(prog, "New Worker@Program", 2, 2, WORKER_TYPE);
+	aworker->implement_func = (custom_worker *)vis_program_new_worker;
+	aworker->input_types[0] = BUILTIN_TYPE_PROGRAM;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+	
+	aworker = create_worker(prog, "Add Worker@Program", 2, 2, WORKER_TYPE);
+	aworker->implement_func = (custom_worker *)vis_program_add_worker;
+	aworker->input_types[0] = BUILTIN_TYPE_PROGRAM;
+	aworker->input_types[1] = BUILTIN_TYPE_WORKER;
+	
+	aworker = create_worker(prog, "Add Builtins@Program", 1, 1, WORKER_TYPE);
+	aworker->implement_func = (custom_worker *)vis_program_add_builtins;
+	aworker->input_types[0] = BUILTIN_TYPE_PROGRAM;
+	
+	aworker = create_worker(prog, "Run@Program", 2, 1, WORKER_TYPE);
+	aworker->implement_func = (custom_worker *)vis_program_run;
+	aworker->input_types[0] = BUILTIN_TYPE_PROGRAM;
+	aworker->input_types[1] = ANY_TYPE;
+	
+	aworker = create_worker(prog, "Find Worker@Program", 2, 2, WORKER_TYPE);
+	aworker->implement_func = (custom_worker *)vis_program_find_worker;
+	aworker->input_types[0] = BUILTIN_TYPE_PROGRAM;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+
+#ifdef GUI_LIB
+#ifdef SYLLABLE
+	create_company(prog, "Custom Widget", 2, 0, FALSE);
+	
+	aworker = create_worker(prog, "New@Custom Widget", 3, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_customwidget_new;
+	aworker->input_types[0] = BUILTIN_TYPE_STRING;
+	aworker->input_types[1] = BUILTIN_TYPE_REAL;
+	aworker->input_types[2] = BUILTIN_TYPE_REAL;
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "Set Handler@Custom Widget", 3, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_button_set_handler;
+	aworker->input_types[0] = BUILTIN_TYPE_CUSTOM_WIDGET;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+	aworker->input_types[2] = BUILTIN_TYPE_WORKER;
+	//add_method(this_comp, aworker);
+	
+	create_company(prog, "Screen Custom Widget", 3, 0, FALSE);
+	
+	aworker = create_worker(prog, "Default Draw@Screen Custom Widget", 1, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_screen_custom_defaultpaint;
+	aworker->input_types[0] = BUILTIN_TYPE_SCREEN_CUSTOM;
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "Draw Line@Screen Custom Widget", 5, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_screen_custom_drawline;
+	aworker->input_types[0] = BUILTIN_TYPE_SCREEN_CUSTOM;
+	aworker->input_types[1] = BUILTIN_TYPE_REAL;
+	aworker->input_types[2] = BUILTIN_TYPE_REAL;
+	aworker->input_types[3] = BUILTIN_TYPE_REAL;
+	aworker->input_types[4] = BUILTIN_TYPE_REAL;
+	//add_method(this_comp, aworker);
+	
+	aworker = create_worker(prog, "Draw String@Screen Custom Widget", 4, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_screen_custom_drawstring;
+	aworker->input_types[0] = BUILTIN_TYPE_SCREEN_CUSTOM;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+	aworker->input_types[2] = BUILTIN_TYPE_REAL;
+	aworker->input_types[3] = BUILTIN_TYPE_REAL;
+	
+	aworker = create_worker(prog, "Set Draw Color@Screen Custom Widget", 5, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_screen_custom_setdrawcolor;
+	aworker->input_types[0] = BUILTIN_TYPE_SCREEN_CUSTOM;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+	aworker->input_types[2] = BUILTIN_TYPE_WHOLE;
+	aworker->input_types[3] = BUILTIN_TYPE_WHOLE;
+	aworker->input_types[4] = BUILTIN_TYPE_WHOLE;
+	
+	aworker = create_worker(prog, "Move By@Screen Custom Widget", 3, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_screen_custom_moveby;
+	aworker->input_types[0] = BUILTIN_TYPE_SCREEN_CUSTOM;
+	aworker->input_types[1] = BUILTIN_TYPE_REAL;
+	aworker->input_types[2] = BUILTIN_TYPE_REAL;
+	
+	aworker = create_worker(prog, "Set Handler@Screen Custom Widget", 3, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_screen_custom_sethandler;
+	aworker->input_types[0] = BUILTIN_TYPE_SCREEN_CUSTOM;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+	aworker->input_types[2] = BUILTIN_TYPE_WORKER;
+	
+	aworker = create_worker(prog, "Remove Handler@Screen Custom Widget", 2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_screen_custom_removehandler;
+	aworker->input_types[0] = BUILTIN_TYPE_SCREEN_CUSTOM;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+	
+	aworker = create_worker(prog, "Give Focus@Screen Custom Widget", 2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_screen_custom_givefocus;
+	aworker->input_types[0] = BUILTIN_TYPE_SCREEN_CUSTOM;
+	aworker->input_types[1] = BUILTIN_TYPE_YESNO;
+	
+	aworker = create_worker(prog, "Add Widget@Screen Custom Widget", 5, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_screen_custom_addwidget;
+	aworker->input_types[0] = BUILTIN_TYPE_SCREEN_CUSTOM;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+	aworker->input_types[2] = ANY_TYPE;
+	aworker->input_types[3] = BUILTIN_TYPE_REAL;
+	aworker->input_types[4] = BUILTIN_TYPE_REAL;
+	
+#endif
+#endif
+	create_company(prog, "Buffer", 7, 0, FALSE);
+	
+	aworker = create_worker(prog, "New@Buffer", 1, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_buffer_new;
+	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
+	
+	aworker = create_worker(prog, "Lock@Buffer", 1, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_buffer_lock;
+	aworker->input_types[0] = BUILTIN_TYPE_BUFFER;
+	
+	aworker = create_worker(prog, "Unlock@Buffer", 1, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_buffer_unlock;
+	aworker->input_types[0] = BUILTIN_TYPE_BUFFER;
+	
+	aworker = create_worker(prog, "Put Byte@Buffer", 2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_buffer_putbyte;
+	aworker->input_types[0] = BUILTIN_TYPE_BUFFER;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+	
+	aworker = create_worker(prog, "Write Byte@Buffer", 2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_buffer_writebyte;
+	aworker->input_types[0] = BUILTIN_TYPE_BUFFER;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+	
+	aworker = create_worker(prog, "Put Word@Buffer", 2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_buffer_putshort;
+	aworker->input_types[0] = BUILTIN_TYPE_BUFFER;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+	
+	aworker = create_worker(prog, "Write Word@Buffer", 2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_buffer_writeshort;
+	aworker->input_types[0] = BUILTIN_TYPE_BUFFER;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+	
+	aworker = create_worker(prog, "Put Long@Buffer", 2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_buffer_putlong;
+	aworker->input_types[0] = BUILTIN_TYPE_BUFFER;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+	
+	aworker = create_worker(prog, "Write Long@Buffer", 2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_buffer_writelong;
+	aworker->input_types[0] = BUILTIN_TYPE_BUFFER;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+	
+	aworker = create_worker(prog, "Reset@Buffer", 1, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_buffer_reset;
+	aworker->input_types[0] = BUILTIN_TYPE_BUFFER;
+	
+#if defined(SEGA) || defined(NINTENDO_DS)
+
+	aworker = create_worker(prog, "From Address@Buffer", 2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_buffer_fromaddress;
+	aworker->input_types[0] = BUILTIN_TYPE_WHOLE;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+#endif //SEGA
+
+	create_company(prog, "Blueprint", 4, 0, FALSE);
+	
+	aworker = create_worker(prog, "New@Blueprint", 1, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_blueprint_new;
+	aworker->input_types[0] = BUILTIN_TYPE_STRING;
+	
+	aworker = create_worker(prog, "Add Field@Blueprint", 3, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_blueprint_addfield;
+	aworker->input_types[0] = BUILTIN_TYPE_BLUEPRINT;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+	aworker->input_types[2] = BUILTIN_TYPE_STRING;
+	
+	aworker = create_worker(prog, "Name@Blueprint", 1, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_blueprint_name;
+	aworker->input_types[0] = BUILTIN_TYPE_BLUEPRINT;
+	
+	aworker = create_worker(prog, "Get Fields@Blueprint", 1, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_blueprint_getfields;
+	aworker->input_types[0] = BUILTIN_TYPE_BLUEPRINT;
+	
+	aworker = create_worker(prog, "Blueprint Of", 1, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_get_blueprint;
+	aworker->input_types[0] = ANY_TYPE;
+	
+	aworker = create_worker(prog, "Get Field", 2, 2, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_get_field;
+	aworker->input_types[0] = ANY_TYPE;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+	
+	aworker = create_worker(prog, "Set Field", 3, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_set_field;
+	aworker->input_types[0] = ANY_TYPE;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+	aworker->input_types[2] = ANY_TYPE;
+	
+	aworker = create_worker(prog, "New Blueprint@Program", 2, 2, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_program_newblueprint;
+	aworker->input_types[0] = BUILTIN_TYPE_PROGRAM;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+
+#ifdef SYLLABLE
+	create_company(prog, "Checkbox", 2, 0, FALSE);
+
+	aworker = create_worker(prog, "New@Checkbox", 4, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_checkbox_new;
+	aworker->input_types[0] = BUILTIN_TYPE_STRING;
+	aworker->input_types[1] = BUILTIN_TYPE_REAL;
+	aworker->input_types[2] = BUILTIN_TYPE_REAL;
+	aworker->input_types[3] = BUILTIN_TYPE_YESNO;
+
+	aworker = create_worker(prog, "Set Handler@Checkbox", 3, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_button_set_handler;
+	aworker->input_types[0] = BUILTIN_TYPE_CHECKBOX;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+	aworker->input_types[2] = BUILTIN_TYPE_WORKER;
+
+	create_company(prog, "Dropdown", 4, 0, FALSE);
+
+	aworker = create_worker(prog, "New@Dropdown", 3, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_dropdown_new;
+	aworker->input_types[0] = BUILTIN_TYPE_LIST;
+	aworker->input_types[1] = BUILTIN_TYPE_REAL;
+	aworker->input_types[2] = BUILTIN_TYPE_REAL;
+
+	aworker = create_worker(prog, "Set Handler@Dropdown", 3, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_button_set_handler;
+	aworker->input_types[0] = BUILTIN_TYPE_DROPDOWN;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+	aworker->input_types[2] = BUILTIN_TYPE_WORKER;
+
+	aworker = create_worker(prog, "Set Text@Dropdown", 2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_dropdown_settext;
+	aworker->input_types[0] = BUILTIN_TYPE_DROPDOWN;
+	aworker->input_types[1] = BUILTIN_TYPE_STRING;
+
+	aworker = create_worker(prog, "Select@Dropdown", 2, 1, WORKER_TYPE);
+	aworker->implement_func=(custom_worker *)vis_dropdown_select;
+	aworker->input_types[0] = BUILTIN_TYPE_DROPDOWN;
+	aworker->input_types[1] = BUILTIN_TYPE_WHOLE;
+#endif
+
+	/*if(current_def > num_defs)
+		num_defs = current_def;
+	if(current_company > num_companies)
+		num_companies = current_company;*/
+}
+
+void initworkers(program * prog)
+{
+	//num_defs=0;
+	//num_companies=0;
+	create_worker(prog, "Main", 0, 0, USER_FLAG | WORKER_TYPE);
+
+	initpredefworkers(prog);	
+	
+}
+/*
+void add_if_ready(int workerNum, worker_instance * instance)
+{
+	//int i, j, n, old_ready_count;
+	BOOL ready=FALSE;
+	//int paramstore[32];
+	//int * params = paramstore;
+	DEBUGPUTS("add_if_ready\n");
+	if(!instance || !instance->def)
+		return;
+	VIS_PROFILE_START(PROF_ADDREADY);
+	DEBUGPRINTF( "add_if_ready on %s\n", instance->def->implement_func->workerlist[workerNum].name);
+	VIS_EnterCriticalSection(instance->workerlist[workerNum].worker_lock);
+		++instance->workerlist[workerNum].ready_count;
+		if(instance->workerlist[workerNum].ready_count >= (instance->def->implement_func->workerlist[workerNum].num_inputs + (instance->def->implement_func->workerlist[workerNum].null_input ? 1 : 0)))
+		{
+			ready = TRUE;
+			instance->workerlist[workerNum].ready_count = 0;
+		}
+	VIS_LeaveCriticalSection(instance->workerlist[workerNum].worker_lock);
+	if(ready)
+	{
+		DEBUGPRINTF("add_queue on %s\n", instance->def->implement_func->workerlist[workerNum].name);
+		add_queue(workerNum, instance);
+	}
+	VIS_PROFILE_END(PROF_ADDREADY);
+}*/
+#define RETURN_CODE_EXIT		0xABCE1234
+#define	RETURN_CODE_IDLE		0x00BADFAD
+#define	RETURN_CODE_NORMAL		0xABBAABBA
+#define RETURN_CODE_PARALLEL	0xC001D00D
+#define GET_OP1(opcode)			((opcode & 0xF0000000) >> 28)
+#define GET_OP2(opcode)			((opcode & 0x0F000000) >> 24)
+#define	GET_INST(opcode)		((opcode & 0x00FF0000) >> 16)
+
+#define MOVE_INST		0x00
+#define ADDREF_INST		0x01
+#define	RELEASE_INST	0x02
+#define LOAD_INST		0x03
+#define	CALL_INST		0x04
+#define CALLB_INST		0x05
+#define	CALLP_INST		0x06
+#define	CALLBP_INST		0x07
+#define RETURN_INST		0x08
+#define	BRANCH_INST		0x09
+#define	BRANCHT_INST	0x0A
+#define	BRANCHF_INST	0x0B
+#define WAIT_INST		0x0C
+#define ADD_INST		0x0D
+#define SUB_INST		0x0E
+#define SUBR_INST		0x0F
+#define GREATER_INST	0x10
+#define	LESSER_INST		0x11
+
+#define REGISTER_BIT	0x8
+#define NO_OPERAND		0x7
+#define OP_REG_MASK		0x7
+#define GET_REGNUM1(opcode)		((opcode & 0x0000FF00) >> 8)
+#define GET_REGNUM2(opcode)		(opcode & 0x000000FF)
+
+#define REG_DIRECT		0
+#define REG_INDIRECT	1
+#define IMMED_8			2
+#define IMMED_32		3
+#define STACK_8			4
+#define REG_REL_32		5
+#define PC_REL_8		6
+
+#define STACK_REG		31
+#define PC_REG			30
+
+#define OPC(inst, op1, reg1, op2, reg2)	((op1 << 28) | (op2 << 24) | (inst << 16) | ((reg1 & 0xff) << 8) | (reg2 & 0xFF))
+
+//unsigned long test_program[] =
+//{
+//	OPC(LOAD_INST, PC_REL_8, 8 /* Hi */, REG_DIRECT, 0),
+//	OPC(CALLB_INST, IMMED_8, 1/* Print */, NO_OPERAND, 0),
+//	OPC(RETURN_INST, NO_OPERAND, 0, NO_OPERAND, 0),
+//	26952//Hi
+//};
+
+unsigned long test_program[] =
+{
+	//Main:
+	OPC(LOAD_INST, PC_REL_8, 20/* 10 */, REG_DIRECT, 0),
+	OPC(LOAD_INST, PC_REL_8, 20/* 2 */, PC_REL_8, 28),
+	OPC(LOAD_INST, PC_REL_8, 20/* 1 */, PC_REL_8, 28),
+	OPC(CALL_INST, PC_REL_8, 28/* Fib: */, NO_OPERAND, 0),
+	OPC(CALLB_INST, IMMED_8, 1/* Print */, NO_OPERAND, 0),
+	OPC(RETURN_INST, NO_OPERAND, 0, NO_OPERAND, 0),
+	0x3033,//'30'
+	0x32,//'2'
+	0x31,//'1'
+	0,//2 storage
+	0,//1 storage
+	//Fib:
+	OPC(ADD_INST, IMMED_8, 8, REG_DIRECT, STACK_REG),
+	OPC(MOVE_INST, REG_DIRECT, 0, STACK_8, -4),
+	OPC(ADDREF_INST, REG_INDIRECT, 0, NO_OPERAND, 0),
+	OPC(ADDREF_INST, REG_INDIRECT, 0, NO_OPERAND, 0),
+	OPC(MOVE_INST, PC_REL_8, -28/* 2 */, REG_DIRECT, 1),
+	OPC(ADDREF_INST, REG_INDIRECT, 1, NO_OPERAND, 0),
+	OPC(CALLB_INST, IMMED_8, 8/* < */, NO_OPERAND, 0),
+	OPC(CALLB_INST, IMMED_8, 11/* If */, NO_OPERAND, 0),
+	OPC(BRANCHT_INST, PC_REL_8, 64/* _Base */, REG_DIRECT, 0),
+	
+	OPC(RELEASE_INST, REG_INDIRECT, 1, NO_OPERAND, 0),
+	OPC(MOVE_INST, STACK_8, -4, REG_DIRECT, 0),
+	OPC(MOVE_INST, PC_REL_8, -56/* 2 */, REG_DIRECT, 1),
+	OPC(ADDREF_INST, REG_INDIRECT, 1, NO_OPERAND, 0),
+	OPC(CALLB_INST, IMMED_8, 6/* - */, NO_OPERAND, 0),
+	OPC(CALL_INST, PC_REL_8, -60/* Fib */, NO_OPERAND, 0),
+	OPC(MOVE_INST, REG_DIRECT, 0, STACK_8, -8),
+	OPC(MOVE_INST, STACK_8, -4, REG_DIRECT, 0),
+	OPC(MOVE_INST, PC_REL_8, -76/* 1 */, REG_DIRECT, 1),
+	OPC(ADDREF_INST, REG_INDIRECT, 1, NO_OPERAND, 0),
+	OPC(CALLB_INST, IMMED_8, 6/* - */, NO_OPERAND, 0),
+	OPC(CALL_INST, PC_REL_8, -84/* Fib */, NO_OPERAND, 0),
+	OPC(MOVE_INST, STACK_8, -8, REG_DIRECT, 1),
+	OPC(CALLB_INST, IMMED_8, 5/* + */, NO_OPERAND, 0),
+	OPC(SUBR_INST, IMMED_8, 8, REG_DIRECT, STACK_REG),
+	OPC(RETURN_INST, NO_OPERAND, 0, NO_OPERAND, 0),
+	//_Base:
+	OPC(RELEASE_INST, REG_INDIRECT, 0, NO_OPERAND, 0),
+	OPC(MOVE_INST, PC_REL_8, -112/* 1 */, REG_DIRECT, 0),
+	OPC(ADDREF_INST, REG_INDIRECT, 0, NO_OPERAND, 0),
+	OPC(SUBR_INST, IMMED_8, 8, REG_DIRECT, STACK_REG),
+	OPC(RETURN_INST, NO_OPERAND, 0, NO_OPERAND, 0),
+	
+};
+
+unsigned long * get_effective_address(char op, unsigned short regnum, unsigned long ** pc, unsigned long * registers, unsigned long * immed)
+{
+	unsigned long * add = NULL;
+	unsigned long work;
+	if(op != NO_OPERAND)
+	{
+		if(op & REGISTER_BIT)
+			add = (unsigned long *)(registers[regnum] + registers[op & OP_REG_MASK]);
+		else
+		{
+			switch(op)
+			{
+				case REG_DIRECT:
+					add = registers + regnum;
+					break;
+				case REG_INDIRECT:
+					add = (unsigned long *) registers[regnum];
+					break;
+				case IMMED_8:
+					*immed = (char)regnum;
+					add = (unsigned long *)immed;
+					break;
+				case IMMED_32:
+					*immed = *((*pc)++);
+					add = (unsigned long *)immed;
+					break;
+				case STACK_8:
+					work = (char)regnum;
+					add = (unsigned long *)(registers[STACK_REG] + work);
+					break;
+				case REG_REL_32:
+					work = *((*pc)++);
+					add = (unsigned long *)(registers[regnum] + work);
+					break;
+				case PC_REL_8:
+					work = (char)regnum;
+					add = (unsigned long *)(registers[PC_REG] + work);
+					break;
+				default:
+					break;
+			}
+		}
+	}
+	return add;
+}
+
+DWORD WINAPI virtual_processor(unsigned long * program, BOOL main)
+{
+	int i;
+	unsigned long **pc;
+	unsigned long **stack;
+	unsigned long registers[32];
+	unsigned long opcode;
+	unsigned long extra, extra2;
+	queue_entry entry;
+	stack_segment initial_stack;
+	stack_segment * current = &initial_stack;
+	char slot_usage[7];
+	char op1, op2;
+	char inst;
+	unsigned long *add1, *add2;
+	long immed1, immed2;
+	initial_stack.size = MIN_STACK_SIZE;
+	initial_stack.parent = initial_stack.child = NULL;
+	initial_stack.data[0] = main ? RETURN_CODE_EXIT : RETURN_CODE_IDLE;
+	pc = (unsigned long **)(&(registers[PC_REG]));
+	stack = (unsigned long **)(&(registers[STACK_REG]));
+	*pc = program;
+	*stack = (unsigned long *)(initial_stack.data + 1);
+	entry.instance = NULL;
+	entry.worker_num = 0;
+	DEBUGPRINTF("Virtual processor, Program start: %X\n", program);
+	#ifdef ENABLE_PROFILING
+	for(i = 0; i < NUM_PROFS; ++i)
+	{
+		vis_profile_running_total[i] = 0;
+		vis_profile_counts[i] = 0;
+	}
+	VIS_PROFILE_START(PROF_EMPTYFUNC);
+	empty_test(NULL,NULL);
+	VIS_PROFILE_END(PROF_EMPTYFUNC);
+	VIS_PROFILE_START(PROF_NOCODE);
+	VIS_PROFILE_END(PROF_NOCODE);
+#endif
+	while(execute_active)
+	{
+		VIS_PROFILE_START(PROF_VIRTUAL_DECODE);
+		DEBUGPRINTF("PC: %X\n", *pc);
+		opcode = *((*pc)++);
+		op1 = GET_OP1(opcode);
+		op2 = GET_OP2(opcode);
+		add1 = get_effective_address(op1, GET_REGNUM1(opcode), pc, registers, &immed1);
+		add2 = get_effective_address(op2, GET_REGNUM2(opcode), pc, registers, &immed2);
+		DEBUGPRINTF("Opcode: %X, Instruction: %X, op1 %X, op2 %X\n", opcode, GET_INST(opcode), op1, op2);
+		inst = GET_INST(opcode);
+		VIS_PROFILE_END(PROF_VIRTUAL_DECODE);
+		VIS_PROFILE_START(PROF_VIRTUAL_EXECUTE);
+		switch(inst)
+		{
+		case MOVE_INST:
+			*add2 = *add1;
+			break;
+		case ADDREF_INST:
+			add_ref((datum *)add1);
+			break;
+		case RELEASE_INST:
+			release_ref((datum *)add1);
+			break;
+/*
+Temporarily commented out until multiple program support is finished
+		case LOAD_INST:
+			*add2 = (long)get_constant((char *)add1, -1);
+			break;
+*/
+		case CALL_INST:
+			*((*stack)++) = (unsigned long)*pc;
+			*((*stack)++) = RETURN_CODE_NORMAL;
+			*pc = add1;
+			break;
+/*
+Temporarily commented out until multiple program support is finished
+		case CALLB_INST:
+			//TODO: Needs to be made 100% correct
+			DEBUGPRINTF("Calling builtin: %s\n", deflist[*add1].name);
+			execute_def(deflist + *add1, entry, (datum **)registers, NULL);
+			break;*/
+		case CALLP_INST:
+			//TODO Implement me
+			break;
+		case CALLBP_INST:
+			//TODO Implement me
+			break;
+		case RETURN_INST:
+			switch(*(--(*stack)))
+			{
+				case RETURN_CODE_EXIT:
+					execute_active = FALSE;
+					break;
+				case RETURN_CODE_IDLE:
+					//TODO: Implement me
+					break;
+				case RETURN_CODE_NORMAL:
+					*pc = (unsigned long *)*(--(*stack));
+					break;
+				default:
+					break;
+			}
+			break;
+		case BRANCH_INST:
+			*pc = add1;
+			break;
+		case BRANCHT_INST:
+			if(*add2)
+				*pc = add1;
+			break;
+		case BRANCHF_INST:
+			if(!*add2)
+				*pc = add1;
+			break;
+		case WAIT_INST:
+			//TODO: Implement Me
+			break;
+		case ADD_INST:
+			*add2 = *add1 + *add2;
+			break;
+		case SUB_INST:
+			*add2 = *add1 - *add2;
+			break;
+		case SUBR_INST:
+			*add2 = *add2 - *add1;
+			break;
+		case GREATER_INST:
+			*add2 = *add1 > *add2;
+			break;
+		case LESSER_INST:
+			*add2 = *add1 < *add2;
+			break;
+		default:
+			break;
+		}
+		VIS_PROFILE_END(PROF_VIRTUAL_EXECUTE);
+	}
+#ifdef ENABLE_PROFILING
+	for(i = 0; i < NUM_PROFS; ++i)
+		printf("%d:\t%f,\tcount: %d,\taverage: %f\n", i, (double)vis_profile_running_total[i], vis_profile_counts[i], ((double)vis_profile_running_total[i])/((double)vis_profile_counts[i]));
+#endif
+	return 0;
+}
+
+void test_virtual()
+{
+//	int i,j,k;
+	program * prog = new_program(START_DEF_STORAGE, START_COMP_STORAGE);
+	initpredefworkers(prog);
+	init_sync_primitives();
+	init_datum_storage();
+//TODO Uncomment me
+//	init_global_storage();
+	execute_active = TRUE;
+/*	for(i = MOVE_INST; i <= LESSER_INST; ++i)
+	{
+		for(j = 0; j < 0x10; ++j)
+		{
+			for(k = 0; k < 0x10; ++k)
+			{
+				DEBUGPRINTF("i: %X, j: %X, k: %X, OPC: %X\n", i, j, k, OPC(i, j, j, k, k));
+			}
+		}
+	}*/
+	virtual_processor(test_program, TRUE);
+}
+
+DWORD WINAPI worker_thread(LPVOID param)
+{
+	queue_entry aworker;
+	int	temp_queue_len;
+	while(execute_active)
+	{
+		VIS_PROFILE_START(PROF_WORKER_THREAD);
+#ifdef NINTENDO_DS
+		if(irq_queue_count > 0)
+			run_queued_irqs();
+#endif
+		//DEBUGPUTS("Before WaitForSingleObect\n");
+		/*VIS_EnterCriticalSection(worker_queue_lock);
+			temp_queue_len = queue_len;
+		VIS_LeaveCriticalSection(worker_queue_lock);*/
+		//DEBUGPUTS("After WaitForSingleObject\n");
+		aworker = get_queue();
+		//DEBUGPUTS("After get_queue()\n");
+		//while(execute_active && aworker.worker_num < 0)//temp_queue_len == 0 && execute_active)
+		//{
+		//	VIS_WaitEvent(queue_add_event);
+		//	aworker = get_queue();
+			/*#if COMPILE_THREADS > 0
+				#ifdef WIN32
+					Sleep(0);
+				#else
+					sleep(0);
+				#endif
+			#endif
+			VIS_EnterCriticalSection(worker_queue_lock);
+				temp_queue_len = queue_len;
+			VIS_LeaveCriticalSection(worker_queue_lock);*/
+		//}
+		
+		if(aworker.worker_num >= 0)
+		{
+			//DEBUGPUTS("Before EnterCriticalSection\n");
+			
+		/*	VIS_EnterCriticalSection(worker_queue_lock);
+				if(queue_len > 0)
+				{
+					DEBUGPUTS("SetEvent\n");
+					VIS_SetEvent(queue_add_event);
+				}
+			VIS_LeaveCriticalSection(worker_queue_lock);*/
+			DEBUGPRINTF( "\nExecuting: %s<%d>, Instance: %X\n", aworker.instance->def->implement_func->workerlist[aworker.worker_num].name,aworker.worker_num,aworker.instance);
+			
+			if(process_worker(aworker) == 0)
+			{
+				//worker_complete(aworker);
+				cleanup_check(aworker);
+				//DEBUGPUTS("After cleanup_check\n");
+				
+			}
+
+		}
+		VIS_PROFILE_END(PROF_WORKER_THREAD);
+	}
+	VIS_SetEvent(queue_add_event);
+	return 0;
+}
+
+int set_comp_room(datum ** params, int room_index, queue_entry * entry, program * prog)
+{
+	int i;
+	char * data;
+	//DEBUGPRINTF("params[0]->ref_count: %d\n", params[0]->ref_count);
+	params[0] = copy_datum(params[0], 0);
+	data = ((char *)(params[0]->c.generic.data) + (int)params[0]->company->room_list[room_index].set_func);
+	DEBUGPRINTF("Set comp room: c.generic.data = %X, +get_func = %X\n", params[0]->c.generic.data, data);
+	//TODO: input conversion
+	switch(params[0]->company->room_list[room_index].get_func_type)
+	{
+	case ROOM_BYTE:
+		*data = params[1]->c.integers.num_a;
+		release_ref(params[1]);
+		break;
+	case ROOM_SHORT:
+		*((short *)data) = params[1]->c.integers.num_a;
+		release_ref(params[1]);
+		break;
+	case ROOM_LONG:
+		*((long *)data) = params[1]->c.integers.num_a;
+		release_ref(params[1]);
+		break;
+	case ROOM_SINGLE:
+		*((float *)data) = params[1]->c.real;
+		release_ref(params[1]);
+		break;
+	case ROOM_DOUBLE:
+		*((double *)data) = params[1]->c.real;
+		release_ref(params[1]);
+		break;
+	case ROOM_VIS_REF:
+		release_ref(*((datum **)data));
+		*((datum **)data) = params[1];
+		break;
+	case ROOM_CSTRING:	//not implemented
+	case ROOM_CSTRING_STRUCT:
+	case ROOM_PSTRING:
+	case ROOM_PSTRING_STRUCT:
+	case ROOM_WORKER://not implemented
+	case ROOM_VIS_OBJECT://not implemented
+	default:
+		release_ref(params[0]);
+		release_ref(params[1]);
+		params[0] = params[1] = NULL;
+		puts("unimplemented company room type\n");
+		break;
+	}
+	return 0;
+}
+
+int set_comp_room_by_name(datum ** company, char * name, int * room_index_ret, queue_entry * entry, program * prog)
+{
+	int i;
+	for (i = 0; i < company[0]->company->num_rooms; ++i)
+		if(!strcmp(name,company[0]->company->room_list[i].name))
+		{
+			if(room_index_ret)
+				*room_index_ret = i;
+			return set_comp_room(company, i, entry, prog);
+		}
+	if(room_index_ret)
+		*room_index_ret = -1;
+	return -1;
+}
+
+int get_comp_room(datum ** company, int room_index, queue_entry * entry, program * prog)
+{
+	int i;
+	datum * out;
+	queue_entry empty;
+	char * data = ((char *)(company[0]->c.generic.data) + (int)company[0]->company->room_list[room_index].get_func);
+	company[1] = NULL;
+	DEBUGPRINTF("Get comp room: c.generic.data = %X, +get_func = %X\n", company[0]->c.generic.data, data);
+	switch(company[0]->company->room_list[room_index].get_func_type)
+	{
+	case ROOM_BYTE:
+		out = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, prog);
+		out->c.integers.num_a = *data;
+		break;
+	case ROOM_SHORT:
+		out = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, prog);
+		out->c.integers.num_a = *((short *)data);
+		break;
+	case ROOM_LONG:
+		out = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, prog);
+		out->c.integers.num_a = *((long *)data);
+		break;
+	case ROOM_SINGLE:
+		out = new_datum(BUILTIN_TYPE_REAL, 3, 0, prog);
+		out->c.real = *((float *)data);
+		break;
+	case ROOM_DOUBLE:
+		out = new_datum(BUILTIN_TYPE_REAL, 3, 0, prog);
+		out->c.real = *((double *)data);
+		break;
+	case ROOM_CSTRING:
+		data = *((char **)data);
+	case ROOM_CSTRING_STRUCT:
+		out = new_datum(BUILTIN_TYPE_STRING, 1, strlen(data)+1, prog);
+		strcpy(out->c.generic.data, data);
+		break;
+	case ROOM_PSTRING:
+		data = *((char **)data);
+	case ROOM_PSTRING_STRUCT:
+		out = new_datum(BUILTIN_TYPE_STRING, 1, *((unsigned char *)data), prog);
+		memcpy(out->c.generic.data, data, *((unsigned char *)data));
+		((char *)out->c.generic.data)[*((unsigned char *)data)] = '\0';
+		break;
+	case ROOM_VIS_REF:
+		out = add_ref(*((datum **)data));
+		if(!out) {
+			company[1] = company[0];
+			company[0] = NULL;
+		}
+		break;
+	case ROOM_WORKER:
+		if(entry)
+			return execute_def((worker_def *)(company[0]->company->room_list[room_index].get_func), *entry, company, sub_callback);
+		else
+		{
+			empty.instance = NULL;
+			empty.worker_num = -1;
+			return execute_def((worker_def *)(company[0]->company->room_list[room_index].get_func), empty, company, sub_callback);
+		}
+	case ROOM_VIS_OBJECT://not implemented
+	default:
+		out = NULL;
+		puts("unimplemented company room type\n");
+		break;
+	}
+	release_ref(company[0]);
+	company[0] = out;
+	return 0;
+}
+
+int get_comp_room_by_name(datum ** company, char * name, int * room_index_ret, queue_entry * entry, program * prog)
+{
+	int i;
+	for (i = 0; i < company[0]->company->num_rooms; ++i)
+		if(!strcmp(name,company[0]->company->room_list[i].name))
+		{
+			if(room_index_ret)
+				*room_index_ret = i;
+			return get_comp_room(company, i, entry, prog);
+		}
+	if(room_index_ret)
+		*room_index_ret = -1;
+	return -1;
+}
+
+datum * literal_string(char * value, int len, program * prog)
+{
+	char literalchar;
+	BOOL literal;
+	int i, bufpos, lenstr;
+	datum * returnval;
+	
+	if(len < 0) {
+		len = strlen(value);
+	}
+	
+	literal = FALSE;
+	lenstr = 0;
+	for(i = 0; i < len; ++i)
+		if(literal)
+			literal = FALSE;
+		else
+		{
+			++lenstr;
+			if(value[i] == '\\')
+				literal = TRUE;
+		}
+	//DEBUGPRINTF("Allocating %d bytes for string constant\n", lenstr+1);
+	returnval = new_datum(BUILTIN_TYPE_STRING, 1, lenstr+1, prog);
+	bufpos = 0;
+	for(i = 0; i < len; ++i)
+	{
+		if(literal)
+		{
+			literal = FALSE;
+			switch(value[i])
+			{
+			case 'n':	//newline
+				literalchar = '\n';
+				break;
+			case 'r':	//carriage return
+				literalchar = '\r';
+				break;
+			case 't':	// tab
+				literalchar = '\t';
+				break;
+			case '0':	//NULL
+				literalchar = '\0';
+				break;
+			default:
+				literalchar = value[i];
+				break;
+			}
+			((char *)returnval->c.generic.data)[bufpos++] = literalchar;
+		}
+		else
+		{
+			if(value[i] == '\\')
+				literal = TRUE;
+			else
+			{
+				((char *)returnval->c.generic.data)[bufpos++] = value[i];
+			}
+		}
+	}
+	//DEBUGPRINTF("bufpos: %d\n", bufpos);
+	((char *)returnval->c.generic.data)[bufpos] = '\0';
+	DEBUGPUTS("Constant Type: String\n");
+	return returnval;
+}
+
+datum * get_constant(char * value, int len, program * prog)
+{
+	datum * params[2];
+	datum * returnval;
+	int i = 0,bufpos;
+	int start;
+	int lenstr;
+	int leftcurly;
+	int dotcount = 0;
+	char literalchar;
+	unsigned short const_type = ANY_TYPE;
+	BOOL literal;
+	if((len == 3 && memcmp(value, "Yes", len) == 0) || (len < 0 && strcmp(value, "Yes") == 0)) 
+	{
+		DEBUGPUTS("Constnat: Yes\n");
+		returnval = new_datum(BUILTIN_TYPE_YESNO, 2, 0, prog);
+		returnval->c.integers.num_a = 1;
+		DEBUGPRINTF("Company: %s, integers.num_a: %d\n", returnval->company->name, returnval->c.integers.num_a);
+		return returnval;
+	} 
+	else if((len == 2 && memcmp(value, "No", len) == 0) || (len < 0 && strcmp(value, "No") == 0)) 
+	{
+		DEBUGPUTS("Constant: No\n");
+		returnval = new_datum(BUILTIN_TYPE_YESNO, 2, 0, prog);
+		returnval->c.integers.num_a = 0;
+		DEBUGPRINTF("Company: %s, integers.num_a: %d\n", returnval->company->name, returnval->c.integers.num_a);
+		return returnval;
+	}
+	if(value[0] == '{')
+	{
+		DEBUGPUTS("Constant type: List");
+		params[0] = create_list(prog);
+		i = start = 1;
+		literal = FALSE;
+		leftcurly = 0;
+		for(;value[i] != 0 && (len < 0 || i < len); ++i)
+		{
+			if(literal)
+				literal = FALSE;
+			else
+			{
+				if(value[i] == '\\')
+					literal = TRUE;
+				else if(value[i] == '}')
+					if(leftcurly)
+						--leftcurly;
+					else
+						break;
+				else if(value[i] == '{')
+					++leftcurly;
+				else if(value[i] == ',' && !leftcurly)
+				{
+					params[1] = get_constant(value+start, i-start, prog);
+					vis_list_append(params, NULL);
+					start = i+1;
+				}
+			}
+		}
+		params[1]= get_constant(value+start, i-start, prog);
+		vis_list_append(params, NULL);
+		returnval = params[0];
+	}
+	else if(value[0] == '"')
+	{
+		if(len < 0) {
+			len = strlen(value);
+		}
+		len -= 2;
+		returnval = literal_string(value+1, len, prog);
+		
+	}
+	else
+	{
+		while(value[i] != 0 && (len < 0 || i < len))
+		{
+			if(value[i] >= '0' && value[i] <= '9')
+			{
+				if(const_type == ANY_TYPE)
+					const_type = BUILTIN_TYPE_WHOLE;
+			}
+			else if(value[i] == '.')
+			{
+				if(dotcount)
+				{
+					const_type = BUILTIN_TYPE_STRING;
+				}
+				else
+				{
+					++dotcount;
+					if(const_type == BUILTIN_TYPE_WHOLE)
+						const_type = BUILTIN_TYPE_REAL;
+				}
+			}
+			else
+			{
+				//DEBUGPRINTF("Current character: %c resulted in String\n", value[i]);
+				const_type = BUILTIN_TYPE_STRING;
+				break;
+			}
+			++i;
+		}
+	
+		if(const_type == BUILTIN_TYPE_WHOLE)
+		{
+			returnval = new_datum(const_type, 2, 0, prog);
+			returnval->c.integers.num_a = atol(value);
+			DEBUGPUTS("Constant Type: Whole Number\n");
+		}
+		else if(const_type == BUILTIN_TYPE_REAL)
+		{
+			returnval = new_datum(const_type, 3, 0, prog);
+			returnval->c.real = atof(value);
+			DEBUGPUTS("Constant Type: Real Number\n");
+		}
+		else
+		{
+			/* literal = FALSE;
+			lenstr = 0;
+			for(i = 0; (i < len || len < 0) && value[i] != 0; ++i)
+				if(literal)
+					literal = FALSE;
+				else
+				{
+					++lenstr;
+					if(value[i] == '\\')
+						literal = TRUE;
+				}
+			DEBUGPRINTF("Allocating %d bytes for string constant\n", lenstr+1);
+			returnval = new_datum(BUILTIN_TYPE_STRING, 1, lenstr+1, prog);
+			bufpos = 0;
+			for(i = 0; (i < len || len < 0) && value[i] != 0; ++i)
+			{
+				DEBUGPRINTF("bufpos: %d\n", bufpos);
+				if(literal)
+				{
+					literal = FALSE;
+					switch(value[i])
+					{
+					case 'n':	//newline
+						literalchar = '\n';
+						break;
+					case 'r':	//carriage return
+						literalchar = '\r';
+						break;
+					case 't':	// tab
+						literalchar = '\t';
+						break;
+					case '0':	//NULL
+						literalchar = '\0';
+						break;
+					default:
+						literalchar = value[i];
+						break;
+					}
+					((char *)returnval->c.generic.data)[bufpos++] = literalchar;
+				}
+				else
+				{
+					if(value[i] == '\\')
+						literal = TRUE;
+					else
+					{
+						((char *)returnval->c.generic.data)[bufpos++] = value[i];
+					}
+				}
+			}
+			DEBUGPRINTF("bufpos: %d\n", bufpos);
+			((char *)returnval->c.generic.data)[bufpos] = '\0';
+			DEBUGPUTS("Constant Type: String\n"); */
+			returnval = literal_string(value, len, prog);
+		}
+	}
+	return returnval;
+}
+
+int execute_def(worker_def * process_def, queue_entry worker_entry, datum ** params, instance_callback callback)
+{
+	return execute_def_type(process_def, worker_entry, params, callback, NULL, WORKER);
+}
+int execute_def_data(worker_def * process_def, queue_entry worker_entry, datum ** params, instance_callback callback, void * data)
+{
+	return execute_def_type(process_def, worker_entry, params, callback, data, WORKER);
+}
+
+int execute_def_type(worker_def * process_def, queue_entry worker_entry, datum ** params, instance_callback callback, void * data, int type)
+{
+	int returnval, i;
+	worker_instance * stack_instance;
+	worker_def *temp_def, *converter;
+	worker_def *parent_def = worker_entry.instance->def;
+	unsigned short magic_cache_type;
+	#ifdef USER_PROFILE
+		LARGE_INTEGER start, end, duration;
+	#endif
+	VIS_PROFILE_START(PROF_PREP_MAGIC);
+	if((process_def->type & TYPE_MASK) == MAGIC_TYPE)
+	{
+		DEBUGPRINTF( "Magic method: %s\n", process_def->name);
+		if(!params || !params[0])
+		{
+			ERRORPRINTF("Error: null first parmeter or null parameter array for worker %s\n", process_def->name);
+			print_stack_trace(worker_entry.instance);
+			execute_active = FALSE;
+			return -1;
+		}
+		VIS_EnterCriticalSection(parent_def->implement_func->workerlist[worker_entry.worker_num].lock);
+			temp_def = parent_def->implement_func->workerlist[worker_entry.worker_num].magic_cache_implement;
+			magic_cache_type = parent_def->implement_func->workerlist[worker_entry.worker_num].magic_cache_type;
+		VIS_LeaveCriticalSection(parent_def->implement_func->workerlist[worker_entry.worker_num].lock);
+		if(!temp_def || magic_cache_type != params[0]->company->type_id)
+		{
+			DEBUGPRINTF("Finding method %s with %d inputs for type %s(%d)\n", process_def->name, process_def->num_inputs, params[0]->company->name, params[0]->company->type_id);
+			temp_def = find_method(params[0]->company->type_id,process_def->name, process_def->num_inputs, process_def->program);
+			if(!temp_def) 
+			{
+				for(i = 1; i < process_def->program->num_companies; ++i)
+				{
+					temp_def = find_method(i,process_def->name, process_def->num_inputs, process_def->program);
+					if(temp_def)
+					{
+						converter = find_converter_method(temp_def->input_types[0], params[0]->company->type_id, process_def->program);
+						if(converter)
+						{
+							((worker_impl)converter->implement_func)(params, &worker_entry);
+							break;
+						}
+						else
+						{
+							//DEBUGPRINTF("Error: Needed conversion from %s to %s for input %d of %s\n", params[0]->company->name, process_def->program->companylist[temp_def->input_types[0]].name, 0, temp_def->name);
+							//printf("Warning: Needed conversion from %s to %s for input %d of %s for loose method call\n", params[0]->company->name, process_def->program->companylist[temp_def->input_types[0]].name, 0, temp_def->name);
+							temp_def = NULL;
+						}
+					}
+				}
+			}
+			if(temp_def)
+			{
+				VIS_EnterCriticalSection(parent_def->implement_func->workerlist[worker_entry.worker_num].lock);
+					parent_def->implement_func->workerlist[worker_entry.worker_num].magic_cache_implement = temp_def;
+					parent_def->implement_func->workerlist[worker_entry.worker_num].magic_cache_type = temp_def->input_types[0];
+				VIS_LeaveCriticalSection(parent_def->implement_func->workerlist[worker_entry.worker_num].lock);
+			}
+			else
+			{
+				ERRORPRINTF("Error: Company %s doesn't implement worker %s. It implements the following:\n", params[0]->company->name, process_def->name);
+				for(i = 0; i < params[0]->company->num_methods; ++i)
+				{
+					ERRORPRINTF("%s\n", params[0]->company->methodlist[i]->name);
+				}
+				print_stack_trace(worker_entry.instance);
+			}
+		}
+		process_def = temp_def;
+	}
+	VIS_PROFILE_END(PROF_PREP_MAGIC);
+	if(!process_def)
+	{
+		//DEBUGPUTS("Invalid def\n");
+		VIS_PROFILE_END(PROF_EXECUTE_WORKER);
+		execute_active = FALSE;
+		return -2;
+	}
+	
+	VIS_PROFILE_START(PROF_CONVERT_INPUTS);
+	for(i = 0; i < process_def->num_inputs; ++i)
+	{
+		DEBUGPRINTF("params[%d] = %X\n", i, params[i]);
+		if(process_def->input_types[i] != ANY_TYPE && process_def->input_types[i] != params[i]->company->type_id)
+		{
+			DEBUGPRINTF("Input %d needs conversion from %d to %d\n", i, params[i]->company->type_id, process_def->input_types[i]);
+			converter = find_converter_method(process_def->input_types[i], params[i]->company->type_id, process_def->program);
+			if(!converter)
+			{
+				if(worker_entry.instance) {
+					ERRORPRINTF("Error: Needed conversion from %s to %s for input %d of %s in worker %s\n", params[i]->company->name, process_def->program->companylist[process_def->input_types[i]].name, i, process_def->name, worker_entry.instance->def->name);
+				} else {
+					DEBUGPRINTF("Error: Needed conversion from %s to %s for input %d of %s\n", params[i]->company->name, process_def->program->companylist[process_def->input_types[i]].name, i, process_def->name);
+					printf("Error: Needed conversion from %s to %s for input %d of %s", params[i]->company->name, process_def->program->companylist[process_def->input_types[i]].name, i, process_def->name);
+				}
+				execute_active = FALSE;
+				VIS_PROFILE_END(PROF_PROCESS_WORKER);
+				return -3;
+			}
+			((worker_impl)(converter->implement_func))(params+i, &worker_entry);
+		}
+	}
+	VIS_PROFILE_END(PROF_CONVERT_INPUTS);
+			
+	if(process_def->type & USER_FLAG)
+	{
+		VIS_PROFILE_START(PROF_EXECUTE_CUSTOM);
+		//
+		init_custom_worker_type(worker_entry.worker_num, worker_entry.instance, process_def, callback, data, params, type);
+		VIS_PROFILE_END(PROF_EXECUTE_CUSTOM);
+		VIS_PROFILE_END(PROF_PROCESS_WORKER);
+		VIS_PROFILE_END(PROF_EXECUTE_WORKER);
+		return 1;
+	}
+	else
+	{
+		VIS_PROFILE_START(PROF_EXECUTE_BUILTIN);
+		//DEBUGPRINTF("%s: before deflist[%d].implement_func: %X. vis_append: %X vis_print: %X\n",def->implement_func->workerlist[aworker].name, def->implement_func->workerlist[aworker].value_index, (int)deflist[def->implement_func->workerlist[aworker].value_index].implement_func, (int)vis_append, (int)vis_print);
+		#ifdef USER_PROFILE
+		QueryPerformanceCounter(&start);
+		#endif
+		returnval = ((worker_impl)(process_def->implement_func))(params, &worker_entry);
+		#ifdef USER_PROFILE
+		if(!returnval)
+		{
+			QueryPerformanceCounter(&end);
+			duration.QuadPart = end.QuadPart - start.QuadPart;
+			VIS_EnterCriticalSection(process_def->lock);
+				process_def->total.QuadPart += duration.QuadPart;
+				++process_def->count;
+				if(duration.QuadPart > process_def->worst.QuadPart)
+					process_def->worst.QuadPart = duration.QuadPart;
+			VIS_LeaveCriticalSection(process_def->lock);
+		}
+		#endif
+		//DEBUGPUTS("Builtin worker returned\n");
+		VIS_PROFILE_END(PROF_EXECUTE_BUILTIN);
+		return returnval;
+	}
+}
+
+void wait_callback(worker_instance * caller_instance, int caller_workerenum, worker_instance * done_instance, void * data)
+{
+	int i;
+	def_done * done = (def_done *)data;
+	//DEBUGPUTS("begin wait_callback\n");
+	for(i = 0; i < done_instance->def->num_outputs; ++i)
+		done->params[i] = NULL;
+	for(i = 0; i < done_instance->def->implement_func->num_workers; ++i)
+	{
+		if(done_instance->def->implement_func->workerlist[i].type == 4)
+		{
+			if(!(done->params[done_instance->def->implement_func->workerlist[i].io_num]))
+			{
+				done->params[done_instance->def->implement_func->workerlist[i].io_num] = done_instance->workerlist[i].value;
+				done_instance->workerlist[i].value = NULL;
+			}
+		}
+	}
+	//DEBUGPUTS("Before EnterCritical\n");
+	VIS_EnterCriticalSection(done->lock);
+		done->done_flag = TRUE;
+	VIS_LeaveCriticalSection(done->lock);
+	//DEBUGPUTS("After EnterCritical\n");
+}
+
+
+BOOL execute_def_wait(worker_def * def, datum ** params)
+{
+	int val;
+	def_done done;
+	queue_entry entry;
+	entry.worker_num = 0;
+	entry.instance = NULL;
+	VIS_InitializeCriticalSection(done.lock);
+	done.done_flag = FALSE;
+	done.params = params;
+	val = execute_def_data(def, entry, params, wait_callback, &done);
+	if(val == 0)
+		return TRUE;
+	else if (val < 0)
+		return FALSE;
+	while(1)
+	{
+		VIS_EnterCriticalSection(done.lock);
+			if(done.done_flag)
+			{
+				VIS_DeleteCriticalSection(done.lock);
+				break;
+			}
+		VIS_LeaveCriticalSection(done.lock);
+#if COMPILE_THREADS > 1
+	#ifdef WIN32
+		Sleep(0);
+	#else
+		sleep(0);
+	#endif
+#endif
+	}
+	return TRUE;
+}
+
+int process_worker(queue_entry worker_entry)
+{
+	//datum * paramstore[32];
+	datum ** params;// = paramstore;
+	int i, j, start=0;
+	global_store * store;
+	char * varname;
+	datum * varname_dat;
+	datum * tempvalindex, *todelete;
+	int got_params=0;
+	int aworker = worker_entry.worker_num;
+	worker_instance * instance = worker_entry.instance;
+	worker_def * def = instance->def;
+	worker_def * process_def;
+	worker_def * temp_def;
+	worker_def * converter;
+	int returnval = 0;
+	short const_type;
+	char * last;
+	
+	VIS_PROFILE_START(PROF_PROCESS_WORKER);
+
+	DEBUGPRINTF( "Processing worker %d with %d inputs and %d outputs\n", aworker,def->implement_func->workerlist[aworker].num_inputs, def->implement_func->workerlist[aworker].num_outputs);
+	/*VIS_EnterCriticalSection(instance->workerlist[aworker].worker_lock);
+		for(i = 0; i < def->implement_func->workerlist[aworker].num_inputs; ++i)
+		{
+			params[i] = instance->workerlist[aworker].params[i+1];
+			DEBUGPRINTF("params[%d] = %X\n", i, params[i]);
+			instance->workerlist[aworker].params[i+1] = NULL;
+		}*/
+		if(def->implement_func->workerlist[aworker].null_input)
+		{
+			//DEBUGPUTS("About to call release_ref\n");
+			release_ref(instance->workerlist[aworker].params[0]);
+			instance->workerlist[aworker].params[0] = NULL;
+		}
+	//VIS_LeaveCriticalSection(instance->workerlist[aworker].worker_lock);
+	//DEBUGPRINTF("Param check complete. returnval: %d, start: %d\n", returnval, start);
+	params = instance->workerlist[aworker].params+1;
+	
+	if(def->implement_func->workerlist[aworker].type == WORKER || def->implement_func->workerlist[aworker].type == TAIL_RECURSE || def->implement_func->workerlist[aworker].type == TAIL_CALL)//Worker
+	{
+		VIS_PROFILE_START(PROF_EXECUTE_WORKER);
+		//DEBUGPUTS("Worker\n");
+		process_def = (worker_def *)(def->implement_func->workerlist[aworker].value_index);
+		//DEBUGPUTS("Got process_def\n");
+		DEBUGPRINTF("process_def->type: %X, type & TYPE_MASK: %X\n", process_def->type, (process_def->type & TYPE_MASK));
+		
+		returnval = execute_def_type(process_def, worker_entry, params, sub_callback, NULL, def->implement_func->workerlist[aworker].type);
+		DEBUGPRINTF("execute_def returned %d\n", returnval);
+		if(returnval != 0)
+		{
+			VIS_PROFILE_END(PROF_PROCESS_WORKER);
+			VIS_PROFILE_END(PROF_EXECUTE_WORKER);
+			return returnval;
+		}
+		//DEBUGPRINTF("params[0] after execute_def: %X\n", params[0]);
+		
+		//DEBUGPUTS("Before process_outputs\n");
+		
+		process_outputs(params, aworker, instance);
+		//DEBUGPUTS("After process_outputs\n");
+		
+		VIS_PROFILE_END(PROF_EXECUTE_WORKER);
+		
+	}
+	else if(def->implement_func->workerlist[aworker].type == GET_GLOBAL)
+	{
+		varname = def->implement_func->workerlist[aworker].name + def->implement_func->workerlist[aworker].io_num;
+		varname_dat = make_string(varname, -1, def->program);
+		if(def->implement_func->workerlist[aworker].value_index < 0)
+		{
+			for(i = 0; i < instance->trans->num_stores; ++i)
+			{
+				VIS_EnterCriticalSection(instance->trans->stores[i].lock);
+					params[0] = add_ref(instance->trans->stores[i].instance_data);
+				VIS_LeaveCriticalSection(instance->trans->stores[i].lock);
+				params[1] = add_ref(varname_dat);
+				vis_dict_index(params, NULL);
+				
+				if(params[0])
+				{
+					def->implement_func->workerlist[aworker].value_index = i;
+					break;
+				}
+			}
+			if(def->implement_func->workerlist[aworker].value_index < 0)
+			{
+				printf("Error: Variable %s not found in any global stores used by worker %s\n", varname, def->name);
+				DEBUGPRINTF("Error: Variable %s not found in any global stores used by worker %s\n", varname, def->name);
+				execute_active = FALSE;
+				return -1;
+			}
+		}
+		else
+		{
+			VIS_EnterCriticalSection(instance->trans->stores[(int)def->implement_func->workerlist[aworker].value_index].lock);
+				params[0] = add_ref(instance->trans->stores[(int)def->implement_func->workerlist[aworker].value_index].instance_data);
+			VIS_LeaveCriticalSection(instance->trans->stores[(int)def->implement_func->workerlist[aworker].value_index].lock);
+			params[1] = varname_dat;
+			vis_dict_index(params, NULL);
+			if(!params[0])
+			{
+				printf("Error: Global variable %s not found in worker %s\n", def->implement_func->workerlist[aworker].name, def->name);
+				DEBUGPRINTF("Error: Global variable %s not found in worker %s\n", def->implement_func->workerlist[aworker].name, def->name);
+				execute_active = FALSE;
+				return -1;
+			}
+		}
+		process_outputs(params, aworker, instance);
+		
+			
+	}
+	else if(def->implement_func->workerlist[aworker].type == SET_GLOBAL)
+	{
+		varname = def->implement_func->workerlist[aworker].name + def->implement_func->workerlist[aworker].io_num;
+		varname_dat = make_string(varname, -1, def->program);
+		params[2] = params[0];
+		params[1] = varname_dat;
+		VIS_EnterCriticalSection(instance->trans->stores[(int)def->implement_func->workerlist[aworker].value_index].lock);
+			//no add_ref here because we'll be replacing instance_data with the result of vis_dict set
+			params[0] = instance->trans->stores[(int)def->implement_func->workerlist[aworker].value_index].instance_data;
+			vis_dict_set(params, NULL);
+			instance->trans->stores[(int)def->implement_func->workerlist[aworker].value_index].instance_data = params[0];
+		VIS_LeaveCriticalSection(instance->trans->stores[(int)def->implement_func->workerlist[aworker].value_index].lock);
+		//no outputs to process
+	}
+	else if(def->implement_func->workerlist[aworker].type == GET_COMP)
+	{
+		returnval = get_comp_room_by_name(params, def->implement_func->workerlist[aworker].name, NULL, &worker_entry, def->program);
+		if(returnval)
+			return returnval;
+		process_outputs(params, aworker, instance);
+	}
+	else if(def->implement_func->workerlist[aworker].type == SET_COMP)
+	{
+		returnval = set_comp_room_by_name(params, def->implement_func->workerlist[aworker].name, NULL, &worker_entry, def->program);
+		if(returnval)
+			return returnval;
+		process_outputs(params, aworker, instance);
+	}
+	else//Variable
+	{
+		VIS_PROFILE_START(PROF_EXECUTE_OTHER);
+		if(def->implement_func->workerlist[aworker].num_inputs > 0 || def->implement_func->workerlist[aworker].type == INPUT) //Is this a Room or a constant?
+		{
+			todelete = NULL;
+			VIS_EnterCriticalSection(instance->workerlist[aworker].worker_lock);
+				if(def->implement_func->workerlist[aworker].type == OUTPUT)
+				{
+					todelete = instance->workerlist[aworker].value;
+					instance->workerlist[aworker].value = params[0];
+					DEBUGPRINTF("Setting room/output at pos %d to %X in instance %X\n", aworker, params[0], instance);
+				}
+				//tempvalindex = instance->workerlist[aworker].value;
+			VIS_LeaveCriticalSection(instance->workerlist[aworker].worker_lock);
+			if(def->implement_func->workerlist[aworker].type == INPUT)
+			{
+				params[0] = instance->workerlist[aworker].value;
+				instance->workerlist[aworker].value = NULL;
+			}
+			if(todelete)
+				release_ref(todelete);
+			if(def->implement_func->workerlist[aworker].num_outputs)
+			{
+				//add_ref(tempvalindex);
+				process_outputs(params/*&tempvalindex*/, aworker, instance);
+			}
+			
+		}
+		else
+		{
+			//Hmm, do I potentially need another lock here?
+			/*if(!(instance->def->implement_func->workerlist[aworker].value_index))
+			{
+				instance->def->implement_func->workerlist[aworker].value_index = (int)(tempvalindex=get_constant(def->implement_func->workerlist[aworker].name,-1));//(int)tempvalindex;
+			}
+			else*/
+				tempvalindex = (datum *)instance->def->implement_func->workerlist[aworker].value_index;
+			add_ref(tempvalindex);
+			process_outputs(&tempvalindex, aworker, instance);
+		}
+		VIS_PROFILE_END(PROF_EXECUTE_OTHER);
+	}
+	VIS_PROFILE_END(PROF_PROCESS_WORKER);
+	return returnval;
+}
+
+#define OPT_RESULT		0
+#define OPT_CUST_RESULT	0x10000000
+#define OPT_CONST		0x20000000
+#define OPT_INPUT		0x30000000
+
+int find_input_worker(custom_worker * cust, int aworker, int input, int *ret_output)
+{
+	int o, p, wire_count;
+	int out_worker;
+	o = cust->workerlist[aworker].wire_up_lookup;
+	wire_count = 0;
+	while(cust->wirelist[p=cust->workers_to_wires_up[o]].end_worker == aworker && p >= 0)
+	{
+		if(cust->wirelist[p].input_num == input)
+		{
+			++wire_count;
+			out_worker = cust->wirelist[p].start_worker;
+			DEBUGPRINTF("Input %d attached to %s(%d)\n", input, cust->workerlist[out_worker].name, out_worker);
+			if(ret_output)
+				*ret_output = cust->wirelist[p].output_num;
+		}
+		++o;
+	}
+	DEBUGPRINTF("wire_count: %d\n", wire_count);
+	if(wire_count == 1)
+		return out_worker;
+	return -1;
+}
+
+int make_input_code(custom_worker * cust, BOOL * in_opt, int * pos_in_opt, int source_worker, int output_num, int index, opt_entry * opts, int * branch_flags, opt_entry ** branch_refs, int input_num, program * prog)
+{
+	/*if(in_opt[source_worker])
+	{
+		if(prog->deflist[cust->workerlist[source_worker].value_index].type & USER_FLAG)
+		{
+			return OPT_CUST_RESULT | ((pos_in_opt[source_worker] & 0xFFFF) << 8) | (output_num & 0xFF);
+		}
+		else
+		{
+			if(strcmp(prog->deflist[cust->workerlist[source_worker].value_index].name, "If") == 0)
+			{
+				if(output_num == 0)
+				{
+					branch_flags[index] = 1;
+					if(opts[pos_in_opt[source_worker]].branch1 <= index)
+						opts[pos_in_opt[source_worker]].branch1 = index+1;
+				}
+				else
+				{
+					branch_flags[index] = 2;
+					if(opts[pos_in_opt[source_worker]].branch2 <= index)
+						opts[pos_in_opt[source_worker]].branch2 = index+1;
+				}
+				branch_refs[index] = opts + pos_in_opt[source_worker];
+			}
+			else if(branch_flags[pos_in_opt[source_worker]])
+			{
+				if(branch_flags[pos_in_opt[source_worker]] == 1)
+				{
+					branch_refs[pos_in_opt[source_worker]]->branch1 = index + 1;
+					branch_flags[index] = 1;
+				}
+				else
+				{
+					branch_refs[pos_in_opt[source_worker]]->branch1 = index + 2;
+					branch_flags[index] = 2;
+				}
+				branch_refs[index] = branch_refs[pos_in_opt[source_worker]];
+			}
+			else
+				branch_flags[index] = 0;
+			if(input_num >= 0)
+				++opts[pos_in_opt[source_worker]].output_refs[output_num];
+			DEBUGPRINTF("OPT_RESULT: opt_num: %d, output_num: %d\n", pos_in_opt[source_worker], output_num);
+			return OPT_RESULT | ((pos_in_opt[source_worker] & 0xFFFF) << 8) | (output_num & 0xFF);
+		}
+	}
+	else if(cust->workerlist[source_worker].type == CONSTANT)
+	{
+		branch_flags[index] = 0;
+		DEBUGPRINTF("OPT_CONST: %d\n", source_worker);
+		return OPT_CONST | source_worker;
+	}
+	else if(cust->workerlist[source_worker].type == INPUT)
+	{
+		branch_flags[index] = 0;
+		DEBUGPRINTF("OPT_INPUT: %d\n", cust->workerlist[source_worker].io_num);
+		return OPT_INPUT | cust->workerlist[source_worker].io_num;
+	}*/
+	return -1;
+}
+
+void optimize(worker_def * def)
+{
+	/*
+	int i,j,k,m,o,p;
+	int * const_in;
+	int num_entries = 0;
+	int aworker;
+	int adjust;
+	int source_worker;
+	int source_output;
+	int source_null;
+	int null_output;
+	int wire_count;
+	int * input_data;
+	int current_null;
+	int cust_result_count;
+	int new_start;
+	custom_worker * cust = def->implement_func;
+	int start_current, end_current, new_current;
+	worker_def * deflist = def->program->deflist;
+	opt_entry * output = malloc(sizeof(opt_entry) * def->implement_func->num_workers);
+	BOOL * in_opt = malloc(sizeof(BOOL) * cust->num_workers);
+	int * branch_flags = malloc(sizeof(int) * cust->num_workers);
+	opt_entry ** branch_refs = malloc(sizeof(int) * cust->num_workers);
+	//BOOL * real_in_opt = malloc(sizeof(BOOL) * cust->num_workers);
+	int * pos_in_opt = malloc(sizeof(int) * cust->num_workers);
+	DEBUGPRINTF("deflist: %X\n", deflist);
+	for(i = 0; i < cust->num_workers; ++i)
+	{
+		branch_flags[i] = 0;
+		DEBUGPRINTF("%d: No input pass\n", i);
+		DEBUGPRINTF("Examining: %s\n", cust->workerlist[i].name);
+		if(cust->workerlist[i].num_inputs == 0 && !cust->workerlist[i].null_input && cust->workerlist[i].type == WORKER)
+		{
+			output[num_entries].def = deflist + cust->workerlist[i].value_index;
+			DEBUGPRINTF("Set output[%d].def = %X\n", num_entries, output[num_entries].def);
+			DEBUGPRINTF("opt: %d is %s\n\n", num_entries, cust->workerlist[i].name);
+			output[num_entries].original_pos = i;
+			output[num_entries].input_data = NULL;
+			if(cust->workerlist[i].num_outputs)
+			{
+				output[num_entries].output_refs = malloc(sizeof(int)*cust->workerlist[i].num_outputs);
+				for(j = 0; j < cust->workerlist[i].num_outputs; ++j)
+					output[num_entries].output_refs[j] = 0;
+			}
+			else
+				output[num_entries].output_refs = NULL;
+			output[num_entries].branch1 = output[num_entries].branch2 = -1;
+			//if(!(deflist[cust->workerlist[i].value_index].type & USER_FLAG))
+			//{
+				in_opt[i] = TRUE;
+				pos_in_opt[i] = num_entries;
+			//}
+			//real_in_opt[i] = TRUE;
+			++num_entries;
+		}
+		else
+		{
+			//real_in_opt[i] = FALSE;
+			in_opt[i] = FALSE;
+		}
+	}
+	start_current = num_entries;
+	for(i = 0; i < cust->num_workers; ++i)
+	{
+		DEBUGPRINTF("%d: Second pass\n", i);
+		if(cust->workerlist[i].num_inputs == 0  && !cust->workerlist[i].null_input)
+		{
+			j = cust->workerlist[i].wire_down_lookup;
+			while(cust->wirelist[k=cust->workers_to_wires_down[j]].start_worker == i && k >= 0)
+			{
+				aworker = cust->wirelist[k].end_worker;
+				if(!in_opt[aworker])
+				{
+					DEBUGPRINTF("Examining: %s(%d)\n", cust->workerlist[aworker].name, aworker);
+					if(cust->workerlist[i].null_input)
+						adjust = 1;
+					else
+						adjust = 0;
+					input_data = malloc(sizeof(int)* (cust->workerlist[aworker].num_inputs+adjust));
+					for(m = (0-adjust); m < cust->workerlist[aworker].num_inputs; ++m)
+					{
+						DEBUGPRINTF("Input: %d\n", m);
+						source_worker = find_input_worker(cust, aworker, m, &source_output);
+						DEBUGPRINTF("source_worker: %d\n", source_worker);
+						if(source_worker == -1)
+							break;
+						source_worker = make_input_code(cust, in_opt, pos_in_opt, source_worker, source_output, num_entries, output, branch_flags, branch_refs, m, def->program);
+						DEBUGPRINTF("input code: %X\n", source_worker);
+						if(source_worker == -1)
+							break;
+						input_data[m+adjust] = source_worker;
+						if(source_worker == -1)
+							break;
+					}
+					if(source_worker == -1)
+						free(input_data);
+					else
+					{
+						if(cust->workerlist[aworker].type == OUTPUT)
+							output[num_entries].def = NULL;
+						else
+							output[num_entries].def = deflist + cust->workerlist[aworker].value_index;
+						DEBUGPRINTF("Set output[%d].def = %X\n", num_entries, output[num_entries].def);
+						DEBUGPRINTF("opt: %d is %s\n\n", num_entries, cust->workerlist[aworker].name);
+						output[num_entries].original_pos = aworker;
+						output[num_entries].input_data = input_data;
+						output[num_entries].null_inputs = adjust;
+						output[num_entries].branch1 = output[num_entries].branch2 = -1;
+						if(cust->workerlist[aworker].num_outputs)
+						{
+							output[num_entries].output_refs = malloc(sizeof(int)*cust->workerlist[aworker].num_outputs);
+							for(m = 0; m < cust->workerlist[aworker].num_outputs; ++m)
+								output[num_entries].output_refs[m] = 0;
+						}
+						else
+							output[num_entries].output_refs = NULL;
+						//if(cust->workerlist[aworker].type != OUTPUT && !(deflist[cust->workerlist[aworker].value_index].type & USER_FLAG))
+						//{
+							in_opt[aworker] = TRUE;
+							pos_in_opt[aworker] = num_entries;
+						//}
+						//real_in_opt[aworker] = TRUE;
+						++num_entries;
+						
+					}
+				}
+				++j;
+			}
+		}
+	}
+	DEBUGPUTS("Before While\n");
+	end_current = num_entries;
+	while(start_current != end_current)
+	{
+		DEBUGPRINTF("start_current: %d, end_current: %d\n", start_current, end_current);
+		new_start = num_entries;
+		for(i = start_current; i < end_current; ++i)
+		{
+			DEBUGPRINTF("opt: %d, def: %X, name: %s\n", i, output[i].def, cust->workerlist[output[i].original_pos].name);
+			j = cust->workerlist[output[i].original_pos].wire_down_lookup;
+			DEBUGPRINTF("wire_down_lookup: %d\n", j);
+			while(cust->wirelist[k=cust->workers_to_wires_down[j]].start_worker == output[i].original_pos && k >= 0)
+			{
+				DEBUGPRINTF("Wire %d is attached to worker %d output %d and worker %d input %d\n", k, cust->wirelist[k].start_worker, cust->wirelist[k].output_num, cust->wirelist[k].end_worker, cust->wirelist[k].input_num);
+				aworker = cust->wirelist[k].end_worker;
+				//FIXME: Only works if constant/input attached to only one destination
+				if(cust->workerlist[aworker].type == CONSTANT || cust->workerlist[aworker].type == INPUT)
+				{
+					DEBUGPRINTF("Worker is of type %d, ", cust->workerlist[aworker].type);
+					aworker = cust->wirelist[cust->workers_to_wires_down[cust->workerlist[aworker].wire_down_lookup]].end_worker;
+					DEBUGPRINTF("reruting to worker %d\n", aworker);
+				}
+				if(!in_opt[aworker])
+				{
+					DEBUGPRINTF("Examining: %s(%d)\n", cust->workerlist[aworker].name, aworker);
+					if(cust->workerlist[i].null_input)
+						adjust = 1;
+					else
+						adjust = 0;
+					for(m = (0-adjust); m < cust->workerlist[aworker].num_inputs; ++m)
+					{	
+						source_worker = find_input_worker(cust, aworker, m, &source_output);
+						if(source_worker == -1)
+							break;
+						if(cust->workerlist[source_worker].null_input && cust->workerlist[source_worker].type != WORKER)
+							++adjust;
+					}
+					if(source_worker != -1)
+					{
+						current_null = 0;
+						input_data = malloc(sizeof(int)* (cust->workerlist[aworker].num_inputs+adjust));
+						cust_result_count = 0;
+						for(m = (cust->workerlist[i].null_input ? -1 : 0); m < cust->workerlist[aworker].num_inputs; ++m)
+						{
+							DEBUGPRINTF("Input: %d\n", m);
+							source_worker = find_input_worker(cust, aworker, m, &source_output);
+							if(cust->workerlist[source_worker].null_input && cust->workerlist[source_worker].type != WORKER)
+							{
+								source_null = find_input_worker(cust, source_worker, -1, &null_output);
+								if(source_null == -1)
+								{
+									source_worker = -1;
+									break;
+								}
+								source_null = make_input_code(cust, in_opt, pos_in_opt, source_null, null_output, num_entries, output, branch_flags, branch_refs,-2, def->program);
+								if((source_null & 0xF0000000) == OPT_CUST_RESULT)
+									++cust_result_count;
+								if(source_null == -1)
+								{
+									source_worker = -1;
+									break;
+								}
+								input_data[current_null++] = source_null;
+							}
+							DEBUGPRINTF("source_worker: %d\n", source_worker);
+							source_worker = make_input_code(cust, in_opt, pos_in_opt, source_worker, source_output, num_entries, output, branch_flags, branch_refs, m, def->program);
+							if((source_worker & 0xF0000000) == OPT_CUST_RESULT)
+									++cust_result_count;
+							DEBUGPRINTF("input code: %d\n", source_worker);
+							if(cust_result_count >= (cust->workerlist[aworker].num_inputs + adjust))
+								source_worker = -1;
+							if(source_worker == -1)
+								break;
+							input_data[m+adjust] = source_worker;
+						}
+						if(source_worker == -1)
+							free(input_data);
+						else
+						{
+							if(cust->workerlist[aworker].type == OUTPUT)
+								output[num_entries].def = NULL;
+							else
+								output[num_entries].def = deflist + cust->workerlist[aworker].value_index;
+							DEBUGPRINTF("Set output[%d].def = %X\n", num_entries, output[num_entries].def);
+							DEBUGPRINTF("opt: %d is %s\n\n", num_entries, cust->workerlist[aworker].name);
+							output[num_entries].original_pos = aworker;
+							output[num_entries].input_data = input_data;
+							output[num_entries].null_inputs = adjust;
+							output[num_entries].branch1 = output[num_entries].branch2 = -1;
+							if(cust->workerlist[aworker].num_outputs)
+							{
+								output[num_entries].output_refs = malloc(sizeof(int)*cust->workerlist[aworker].num_outputs);
+								for(m = 0; m < cust->workerlist[aworker].num_outputs; ++m)
+									output[num_entries].output_refs[m] = 0;
+							}
+							else
+								output[num_entries].output_refs = NULL;
+							//if(cust->workerlist[aworker].type != OUTPUT && !(deflist[cust->workerlist[aworker].value_index].type & USER_FLAG))
+							//{
+								in_opt[aworker] = TRUE;
+								pos_in_opt[aworker] = num_entries;
+							//}
+							//real_in_opt[aworker] = TRUE;
+							++num_entries;
+							
+						}
+					}
+				}
+				++j;
+			}
+		}
+		start_current = new_start;
+		end_current = num_entries;
+	}
+	def->optimized = output;
+	def->opt_count = num_entries;
+	DEBUGPUTS("optimize done\n\n\n");
+	*/
+}
+
+
+void run_optimized(worker_instance * instance, datum ** params)
+{
+	int i = 0,j,k;
+	unsigned short output, opt_num;
+	datum * this_params[32];
+	queue_entry entry;
+	datum * val;
+	BOOL skip;
+	BOOL partial_flag;
+	BOOL continue_flag;
+	int count;
+	int ready;
+	int jump_from = -1;
+	int jump_to = -1;
+	int tmp, addnum;
+	opt_entry * exec_list = instance->def->optimized;
+	datum ** results = instance->opt_results;//malloc(sizeof(datum *) * instance->def->opt_count * 32);
+	VIS_PROFILE_START(PROF_RUN_OPT);
+	entry.instance = instance;
+	for(i = 0; i < instance->def->opt_count; ++i)
+	{
+		VIS_PROFILE_START(PROF_OPT_LOOP);
+		skip = FALSE;
+		partial_flag = FALSE;
+		continue_flag = FALSE;
+		DEBUGPRINTF("\nPeparing exec_list[%d]\n", i);
+		if(exec_list[i].def)
+		{
+			DEBUGPRINTF("Name: %s\n", exec_list[i].def->name);
+			count = exec_list[i].def->num_inputs;
+		}
+		else
+			count = 1;
+		count += exec_list[i].null_inputs;
+		//DEBUGPRINTF("Input count: %d\n", count);
+		if(count && !exec_list[i].input_data)
+			puts("Runtime Error: input data is NULL\n");
+		//DEBUGPRINTF("input_data: %X\n", exec_list[i].input_data);
+		VIS_PROFILE_START(PROF_OPT_PREP_INPUT);
+		for(j = 0; j < count; ++j)
+		{
+			val = NULL;
+			continue_flag = FALSE;
+			switch(exec_list[i].input_data[j] & 0xF0000000)
+			{
+				case OPT_RESULT:
+					output = exec_list[i].input_data[j] & 0xFF;
+					opt_num = (exec_list[i].input_data[j] >> 8)& 0xFFFF;
+					DEBUGPRINTF("OPT_RESULT for input %d, opt_num: %d, output: %d\n", j, opt_num, output);
+					val = results[(opt_num * 32) | output];
+					break;
+				case OPT_CUST_RESULT:
+					val = NULL;
+					partial_flag = TRUE;
+					continue_flag = TRUE;
+					break;
+				case OPT_INPUT:
+					DEBUGPRINTF("OPT_INPUT for input %d\n", j);
+					val = add_ref(params[exec_list[i].input_data[j] & 0xFF]);
+					break;
+				case OPT_CONST:
+					DEBUGPRINTF("OPT_CONST for input %d\n", j);
+					val = add_ref((datum *)(instance->def->implement_func->workerlist[exec_list[i].input_data[j] & 0xFFFFFF].value_index));
+					break;
+				default:
+					puts("Runtime Error: Invalid bytecode\n");
+					val = NULL;
+					break;
+			}
+			if(!val && !continue_flag)
+			{
+				for(k = exec_list[i].null_inputs; k < j; ++k)
+					release_ref(this_params[k]);
+				skip = TRUE;
+				break;
+			}
+			DEBUGPRINTF("this_params[%d] = %X\n", j, val);
+			if(j >= exec_list[i].null_inputs)
+				if(val)
+					this_params[j] = /*add_ref(*/val/*)*/;
+				else
+					this_params[j] = NULL;
+
+		}
+		VIS_PROFILE_END(PROF_OPT_PREP_INPUT);
+		if(!skip)
+		{
+			if(partial_flag)
+			{
+				VIS_PROFILE_START(PROF_PARTIAL_EXEC);
+				ready = 0;
+				for(j = exec_list[i].null_inputs; j < count; ++j)
+					if(this_params[j])
+					{
+						instance->workerlist[exec_list[i].original_pos].params[j-exec_list[i].null_inputs+1] = this_params[j];
+						++ready;
+					}
+				if(instance->def->implement_func->workerlist[exec_list[i].original_pos].null_input && this_params[exec_list[i].null_inputs-1])
+					++ready;
+				DEBUGPRINTF("ready: %d\n", ready);
+				skip = TRUE;
+				VIS_EnterCriticalSection(instance->workerlist[exec_list[i].original_pos].worker_lock);
+					instance->workerlist[exec_list[i].original_pos].ready_count += ready;
+					if(instance->workerlist[exec_list[i].original_pos].ready_count >= (exec_list[i].def->num_inputs + (instance->def->implement_func->workerlist[exec_list[i].original_pos].null_input ? 1 : 0)))
+					{
+						skip = FALSE;
+						instance->workerlist[exec_list[i].original_pos].ready_count = 0;
+						
+					}
+					DEBUGPRINTF("ready_count: %d\n", instance->workerlist[exec_list[i].original_pos].ready_count);
+				VIS_LeaveCriticalSection(instance->workerlist[exec_list[i].original_pos].worker_lock);
+				if(!skip)
+					add_queue(exec_list[i].original_pos, instance);
+				VIS_PROFILE_END(PROF_PARTIAL_EXEC);
+			}
+			else if(exec_list[i].def)
+			{
+				VIS_PROFILE_START(PROF_FULL_EXEC);
+				DEBUGPRINTF("opt_exec: %s(%d)\n", exec_list[i].def->name, exec_list[i].original_pos);
+				entry.worker_num = exec_list[i].original_pos;
+				if(exec_list[i].def->type & USER_FLAG)
+				{
+					VIS_PROFILE_START(PROF_OPT_EXEC_USER);
+					instance->workerlist[exec_list[i].original_pos].params[0] = NULL;
+					memcpy(instance->workerlist[exec_list[i].original_pos].params+1, this_params + exec_list[i].null_inputs, sizeof(datum *) * exec_list[i].def->num_inputs);
+					add_queue(exec_list[i].original_pos, instance);
+					VIS_PROFILE_END(PROF_OPT_EXEC_USER);
+				}
+				else
+				{
+					VIS_PROFILE_START(PROF_OPT_EXEC_BUILT);
+					if(execute_def(exec_list[i].def, entry, this_params + exec_list[i].null_inputs, sub_callback) == 0)
+					{
+						DEBUGPUTS("Exectuted with reslts\n");
+						if(exec_list[i].output_refs)
+						{
+							for(j = exec_list[i].null_inputs; j < (exec_list[i].def->num_outputs+exec_list[i].null_inputs); ++j)
+							{
+								DEBUGPRINTF("output_refs[%d] = %d\n", j-exec_list[i].null_inputs, exec_list[i].output_refs[j-exec_list[i].null_inputs]);
+								if(!exec_list[i].output_refs[j-exec_list[i].null_inputs])
+									release_ref(this_params[j]);
+								else if(exec_list[i].output_refs[j-exec_list[i].null_inputs] > 1)
+								{
+									/*DEBUGPRINTF("multi_add_ref(%X): %d\n", this_params[j], exec_list[i].output_refs[j-exec_list[i].null_inputs]-1);
+									tmp = (int)(&(this_params[j]->ref_count));
+									addnum = exec_list[i].output_refs[j-exec_list[i].null_inputs]-1;
+									__asm
+									{
+										mov ebx, tmp
+										mov eax, addnum
+										lock xadd dword ptr [ebx], eax
+									}*/
+									VIS_EnterCriticalSection(this_params[j]->lock);
+										this_params[j]->ref_count += exec_list[i].output_refs[j-exec_list[i].null_inputs]-1;
+										
+									VIS_LeaveCriticalSection(this_params[j]->lock);
+								}
+							}
+							memcpy(results + i*32, this_params + exec_list[i].null_inputs, sizeof(datum *) * exec_list[i].def->num_outputs);
+							if(exec_list[i].branch1 >= 0)
+							{
+								if(this_params[exec_list[i].null_inputs])
+								{
+									jump_from = exec_list[i].branch1;
+									jump_to = exec_list[i].branch2;
+								}
+								else
+								{
+									i = exec_list[i].branch1-1;
+								}
+							}
+						}
+					}
+					/*else
+					{
+						for(j = exec_list[i].null_inputs; j < (exec_list[i].def->num_outputs + exec_list[i].null_inputs); ++j)
+							results[(i*32)|j] = NULL;
+					}*/
+					VIS_PROFILE_END(PROF_OPT_EXEC_BUILT);
+				}
+				VIS_PROFILE_END(PROF_FULL_EXEC);
+				DEBUGPUTS("Executed\n");
+			}
+			else
+				instance->workerlist[exec_list[i].original_pos].value = this_params[exec_list[i].null_inputs];
+		}
+		else
+		{
+			DEBUGPUTS("Skipped\n");
+			if(exec_list[i].def)
+			{
+				for(j = 0; j < exec_list[i].def->num_outputs; ++j)
+					results[(i*32)|j] = NULL;
+			}
+		}
+		if(jump_from >= 0 && (i+1) == jump_from)
+		{
+			i = jump_to-1;
+			jump_from = -1;
+		}
+		VIS_PROFILE_END(PROF_OPT_LOOP);
+	}
+	DEBUGPUTS("run_optimized calling cleanup_check\n");
+	for(i = 0; i < instance->def->num_inputs; ++i)
+		release_ref(params[i]);
+	cleanup_check(entry);
+	VIS_PROFILE_END(PROF_RUN_OPT);
+}
+
+int vis_print(datum ** inputlist, queue_entry * worker_entry)
+{
+	int result;
+#ifdef	CONSOLE
+	puts((char *)inputlist[0]->c.generic.data);
+#else
+	MessageBox(NULL, (char *)inputlist[0]->c.generic.data, "Visuality Output", MB_OK);
+#endif
+	result = 1;
+
+	release_ref(inputlist[0]);
+	inputlist[0] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, worker_entry->instance->def->program);
+	//No one else knows about this new datum yet so we can skip getting a lock
+	datum_set_yesno(inputlist[0], result);
+	return 0;
+}
+
+int vis_end(datum ** inputlist, queue_entry * worker_entry)
+{
+//	fprintf(outfile, "End worker reached.\n");
+	execute_active=FALSE;
+	release_ref(inputlist[0]);
+	//interp_stop();
+	return 0;
+}
+
+#ifdef NINTENDO_DS
+const char keyLetters[15] = "ABESRLUD><XYMC";
+#define MAX_KEY_BITS	14
+#endif
+
+int vis_getinput(datum ** inputlist, queue_entry * worker_entry)
+{
+	#ifdef NINTENDO_DS
+		int held,i,pos;
+		char tempstring[14];
+		scanKeys();
+		held = keysHeld();
+		if(held)
+		{
+			pos = 0;
+			for(i = 0; i < MAX_KEY_BITS; ++i)
+				if(held & (1 << i))
+					tempstring[pos++] = keyLetters[i];
+			inputlist[0] = new_datum(BUILTIN_TYPE_STRING, 1, pos+1, worker_entry->instance->def->program);
+			memcpy(inputlist[0]->c.generic.data, tempstring, pos);
+			((char *)inputlist[0]->c.generic.data)[pos]='\0';
+			return 0;
+		}
+		else
+		{
+			requeue(worker_entry->worker_num, worker_entry->instance);
+			return 1;
+		}
+	#else
+		#ifdef CONSOLE
+			gets(text_buf);
+			text_buf_size = strlen(text_buf);
+			//Nasty hack for testing until I get around to supporting command line args propery
+			//text_buf_size = strlen(global_argv[1]);
+		#else
+		
+		while(text_buf_size <= 0)
+		{
+			Sleep(30); //TODO: replace with I/O queue mechanism
+		}
+		#endif
+	//	VIS_EnterCriticalSection(text_buf_lock);
+			DEBUGPRINTF("Allocating %d bytes\n", text_buf_size+1);
+			inputlist[0] = new_datum(BUILTIN_TYPE_STRING, 1, text_buf_size+1, worker_entry->instance->def->program);
+			DEBUGPUTS("Allocated datum.\n");
+			memcpy(inputlist[0]->c.generic.data, text_buf, text_buf_size);
+			DEBUGPUTS("Copied string.\n");
+			((char *)inputlist[0]->c.generic.data)[text_buf_size]='\0';
+			DEBUGPRINTF("Input is %s\n", inputlist[0]->c.generic.data);
+			text_buf_size = 0;
+	//	VIS_LeaveCriticalSection(text_buf_lock);
+		return 0;
+	#endif
+}
+
+int vis_if(datum ** inputlist, queue_entry * worker_entry)
+{
+	if(!(inputlist[0]->c.integers.num_a))
+	{
+		inputlist[1] = inputlist[0];
+		inputlist[0] = NULL;
+	}
+	else
+		inputlist[1] = NULL;
+	return 0;
+}
+
+int vis_build(datum ** inputlist, queue_entry * worker_entry)
+{
+	int i,j;
+	company * companylist = worker_entry->instance->def->program->companylist;
+	int num_companies = worker_entry->instance->def->program->num_companies;
+	DEBUGPRINTF("Looking for company named %s\n", inputlist[0]->c.generic.data);
+	for(i = 0; i < num_companies; ++i)
+	{
+		DEBUGPRINTF("Checking company %d:%s\n", i, companylist[i].name);
+		if(!strcmp(inputlist[0]->c.generic.data, companylist[i].name))
+			break;
+	}
+	release_ref(inputlist[0]);
+	if(i < num_companies && companylist[i].build_size > 0)
+	{
+		DEBUGPRINTF("Building company with size %d\n", companylist[i].build_size);
+		inputlist[0] = new_datum(i, 1, companylist[i].build_size, worker_entry->instance->def->program);
+		for(j = 0; j < companylist[i].build_size; ++j)
+			((char*)(inputlist[0]->c.generic.data))[j] = 0;
+	}
+	else
+	{
+		DEBUGPUTS("Could not find company\n");
+		inputlist[0] = NULL;
+	}
+	return 0;
+}
+
+int vis_wait_forever(datum ** inputlist, queue_entry * worker_entry)
+{
+	return 1;
+}
+
+int init_global_store(datum ** inputlist, queue_entry * worker_entry)
+{
+	datum * params[3];
+	global_store * store;
+	datum * store_dat = new_datum(BUILTIN_TYPE_GLOBAL_STORE, 1, sizeof(global_store), worker_entry->instance->def->program);
+	store = store_dat->c.generic.data;
+	store->name = add_ref(inputlist[0]);
+	store->data = create_dict(worker_entry->instance->def->program);
+	VIS_EnterCriticalSection(global_store_lock);
+		params[0] = global_store_dict;
+		params[1] = inputlist[0];
+		params[2] = store_dat;
+		vis_dict_set(params, NULL);
+		global_store_dict = params[0];
+		DEBUGPUTS("Global store init complete\n");
+	VIS_LeaveCriticalSection(global_store_lock);
+	DEBUGPUTS("Released global_store_lock\n");
+	inputlist[0] = NULL;
+	return 0;
+}
+
+int vis_type_of(datum ** inputlist, queue_entry * worker_entry)
+{
+	datum * output = make_string(inputlist[0]->company->name, -1, worker_entry->instance->def->program);
+	release_ref(inputlist[0]);
+	inputlist[0] = output;
+	return 0;
+}
+
+int vis_random(datum ** inputlist, queue_entry * worker_entry)
+{
+	inputlist[0] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program);
+	VIS_EnterCriticalSection(randlock);
+		inputlist[0]->c.integers.num_a = genrand_int32();
+	VIS_LeaveCriticalSection(randlock);
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/interp.h	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,309 @@
+#ifndef	_INTERP_H_
+#define _INTERP_H_
+
+#ifdef WIN32
+	#include <windows.h>
+#endif
+
+#ifndef BOOL
+	#define BOOL short
+	#define	TRUE	1
+	#define	FALSE	0
+#endif
+
+#ifndef DWORD
+	#define	DWORD	unsigned long
+#endif
+
+#ifndef	WINAPI
+	#define WINAPI
+#endif
+
+#ifndef LPVOID
+	#define LPVOID void *
+#endif
+#ifndef NULL
+	#define NULL 0
+#endif
+#include "vis_threading.h"
+#include "structs.h"
+#include "debugmacros.h"
+
+#define	CONSTANT		0
+#define	ROOM			1
+#define	WORKER			2
+#define	INPUT			3
+#define	OUTPUT			4
+#define SET_COMP		5
+#define GET_COMP		6
+#define SET_GLOBAL		7
+#define	GET_GLOBAL		8
+#define TAIL_CALL		9
+#define TAIL_RECURSE	10
+
+#define	RECTANGLE	1
+#define	TRAPEZOID	2
+
+
+#define WORKER_TYPE	0
+#define	MAGIC_TYPE	1
+#define	USER_FLAG	0x8000
+#define	TYPE_MASK 	0xFF
+
+#define START_COMP_STORAGE	40
+#define START_DEF_STORAGE	100
+
+#ifdef CPLUSPLUS
+extern "C" {
+#endif
+
+//extern company companylist[];
+//extern int num_companies;
+extern BOOL execute_active;
+extern int program_count;
+VIS_EXTERN_CRITICAL_SECTION(program_count_lock)
+
+void main_callback(worker_instance * junkinst, int junk, worker_instance * main_instance, void * data);
+
+void optimize(worker_def * def);
+void run_optimized(worker_instance * instance, datum ** params);
+datum * get_constant(char * value, int len, program * prog);
+int execute_def(worker_def * process_def, queue_entry worker_entry, datum ** params, instance_callback callback);
+int execute_def_data(worker_def * process_def, queue_entry worker_entry, datum ** params, instance_callback callback, void * data);
+BOOL execute_def_wait(worker_def * def, datum ** params);
+int process_worker(queue_entry aworker);
+void initworkers(program * prog);
+void initpredefworkers(program * prog);
+DWORD WINAPI worker_thread(LPVOID param);
+void interp_start(int num_threads, BOOL use_this_thread, int argc, char ** argv, program * initial_prog);
+void interp_stop();
+void add_if_ready(int workerNum, worker_instance * instance);
+void make_lookup_arrays(program * prog);
+void def_make_lookup(worker_def * def);
+queue_entry get_queue();
+void add_queue(int data, worker_instance * instance);
+void add_multiple(int * data, int num, worker_instance * instance);
+void init_sync_primitives();
+void init_global_storage();
+void pack_list_sub_callback(worker_instance * caller_instance, int caller_workernum, worker_instance * done_instance, void * data);
+worker_def * find_method(int type, char * name, int num_inputs, program * prog);
+worker_def * find_method_noinputcheck(int type, char * name, program * prog);
+worker_def * find_converter_method(int totype, int fromtype, program * prog);
+
+//doesn't belong here, but because of include order issues I can't put it in datum.h
+datum * new_datum_comp(company * comp, unsigned char union_type, int generic_len);
+
+void vis_window_init(); //defined in window.cpp
+
+int vis_random(datum ** inputlist, queue_entry * worker_entry);
+int vis_print(datum ** inputlist, queue_entry * worker_entry);
+int vis_build(datum ** inputlist, queue_entry * worker_entry);
+int vis_end(datum ** inputlist, queue_entry * worker_entry);
+int vis_append(datum ** inputlist, queue_entry * worker_entry);
+int vis_getinput(datum ** inputlist, queue_entry * worker_entry);
+int vis_stringtoint(datum ** inputlist, queue_entry * worker_entry);
+int vis_string_get_dstring(datum ** inputlist, queue_entry * worker_entry);
+int vis_whole_add(datum ** inputlist, queue_entry * worker_entry);
+int vis_whole_fromhex(datum ** inputlist, queue_entry * worker_entry);
+int vis_whole_subtract(datum ** inputlist, queue_entry * worker_entry);
+int vis_whole_mult(datum ** inputlist, queue_entry * worker_entry);
+int vis_whole_div(datum ** inputlist, queue_entry * worker_entry);
+int vis_whole_or(datum ** inputlist, queue_entry * worker_entry);
+int vis_whole_and(datum ** inputlist, queue_entry * worker_entry);
+int vis_whole_lsh(datum ** inputlist, queue_entry * worker_entry);
+int vis_whole_rsh(datum ** inputlist, queue_entry * worker_entry);
+int vis_inttostring(datum ** inputlist, queue_entry * worker_entry);
+int vis_stringequal(datum ** inputlist, queue_entry * worker_entry);
+int vis_string_split(datum ** inputlist, queue_entry * worker_entry);
+int vis_string_get_raw(datum ** inputlist, queue_entry * worker_entry);
+int vis_string_put_raw(datum ** inputlist, queue_entry * worker_entry);
+int vis_string_slice(datum ** inputlist, queue_entry * worker_entry);
+int vis_string_reverse(datum ** inputlist, queue_entry * worker_entry);
+int vis_string_length(datum ** inputlist, queue_entry * worker_entry);
+int vis_string_put_byte(datum ** inputlist, queue_entry * worker_entry);
+int vis_wholeequal(datum ** inputlist, queue_entry * worker_entry);
+int vis_if(datum ** inputlist, queue_entry * worker_entry);
+int vis_yesnotostring(datum ** inputlist, queue_entry * worker_entry);
+int vis_greaterint(datum ** inputlist, queue_entry * worker_entry);
+int vis_lesserint(datum ** inputlist, queue_entry * worker_entry);
+int vis_greaterstring(datum ** inputlist, queue_entry * worker_entry);
+int vis_lesserstring(datum ** inputlist, queue_entry * worker_entry);
+int vis_stringtoreal(datum ** inputlist, queue_entry * worker_entry);
+int vis_real_add(datum ** inputlist, queue_entry * worker_entry);
+int vis_real_subtract(datum ** inputlist, queue_entry * worker_entry);
+int vis_realequal(datum ** inputlist, queue_entry * worker_entry);
+int vis_greaterreal(datum ** inputlist, queue_entry * worker_entry);
+int vis_lesserreal(datum ** inputlist, queue_entry * worker_entry);
+int vis_realtostring(datum ** inputlist, queue_entry * worker_entry);
+//Index, Append, Swap, Insert, Remove, Set, Length, New
+int vis_list_index(datum ** inputlist, queue_entry * worker_entry);
+int vis_list_append(datum ** inputlist, queue_entry * worker_entry);
+int vis_list_swap(datum ** inputlist, queue_entry * worker_entry);
+int vis_list_insert(datum ** inputlist, queue_entry * worker_entry);
+int vis_list_remove(datum ** inputlist, queue_entry * worker_entry);
+int vis_list_set(datum ** inputlist, queue_entry * worker_entry);
+int vis_list_length(datum ** inputlist, queue_entry * worker_entry);
+int vis_list_new(datum ** inputlist, queue_entry * worker_entry);
+int vis_list_first(datum ** inputlist, queue_entry * worker_entry);
+int vis_list_next(datum ** inputlist, queue_entry * worker_entry);
+int vis_dict_index(datum ** inputlist, queue_entry * worker_entry);
+int vis_dict_swap(datum ** inputlist, queue_entry * worker_entry);
+int vis_dict_remove(datum ** inputlist, queue_entry * worker_entry);
+int vis_dict_set(datum ** inputlist, queue_entry * worker_entry);
+int vis_dict_length(datum ** inputlist, queue_entry * worker_entry);
+int vis_dict_new(datum ** inputlist, queue_entry * worker_entry);
+int vis_dict_first(datum ** inputlist, queue_entry * worker_entry);
+int vis_dict_next(datum ** inputlist, queue_entry * worker_entry);
+int vis_file_from_string(datum ** inputlist, queue_entry * worker_entry);
+int vis_file_get_fstring(datum ** inputlist, queue_entry * worker_entry);
+int vis_file_get_dstring(datum ** inputlist, queue_entry * worker_entry);
+int vis_file_get_byte(datum ** inputlist, queue_entry * worker_entry);
+int vis_file_get_word(datum ** inputlist, queue_entry * worker_entry);
+int vis_file_get_long(datum ** inputlist, queue_entry * worker_entry);
+int vis_file_put_string(datum ** inputlist, queue_entry * worker_entry);
+int vis_file_length(datum ** inputlist, queue_entry * worker_entry);
+int vis_worker_from_string(datum ** inputlist, queue_entry * worker_entry);
+int vis_worker_do(datum ** inputlist, queue_entry * worker_entry);
+int vis_worker_setinput(datum ** inputlist, queue_entry * worker_entry);
+int vis_window_new(datum ** inputlist, queue_entry * worker_entry);
+int vis_window_add_widget(datum ** inputlist, queue_entry * worker_entry);
+int vis_window_show(datum ** inputlist, queue_entry * worker_entry);
+int vis_window_wait_close(datum ** inputlist, queue_entry * worker_entry);
+int vis_window_get_value(datum ** inputlist, queue_entry * worker_entry);
+int vis_window_set_value(datum ** inputlist, queue_entry * worker_entry);
+int vis_window_shown_addwidget(datum ** inputlist, queue_entry * worker_entry);
+int vis_worker_add_worker_call(datum ** inputlist, queue_entry * worker_entry);
+int vis_worker_add_wire(datum ** inputlist, queue_entry * worker_entry);
+int vis_worker_add_constant(datum ** inputlist, queue_entry * worker_entry);
+int vis_worker_add_input(datum ** inputlist, queue_entry * worker_entry);
+int vis_worker_add_output(datum ** inputlist, queue_entry * worker_entry);
+int vis_worker_add_globalget(datum ** inputlist, queue_entry * worker_entry);
+int vis_worker_add_globalset(datum ** inputlist, queue_entry * worker_entry);
+int vis_worker_clear(datum ** inputlist, queue_entry * worker_entry);
+int vis_worker_uses(datum ** inputlist, queue_entry * worker_entry);
+int vis_worker_new(datum ** inputlist, queue_entry * worker_entry);
+int vis_worker_setio_counts(datum ** inputlist, queue_entry * worker_entry);
+int vis_program_run(datum ** inputlist, queue_entry * worker_entry);
+int vis_program_add_builtins(datum ** inputlist, queue_entry * worker_entry);
+int vis_program_new_worker(datum ** inputlist, queue_entry * worker_entry);
+int vis_program_new(datum ** inputlist, queue_entry * worker_entry);
+int vis_program_find_worker(datum ** inputlist, queue_entry * worker_entry);
+int vis_program_add_worker(datum ** inputlist, queue_entry * worker_entry);
+int vis_button_new(datum ** inputlist, queue_entry * worker_entry);
+int vis_button_set_handler(datum ** inputlist, queue_entry * worker_entry);
+int vis_inputbox_new(datum ** inputlist, queue_entry * worker_entry);
+int vis_inputbox_settype(datum ** inputlist, queue_entry * worker_entry);
+int net_client_new(datum ** params, queue_entry * worker_entry);
+int net_client_put_string(datum ** params, queue_entry * worker_entry);
+int net_client_get_fstring(datum ** params, queue_entry * worker_entry);
+int net_client_get_dstring(datum ** params, queue_entry * worker_entry);
+int net_client_put_raw(datum ** params, queue_entry * worker_entry);
+int net_client_get_raw(datum ** params, queue_entry * worker_entry);
+int vis_net_listenport(datum ** params, queue_entry * worker_entry);
+int vis_wait_forever(datum ** params, queue_entry * worker_entry);
+int vis_screen_custom_defaultpaint(datum ** params, queue_entry * entry);
+int vis_screen_custom_drawline(datum ** params, queue_entry * entry);
+int vis_screen_custom_drawstring(datum ** params, queue_entry * entry);
+int vis_screen_custom_setdrawcolor(datum ** params, queue_entry * entry);
+int vis_screen_custom_moveby(datum ** params, queue_entry * entry);
+int vis_screen_custom_sethandler(datum ** params, queue_entry * entry);
+int vis_screen_custom_removehandler(datum ** params, queue_entry * entry);
+int vis_screen_custom_givefocus(datum ** params, queue_entry * entry);
+int vis_screen_custom_addwidget(datum ** params, queue_entry * entry);
+int vis_screen_custom_getwindow(datum ** params, queue_entry * entry);
+int vis_customwidget_new(datum ** inputlist, queue_entry * worker_entry);
+int vis_checkbox_new(datum ** params, queue_entry * entry);
+int vis_dropdown_new(datum ** params, queue_entry * entry);
+int vis_dropdown_settext(datum ** params, queue_entry * entry);
+int vis_dropdown_select(datum ** params, queue_entry * entry);
+int vis_buffer_new(datum ** params, queue_entry * entry);
+int vis_buffer_lock(datum ** params, queue_entry * entry);
+int vis_buffer_unlock(datum ** params, queue_entry * entry);
+int vis_buffer_putbyte(datum ** params, queue_entry * entry);
+int vis_buffer_writebyte(datum ** params, queue_entry * entry);
+int vis_buffer_putshort(datum ** params, queue_entry * entry);
+int vis_buffer_writeshort(datum ** params, queue_entry * entry);
+int vis_buffer_putlong(datum ** params, queue_entry * entry);
+int vis_buffer_writelong(datum ** params, queue_entry * entry);
+int vis_buffer_reset(datum ** params, queue_entry * entry);
+int vis_buffer_fromaddress(datum ** params, queue_entry * entry);
+int init_global_store(datum ** params, queue_entry * worker_entry);
+int vis_type_of(datum ** params, queue_entry * worker_entry);
+int vis_real_div(datum ** inputlist, queue_entry * worker_entry);
+int vis_clear_handler(datum ** params, queue_entry * entry);
+int vis_register_handler(datum  ** params, queue_entry * entry);
+int vis_held_keys(datum ** params, queue_entry * worker_entry);
+int vis_touch_position(datum ** params, queue_entry * worker_entry);
+int vis_blueprint_new(datum ** params, queue_entry * entry);
+int vis_blueprint_addfield(datum ** params, queue_entry * entry);
+int vis_blueprint_name(datum ** params, queue_entry * entry);
+int vis_blueprint_getfields(datum ** params, queue_entry * entry);
+int vis_get_blueprint(datum ** params, queue_entry * entry);
+int vis_get_field(datum ** params, queue_entry * entry);
+int vis_set_field(datum ** params, queue_entry * entry);
+int vis_program_newblueprint(datum ** params, queue_entry * entry);
+int vis_worker_add_objectset(datum ** inputlist, queue_entry * worker_entry);
+int vis_worker_add_objectget(datum ** inputlist, queue_entry * worker_entry);
+
+datum * make_string(const char * string, int len, program * prog);
+void close_sync_primitives();
+void vis_window_closed(datum * window_datum);
+void cleanup_check(queue_entry aworker);
+void cleanup_custom_worker(worker_instance * instance, int worker_num);
+void process_outputs(datum ** params, int aworker, worker_instance * instance);
+void worker_complete(queue_entry aworker);
+void test_virtual();
+datum * create_dict(program * prog);
+datum * create_list(program * prog);
+int worker_populate_inputs(datum * inputWorker, datum * ioList, datum ** inputlist);
+void run_queued_irqs();
+void prep_program(program * prog);
+void add_program_ref(program * prog);
+void release_program_ref(program * prog);
+
+extern int irq_queue_count;
+
+#ifdef	ENABLE_PROFILING
+#define	NUM_PROFS					33
+
+extern __int64	vis_profile_start_times[NUM_PROFS];
+extern __int64 vis_profile_running_total[NUM_PROFS];
+extern int	vis_profile_counts[NUM_PROFS];
+unsigned __int64 __cdecl rdtsc(void);
+
+#define VIS_PROFILE_START(index)	vis_profile_start_times[index] = rdtsc()
+#define	VIS_PROFILE_END(index)		vis_profile_running_total[index] += (rdtsc()-vis_profile_start_times[index]); ++vis_profile_counts[index]
+
+#define PROF_ADDREF	29
+#define PROF_RELEASE	30
+#define PROF_NEW_DATUM	31	
+#define PROF_DATUM_ALLOC	32
+
+#else
+#define VIS_PROFILE_START(index)
+#define	VIS_PROFILE_END(index)
+#endif
+
+
+#ifdef CPLUSPLUS
+}
+#endif
+
+
+#endif //_INTERP_H_
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/list.c	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,290 @@
+#include "structs.h"
+#include "datum.h"
+#include "interp.h"
+#include <stdlib.h>
+#include <string.h>
+
+datum * create_list(program * prog)
+{
+	short i;
+	datum * dat = new_datum(BUILTIN_TYPE_LIST, 1, sizeof(list_data) + sizeof(datum *)*7, prog);
+	dat->c.generic.len = 8;
+	((list_data *)dat->c.generic.data)->num_entries = 0;
+	return dat;
+}
+
+int vis_list_new(datum ** inputlist, queue_entry * worker_entry)
+{
+	inputlist[0] = create_list(worker_entry->instance->def->program);
+	return 0;
+}
+
+int vis_list_append(datum ** inputlist, queue_entry * worker_entry)
+{
+	int ref_count, new_entry_count;
+	list_data * list, * new_list;
+	datum * output;
+	int i;
+	
+	VIS_EnterCriticalSection(inputlist[0]->lock);
+		ref_count = inputlist[0]->ref_count;
+	VIS_LeaveCriticalSection(inputlist[0]->lock);
+	list = ((list_data *)inputlist[0]->c.generic.data);
+	DEBUGPRINTF("append: generic.len = %d, list->num_entries = %d, ref_count = %d\n", inputlist[0]->c.generic.len, list->num_entries, ref_count);
+	if(ref_count == 1)
+	{
+		if(inputlist[0]->c.generic.len > list->num_entries)
+		{
+			DEBUGPUTS("Fast append\n");
+			list->entries[list->num_entries] = inputlist[1]; //No need to add_ref because we're consuming the ref we wer passed
+			++(list->num_entries);
+		}
+		else
+		{
+			DEBUGPUTS("malloc append\n");
+			new_entry_count = list->num_entries + (list->num_entries > 1);//grow by half current size
+			new_list = malloc((new_entry_count -1) * sizeof(datum *) + sizeof(list_data));
+			new_list->num_entries = list->num_entries+1;
+			inputlist[0]->c.generic.len = new_entry_count;
+			memcpy(new_list->entries, list->entries, list->num_entries * sizeof(datum *));
+			new_list->entries[list->num_entries] = inputlist[1];
+			inputlist[0]->c.generic.data = new_list;
+			VIS_FREE(list, "List object");
+		}
+	}
+	else
+	{
+		DEBUGPUTS("datum copy append\n");
+		
+		if(inputlist[0]->c.generic.len > list->num_entries)
+			new_entry_count = inputlist[0]->c.generic.len;
+		else
+			new_entry_count = list->num_entries + (list->num_entries > 1);//grow by half current size
+		output = new_datum_comp(inputlist[0]->company, 1, (new_entry_count -1) * sizeof(datum *) + sizeof(list_data));
+		new_list = output->c.generic.data;
+		new_list->num_entries = list->num_entries+1;
+		output->c.generic.len = new_entry_count;
+		for(i = 0; i < list->num_entries; ++i)
+			new_list->entries[i] = add_ref(list->entries[i]);
+		new_list->entries[list->num_entries] = inputlist[1];
+		release_ref(inputlist[0]);
+		inputlist[0] = output;
+	}
+	DEBUGPRINTF("append: generic.len = %d, list->num_entries = %d\n", inputlist[0]->c.generic.len, ((list_data *)inputlist[0]->c.generic.data)->num_entries);
+	return 0;
+}
+
+int vis_list_swap(datum ** inputlist, queue_entry * worker_entry)
+{
+	//TODO: Throw error if indices out of bounds
+	list_data * list;
+	datum * temp;
+	inputlist[0] = copy_datum(inputlist[0], 0);
+	list = ((list_data *)inputlist[0]->c.generic.data);
+
+	temp = list->entries[inputlist[1]->c.integers.num_a];
+	list->entries[inputlist[1]->c.integers.num_a] = list->entries[inputlist[2]->c.integers.num_a];
+	list->entries[inputlist[2]->c.integers.num_a] = temp;
+	release_ref(inputlist[1]);
+	release_ref(inputlist[2]);
+	return 0;
+}
+
+int vis_list_index(datum ** inputlist, queue_entry * worker_entry)
+{
+	//TODO: Throw error if indices out of bounds
+	list_data * list = ((list_data *)inputlist[0]->c.generic.data);
+	datum * output;
+	DEBUGPRINTF("index: generic.len = %d, list->num_entries = %d, requested index: %d\n", inputlist[0]->c.generic.len, list->num_entries, inputlist[1]->c.integers.num_a);
+	DEBUGPRINTF("list->entries[%d] = %X\n", inputlist[1]->c.integers.num_a, list->entries[inputlist[1]->c.integers.num_a]);
+	if(inputlist[1]->c.integers.num_a < list->num_entries && list->entries[inputlist[1]->c.integers.num_a])
+	{
+		output = add_ref(list->entries[inputlist[1]->c.integers.num_a]);
+		release_ref(inputlist[1]);
+		inputlist[1] = NULL;
+	}
+	else
+	{
+		output = NULL;
+		inputlist[1] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, worker_entry->instance->def->program);
+		inputlist[1]->c.integers.num_a = 0;
+	}
+	
+	release_ref(inputlist[0]);
+	inputlist[0] = output;
+	return 0;
+}
+
+int vis_list_insert(datum ** inputlist, queue_entry * worker_entry)
+{
+	int ref_count, new_entry_count;
+	list_data * list, * new_list;
+	datum * output;
+	int i;
+	VIS_EnterCriticalSection(inputlist[0]->lock);
+		ref_count = inputlist[0]->ref_count;
+	VIS_LeaveCriticalSection(inputlist[0]->lock);
+	list = ((list_data *)inputlist[0]->c.generic.data);
+	if(ref_count == 1)
+	{
+		if(inputlist[0]->c.generic.len > list->num_entries)
+		{
+			memmove(list->entries + inputlist[1]->c.integers.num_a + 1, list->entries + inputlist[1]->c.integers.num_a, sizeof(datum *) * (list->num_entries-inputlist[1]->c.integers.num_a));
+			list->entries[inputlist[1]->c.integers.num_a] = inputlist[2]; //No need to add_ref because we're consuming the ref we wer passed
+			++(list->num_entries);
+		}
+		else
+		{
+			new_entry_count = list->num_entries + (list->num_entries > 1);//grow by half current size
+			new_list = malloc((new_entry_count -1) * sizeof(datum *) + sizeof(list_data));
+			new_list->num_entries = list->num_entries+1;
+			inputlist[0]->c.generic.len = new_entry_count;
+			memcpy(new_list->entries, list->entries, list->num_entries * sizeof(datum *));
+			new_list->entries[list->num_entries] = inputlist[1];
+			inputlist[0]->c.generic.data = new_list;
+			VIS_FREE(list, "List object");
+		}
+	}
+	else
+	{
+		new_entry_count = list->num_entries + (list->num_entries > 1);//grow by half current size
+		output = new_datum_comp(inputlist[0]->company, 1, (new_entry_count -1) * sizeof(datum *) + sizeof(list_data));
+		new_list = output->c.generic.data;
+		new_list->num_entries = list->num_entries+1;
+		output->c.generic.len = new_entry_count;
+		for(i = 0; i < inputlist[1]->c.integers.num_a; ++i)
+			new_list->entries[i] = add_ref(list->entries[i]);
+		for(i = inputlist[1]->c.integers.num_a; i < list->num_entries; ++i)
+			new_list->entries[i+1] = add_ref(list->entries[i]);
+		release_ref(inputlist[0]);
+		new_list->entries[list->num_entries] = inputlist[2];
+		inputlist[0] = output;
+	}
+	release_ref(inputlist[1]);
+	return 0;
+}
+
+int vis_list_remove(datum ** inputlist, queue_entry * worker_entry)
+{
+	int ref_count, new_entry_count;
+	list_data * list, * new_list;
+	int i;
+	datum * output;
+	VIS_EnterCriticalSection(inputlist[0]->lock);
+		ref_count = inputlist[0]->ref_count;
+	VIS_LeaveCriticalSection(inputlist[0]->lock);
+	list = ((list_data *)inputlist[0]->c.generic.data);
+	if(ref_count == 1)
+	{
+		release_ref(list->entries[inputlist[1]->c.integers.num_a]);
+		memmove(list->entries + inputlist[1]->c.integers.num_a, list->entries + inputlist[1]->c.integers.num_a + 1, sizeof(datum *) * (list->num_entries-(inputlist[1]->c.integers.num_a+1)));
+		--(list->num_entries);
+	}
+	else
+	{
+		new_entry_count = list->num_entries + (list->num_entries > 1);//grow by half current size
+		output = new_datum_comp(inputlist[0]->company, 1, (new_entry_count -1) * sizeof(datum *) + sizeof(list_data));
+		new_list = output->c.generic.data;
+		new_list->num_entries = list->num_entries+1;
+		output->c.generic.len = new_entry_count;
+		for(i = 0; i < inputlist[1]->c.integers.num_a; ++i)
+			new_list->entries[i] = add_ref(list->entries[i]);
+		for(i = inputlist[1]->c.integers.num_a+1; i < list->num_entries; ++i)
+			new_list->entries[i-1] = add_ref(list->entries[i]);
+		release_ref(inputlist[0]);
+		inputlist[0] = output;
+	}
+	release_ref(inputlist[1]);
+	return 0;
+}
+
+int vis_list_set(datum ** inputlist, queue_entry * worker_entry)
+{
+	int new_num_entries, new_generic_len, i;
+	list_data * list;
+	DEBUGPUTS("vis_list_set\n");
+	if(((list_data *)inputlist[0]->c.generic.data)->num_entries <= inputlist[1]->c.integers.num_a)
+	{
+		new_num_entries = inputlist[1]->c.integers.num_a + 1;
+		new_generic_len = (new_num_entries + (new_num_entries>>1)-1)*sizeof(datum*) + sizeof(list_data);
+	}
+	else 
+	{
+		new_num_entries = ((list_data *)inputlist[0]->c.generic.data)->num_entries;
+		new_generic_len = 0;
+	}
+	DEBUGPRINTF("new_generic_len: %d, new num_entries: %d\n", new_generic_len, new_num_entries);
+	inputlist[0] = copy_datum(inputlist[0], new_generic_len);
+	if(new_generic_len) {
+		inputlist[0]->c.generic.len = (new_num_entries + (new_num_entries>>1));
+	}
+	DEBUGPUTS("Datum copy done\n");
+	list = ((list_data *)inputlist[0]->c.generic.data);
+	DEBUGPUTS("before Null fill loop\n");
+	for(i = list->num_entries; i < new_num_entries; ++i)
+		list->entries[i] = NULL;
+	DEBUGPUTS("Before existing entry release_ref\n");
+	if(inputlist[1]->c.integers.num_a < list->num_entries)
+		release_ref(list->entries[inputlist[1]->c.integers.num_a]);
+	DEBUGPRINTF("Setting index %d to %X\n", inputlist[1]->c.integers.num_a, inputlist[2]);
+	list->entries[inputlist[1]->c.integers.num_a] = inputlist[2];
+	release_ref(inputlist[1]);
+	list->num_entries = new_num_entries;
+	DEBUGPUTS("vis_list_set done\n");
+	return 0;
+
+}
+
+int vis_list_length(datum ** inputlist, queue_entry * worker_entry)
+{
+	datum * output;
+	list_data * list = ((list_data *)inputlist[0]->c.generic.data);
+	output = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program);
+	output->c.integers.num_a = list->num_entries;
+	release_ref(inputlist[0]);
+	inputlist[0] = output;
+	return 0;
+}
+
+int vis_list_first(datum ** inputlist, queue_entry * worker_entry)
+{
+	int i;
+	list_data * list = inputlist[0]->c.generic.data;
+	if(!list->num_entries)
+	{
+		inputlist[1] = inputlist[0];
+		inputlist[0] = NULL;
+	}
+	else
+	{
+		i = 0;
+		while(!list->entries[i] && i < list->num_entries)
+			++i;
+		release_ref(inputlist[0]);
+		inputlist[0] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program);
+		inputlist[0]->c.integers.num_a = i;
+		inputlist[1] = NULL;
+	}
+	return 0;
+}
+
+int vis_list_next(datum ** inputlist, queue_entry * worker_entry)
+{
+	int i;
+	list_data * list = inputlist[0]->c.generic.data;
+	i = inputlist[1]->c.integers.num_a + 1;
+	while(i < list->num_entries && !list->entries[i])
+		++i;
+	if(i < list->num_entries)
+	{
+		release_ref(inputlist[0]);
+		inputlist[0] = copy_datum(inputlist[1], 0);
+		inputlist[1] = NULL;
+		inputlist[0]->c.integers.num_a = i;
+	} else {
+		release_ref(inputlist[1]);
+		inputlist[1] = inputlist[0];
+		inputlist[0] = NULL;
+	}
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/makefile	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,16 @@
+CFLAGS = -DCONSOLE -DGUI_LIB -DSYLLABLE
+OBJS = datum.o dict.o file.o interp.o list.o net.o number.o parser.o saveload.o string.o visuality_cmd.o worker.o vis_threading.o mt19937ar.o buffer.o blueprint.o window.o syl_window.o syl_generic.o
+
+rhope: $(OBJS)
+	g++ -o rhope -lsyllable $(OBJS)
+
+%.o:%.c
+	$(CC) $(CFLAGS) -c $<
+
+%.o:%.cpp
+	g++ -DCPLUSPLUS $(CFLAGS) -c $<
+
+clean:
+	rm *.o
+	rm rhope
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/makefile.linux	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,13 @@
+CFLAGS = -O2 -DCONSOLE -DUSE_OS_PRIMITIVES
+OBJS = datum.o dict.o file.o interp.o list.o net.o number.o parser.o saveload.o string.o visuality_cmd.o worker.o vis_threading.o mt19937ar.o buffer.o blueprint.o
+
+rhope: $(OBJS)
+	$(CC) -g -o rhope -lpthread $(OBJS)
+
+%.o:%.c
+	$(CC) $(CFLAGS) -g -c $<
+
+clean:
+	rm *.o
+	rm rhope
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/makefile.osx	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,13 @@
+CFLAGS = -O2 -force_cpusubtype_ALL -mmacosx-version-min=10.4 -arch i386 -arch ppc -DCONSOLE -DUSE_OS_PRIMITIVES
+OBJS = datum.o dict.o file.o interp.o list.o net.o number.o parser.o saveload.o string.o visuality_cmd.o worker.o mt19937ar.o buffer.o blueprint.o
+
+rhope: $(OBJS)
+	$(CC) -o rhope -lpthread $(OBJS)
+
+%.o:%.c
+	$(CC) $(CFLAGS) -c $<
+
+clean:
+	rm *.o
+	rm rhope
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/makefile.win32	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,8 @@
+OBJECTS = visuality_cmd.obj parser.obj interp.obj saveload.obj datum.obj number.obj string.obj list.obj dict.obj file.obj worker.obj net.obj mt19937ar.obj buffer.obj blueprint.obj
+
+rhope.exe : $(OBJECTS)
+	$(CC) $(OBJECTS) /Ox /Oy /Gr /MT /Ferhope.exe /link user32.lib wsock32.lib AdvAPI32.Lib
+
+.c.obj:
+	$(CC) /c /Ox /Oy /Gr /wd4005 -DCONSOLE=1 -D_CRT_SECURE_NO_DEPRECATE -D_WIN32_WINNT=0x0403 -DWIN32 $<
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/makefile.win32wind	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,8 @@
+OBJECTS = visuality_cmd.obj parser.obj interp.obj saveload.obj datum.obj number.obj string.obj list.obj dict.obj buffer.obj file.obj worker.obj net.obj window.obj ms_window.obj mt19937ar.obj blueprint.obj
+
+rhope_gui.exe : $(OBJECTS)
+	$(CC) $(OBJECTS) /MT /Ferhope_gui.exe /link user32.lib wsock32.lib AdvAPI32.Lib
+
+.c.obj:
+	$(CC) /c /wd4005 -DGUI_LIB -DCONSOLE=1 -D_CRT_SECURE_NO_DEPRECATE -D_WIN32_WINNT=0x0403 -DWIN32 $<
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ms_window.c	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,295 @@
+#include "datum.h"
+#include "structs.h"
+#include "ms_window.h"
+#include "interp.h"
+#include <string.h>
+#include <Windows.h>
+
+extern HINSTANCE glob_instance;
+extern int glob_cmd_show;
+
+char class_name[] = "RhopeApp";
+
+BOOL started_message_thread = FALSE;
+HWND * handle_list;
+size_t handle_list_storage;
+size_t handle_list_entries=0;
+datum ** window_list;
+
+
+datum * find_window(HWND window_handle)
+{
+	size_t i;
+	datum * returnval = NULL;
+	VIS_EnterCriticalSection(hwnd_lock);
+		for(i = 0; i < handle_list_entries; ++i)
+			if(handle_list[i] == window_handle)
+			{
+				returnval = window_list[i];
+				break;
+			}
+	VIS_LeaveCriticalSection(hwnd_lock);
+	return returnval;
+}
+
+
+LRESULT CALLBACK process_message (HWND window_handle, UINT message, WPARAM wparam, LPARAM lparam)
+{
+	datum * params[2];
+	datum * window_dat;
+	datum * worker;
+	queue_entry entry;
+	vis_window_shown * window;
+	char buf[256];
+	switch (message)
+	{
+
+		case WM_COMMAND:
+			if(HIWORD(wparam) == BN_CLICKED)
+			{
+				DEBUGPRINTF("Looking for window with handle %X\n", (int)window_handle);
+				window_dat = find_window(window_handle);
+				DEBUGPRINTF("Found %X\n", window_dat);
+				window = window_dat->c.generic.data;
+				window->instance.in_queue_count = window->instance.in_progress_count = 1000;
+				entry.instance = &(window->instance);
+				DEBUGPRINTF("Looking for handler for message %d\n", LOWORD(wparam));
+				worker = add_ref(((list_data *)(window->handler_list->c.generic.data))->entries[LOWORD(wparam)]);
+				params[0] = create_list(((worker_datum *)(worker->c.generic.data))->def->program);
+				params[1] = add_ref(window_dat);
+				DEBUGPUTS("Appending param to list\n");
+				vis_list_append(params, &entry);
+				params[1] = params[0];
+				params[0] = worker;
+				DEBUGPUTS("Calling handler\n");
+				vis_worker_do(params, &entry);
+			}
+			break;
+
+		case WM_DESTROY:
+			PostQuitMessage (0); 
+			break;
+	}
+	return DefWindowProc (window_handle, message, wparam, lparam);
+}
+
+DWORD WINAPI window_thread(datum * show_datum)
+{
+	list_data * list;
+	datum * params[3];
+	int flags;
+	int j;
+	vis_window * window;
+	double xpos, ypos;
+	datum * widget_datum;
+	vis_widget * widget;
+	char buf[256];
+	vis_window_shown * window_show = show_datum->c.generic.data;
+	MSG message;
+	HWND window_handle;
+	HWND widget_handle;
+	// Define the Window Class and try to register it 
+	WNDCLASSEX wc;
+	wc.cbSize        = sizeof (WNDCLASSEX);
+	wc.style         = 0; 
+	wc.lpfnWndProc   = process_message;
+	wc.cbClsExtra    = 0;
+    wc.cbWndExtra    = 0;
+    wc.hInstance     = glob_instance;
+    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
+    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
+	wc.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
+    wc.lpszMenuName  = NULL;
+    wc.lpszClassName = class_name;
+    wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);
+	if (!RegisterClassEx (&wc)) return 0;
+
+	// Create and Show the Window 
+	window_handle = CreateWindowEx (
+		0, class_name, window_show->title->c.generic.data,
+		WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 
+		window_show->width, window_show->height, 
+		HWND_DESKTOP, NULL, glob_instance, NULL);
+	//release_ref(show_datum);
+	
+	VIS_EnterCriticalSection(hwnd_lock);
+
+		if(!handle_list)
+		{
+			window_list = malloc(sizeof(datum *) * START_HANDLE_LIST);
+			handle_list = malloc(sizeof(HWND) * START_HANDLE_LIST);
+			handle_list_storage = START_HANDLE_LIST;
+		} 
+		else if(handle_list_entries == handle_list_storage)
+		{
+			handle_list_storage += START_HANDLE_LIST;
+			handle_list = realloc(handle_list, sizeof(HWND) * handle_list_storage);
+			window_list = realloc(window_list, sizeof(datum *) * handle_list_storage);
+		}
+		window_list[handle_list_entries] = show_datum;
+		handle_list[handle_list_entries++] = window_handle;
+	VIS_LeaveCriticalSection(hwnd_lock);
+	
+	if(window_show->orig_window)
+	{
+		window = window_show->orig_window->c.generic.data;
+		list = (list_data *)(window->id_list->c.generic.data);
+		for(j = 0; j < list->num_entries; ++j)
+		{
+			DEBUGPRINTF("Retrieving widget %d\n", j);
+			params[0] = add_ref(window->widget_dict);
+			params[1] = add_ref(list->entries[j]);
+			vis_dict_index(params, NULL);
+			widget_datum = params[0];
+			DEBUGPRINTF("Retrieving xpos for widget: %d\n", j);
+			params[0] = add_ref(window->widget_xpos);
+			params[1] = add_ref(list->entries[j]);
+			DEBUGPUTS("Calling vis_dict_index(params, NULL) for xpos\n");
+			vis_dict_index(params, NULL);
+			DEBUGPUTS("After vis_dict_index\n");
+			xpos = params[0]->c.real;
+			DEBUGPUTS("Releasing xpos datum\n");
+			release_ref(params[0]);
+			DEBUGPRINTF("Retrieving ypos for widget: %d\n", j);
+			params[0] = add_ref(window->widget_ypos);
+			params[1] = add_ref(list->entries[j]);
+			DEBUGPUTS("Calling vis_dict_index(params, NULL) for ypos\n");
+			vis_dict_index(params, NULL);
+			DEBUGPUTS("After vis_dict_index\n");
+			ypos = params[0]->c.real;
+			DEBUGPUTS("Releasing ypos datum\n");
+			release_ref(params[0]);
+			widget = (vis_widget *)(widget_datum->c.generic.data);
+			DEBUGPUTS("Instantiating OS native widget object\n");
+			switch(widget_datum->company->type_id)
+			{
+				case BUILTIN_TYPE_BUTTON:
+					DEBUGPRINTF("new os::Button() with label %s and message code %d\n", widget->label->c.generic.data, (((list_data *)(window_show->handler_list->c.generic.data))->num_entries));
+					widget_handle = CreateWindow("Button", widget->label->c.generic.data,
+						WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
+						xpos, ypos, widget->width, widget->height,
+						window_handle, (HMENU)(((list_data *)(window_show->handler_list->c.generic.data))->num_entries),
+						GetModuleHandle(NULL), NULL);
+					params[0] = add_ref(widget->handler_dict);
+					params[1] = new_datum_comp(widget->label->company, 1, 6);//click
+					strcpy((char *)(params[1]->c.generic.data), "click");
+					vis_dict_index(params, NULL);
+					params[1] = params[0];
+					params[0] = window_show->handler_list;
+					vis_list_append(params, NULL);
+					window_show->handler_list = params[0];
+					break;
+				case BUILTIN_TYPE_INPUTBOX:
+					flags = WS_VISIBLE | WS_CHILD | WS_BORDER;
+					switch(widget->flags)
+					{
+					case 1:
+						flags |= ES_MULTILINE;
+						break;
+					case 2:
+						flags |= ES_NUMBER;
+						break;
+					case 3:
+						flags |= ES_PASSWORD;
+						break;
+					case 4:
+						flags |= ES_READONLY;
+						break;
+					default:
+						break;
+					}
+					DEBUGPRINTF("Adding inputbox with label %s, xpos %d, ypos %d, width %d, height %d\n", (list->entries[j]->c.generic.data), (int)xpos, (int)ypos, (int)widget->width, (int)widget->height);
+					widget_handle = CreateWindow(
+						"Edit", "",
+						flags,
+						xpos, ypos, widget->width, widget->height,
+						window_handle, (HMENU) 0,
+						GetModuleHandle(NULL), NULL);
+					break;
+				//TODO: Error handling?
+			}
+			params[0] = window_show->widget_handle_lookup;
+			params[1] = add_ref(list->entries[j]);
+			params[2] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, window_show->instance.def->program);
+			params[2]->c.integers.num_a = (int)widget_handle;
+			vis_dict_set(params, NULL);
+			window_show->widget_handle_lookup = params[0];
+		}
+	}
+	ShowWindow (window_handle, glob_cmd_show);
+	while(GetMessage(&message, NULL, 0, 0))
+	{
+		TranslateMessage(&message);
+		DispatchMessage(&message);
+	}
+	vis_window_closed(show_datum);
+	//TODO remove handle and datum from list
+	return 0;
+}
+
+int vis_window_get_value(datum ** inputlist, queue_entry * worker_entry)
+{
+	//TODO: Use WM_GETTEXTLEN? message to determine size of string in text box
+	vis_window_shown * window = inputlist[0]->c.generic.data;
+	datum * params[2];
+	datum * output = new_datum(BUILTIN_TYPE_STRING, 1, 100, worker_entry->instance->def->program);
+	params[0] = add_ref(window->widget_handle_lookup);
+	params[1] = inputlist[1];
+	vis_dict_index(params, NULL);
+	if(params[0])
+		SendMessage((HWND)params[0]->c.integers.num_a, WM_GETTEXT, 100, (LPARAM)(output->c.generic.data));
+	else
+	{
+		*((char*)(output->c.generic.data)) = '\0';
+		output->c.generic.len = 1;
+	}
+	release_ref(inputlist[0]);
+	inputlist[0] = output;
+	return 0;
+}
+
+int vis_window_set_value(datum ** inputlist, queue_entry * worker_entry)
+{
+	vis_window_shown * window = inputlist[0]->c.generic.data;
+	datum * params[2];
+	datum * output = new_datum(BUILTIN_TYPE_STRING, 1, 100, worker_entry->instance->def->program);
+	params[0] = add_ref(window->widget_handle_lookup);
+	params[1] = inputlist[1];
+	vis_dict_index(params, NULL);
+	if(params[0])
+		SendMessage((HWND)params[0]->c.integers.num_a, WM_SETTEXT, 0, (LPARAM)(inputlist[2]->c.generic.data));
+	release_ref(inputlist[0]);
+	release_ref(inputlist[2]);
+	return 0;
+}
+
+int vis_window_show(datum ** inputlist, queue_entry * worker_entry)
+{
+	vis_window * window = inputlist[0]->c.generic.data;
+	vis_window_shown * window_show;
+	datum * show_datum;
+
+	show_datum = new_datum(BUILTIN_TYPE_WINDOW_SHOWN, 1, sizeof(vis_window_shown), worker_entry->instance->def->program);
+	window_show = (vis_window_shown *)(show_datum->c.generic.data);
+	window_show->title = add_ref(window->title);
+	window_show->width = window->width;
+	window_show->height = window->height;
+	window_show->xpos = inputlist[1]->c.real;
+	release_ref(inputlist[1]);
+	window_show->ypos = inputlist[2]->c.real;
+	release_ref(inputlist[2]);
+	window_show->is_open = TRUE;
+	window_show->wait_entry = NULL;
+	VIS_InitializeCriticalSection(window_show->lock);
+	window_show->instance.def = worker_entry->instance->def;
+	window_show->instance.workerlist = NULL;
+	VIS_InitializeCriticalSection(window_show->instance.counter_lock);
+	window_show->orig_window = inputlist[0];
+	window_show->handler_list = create_list(worker_entry->instance->def->program);
+	window_show->widget_handle_lookup = create_dict(worker_entry->instance->def->program);
+
+	inputlist[0] = show_datum;
+	VIS_NewThread(window_thread, add_ref(show_datum));
+
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ms_window.h	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,24 @@
+#include "vis_threading.h"
+typedef struct
+{
+	VIS_CRITICAL_SECTION(lock)
+	datum * orig_window;
+	datum * title;
+	double width;
+	double height;
+	double xpos;
+	double ypos;
+	queue_entry * wait_entry;
+	int next_msg_code;
+	datum * handler_list;
+	datum * widget_handle_lookup;
+	worker_instance instance;
+	HWND window_handle;
+	BOOL is_open;
+} vis_window_shown;
+
+VIS_EXTERN_CRITICAL_SECTION(hwnd_lock);
+
+#define START_HANDLE_LIST	8
+
+void message_loop();
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mt19937ar.c	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,175 @@
+/* 
+   A C-program for MT19937, with initialization improved 2002/1/26.
+   Coded by Takuji Nishimura and Makoto Matsumoto.
+
+   Before using, initialize the state by using init_genrand(seed)  
+   or init_by_array(init_key, key_length).
+
+   Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
+   All rights reserved.                          
+   Copyright (C) 2005, Mutsuo Saito,
+   All rights reserved.                          
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+     1. Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+
+     2. Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+
+     3. The names of its contributors may not be used to endorse or promote 
+        products derived from this software without specific prior written 
+        permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+   Any feedback is very welcome.
+   http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
+   email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
+*/
+
+#include <stdio.h>
+#include "mt19937ar.h"
+
+/* Period parameters */  
+#define N 624
+#define M 397
+#define MATRIX_A 0x9908b0dfUL   /* constant vector a */
+#define UPPER_MASK 0x80000000UL /* most significant w-r bits */
+#define LOWER_MASK 0x7fffffffUL /* least significant r bits */
+
+static unsigned long mt[N]; /* the array for the state vector  */
+static int mti=N+1; /* mti==N+1 means mt[N] is not initialized */
+
+/* initializes mt[N] with a seed */
+void init_genrand(unsigned long s)
+{
+    mt[0]= s & 0xffffffffUL;
+    for (mti=1; mti<N; mti++) {
+        mt[mti] = 
+	    (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti); 
+        /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
+        /* In the previous versions, MSBs of the seed affect   */
+        /* only MSBs of the array mt[].                        */
+        /* 2002/01/09 modified by Makoto Matsumoto             */
+        mt[mti] &= 0xffffffffUL;
+        /* for >32 bit machines */
+    }
+}
+
+/* initialize by an array with array-length */
+/* init_key is the array for initializing keys */
+/* key_length is its length */
+/* slight change for C++, 2004/2/26 */
+void init_by_array(unsigned long init_key[], int key_length)
+{
+    int i, j, k;
+    init_genrand(19650218UL);
+    i=1; j=0;
+    k = (N>key_length ? N : key_length);
+    for (; k; k--) {
+        mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL))
+          + init_key[j] + j; /* non linear */
+        mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
+        i++; j++;
+        if (i>=N) { mt[0] = mt[N-1]; i=1; }
+        if (j>=key_length) j=0;
+    }
+    for (k=N-1; k; k--) {
+        mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL))
+          - i; /* non linear */
+        mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
+        i++;
+        if (i>=N) { mt[0] = mt[N-1]; i=1; }
+    }
+
+    mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */ 
+}
+
+/* generates a random number on [0,0xffffffff]-interval */
+unsigned long genrand_int32(void)
+{
+    unsigned long y;
+    static unsigned long mag01[2]={0x0UL, MATRIX_A};
+    /* mag01[x] = x * MATRIX_A  for x=0,1 */
+
+    if (mti >= N) { /* generate N words at one time */
+        int kk;
+
+        if (mti == N+1)   /* if init_genrand() has not been called, */
+            init_genrand(5489UL); /* a default initial seed is used */
+
+        for (kk=0;kk<N-M;kk++) {
+            y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
+            mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL];
+        }
+        for (;kk<N-1;kk++) {
+            y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
+            mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
+        }
+        y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
+        mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];
+
+        mti = 0;
+    }
+  
+    y = mt[mti++];
+
+    /* Tempering */
+    y ^= (y >> 11);
+    y ^= (y << 7) & 0x9d2c5680UL;
+    y ^= (y << 15) & 0xefc60000UL;
+    y ^= (y >> 18);
+
+    return y;
+}
+
+/* generates a random number on [0,0x7fffffff]-interval */
+long genrand_int31(void)
+{
+    return (long)(genrand_int32()>>1);
+}
+
+/* generates a random number on [0,1]-real-interval */
+double genrand_real1(void)
+{
+    return genrand_int32()*(1.0/4294967295.0); 
+    /* divided by 2^32-1 */ 
+}
+
+/* generates a random number on [0,1)-real-interval */
+double genrand_real2(void)
+{
+    return genrand_int32()*(1.0/4294967296.0); 
+    /* divided by 2^32 */
+}
+
+/* generates a random number on (0,1)-real-interval */
+double genrand_real3(void)
+{
+    return (((double)genrand_int32()) + 0.5)*(1.0/4294967296.0); 
+    /* divided by 2^32 */
+}
+
+/* generates a random number on [0,1) with 53-bit resolution*/
+double genrand_res53(void) 
+{ 
+    unsigned long a=genrand_int32()>>5, b=genrand_int32()>>6; 
+    return(a*67108864.0+b)*(1.0/9007199254740992.0); 
+} 
+/* These real versions are due to Isaku Wada, 2002/01/09 added */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mt19937ar.h	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,72 @@
+/* 
+   A C-program for MT19937, with initialization improved 2002/1/26.
+   Coded by Takuji Nishimura and Makoto Matsumoto.
+
+   Before using, initialize the state by using init_genrand(seed)  
+   or init_by_array(init_key, key_length).
+
+   Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
+   All rights reserved.
+   Copyright (C) 2005, Mutsuo Saito
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+     1. Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+
+     2. Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+
+     3. The names of its contributors may not be used to endorse or promote 
+        products derived from this software without specific prior written 
+        permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+   Any feedback is very welcome.
+   http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
+   email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
+*/
+
+/* initializes mt[N] with a seed */
+void init_genrand(unsigned long s);
+
+/* initialize by an array with array-length */
+/* init_key is the array for initializing keys */
+/* key_length is its length */
+/* slight change for C++, 2004/2/26 */
+void init_by_array(unsigned long init_key[], int key_length);
+
+/* generates a random number on [0,0xffffffff]-interval */
+unsigned long genrand_int32(void);
+
+/* generates a random number on [0,0x7fffffff]-interval */
+long genrand_int31(void);
+
+/* These real versions are due to Isaku Wada, 2002/01/09 added */
+/* generates a random number on [0,1]-real-interval */
+double genrand_real1(void);
+
+/* generates a random number on [0,1)-real-interval */
+double genrand_real2(void);
+
+/* generates a random number on (0,1)-real-interval */
+double genrand_real3(void);
+
+/* generates a random number on [0,1) with 53-bit resolution*/
+double genrand_res53(void);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/net.c	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,625 @@
+#ifdef WIN32
+	#include <winsock.h>
+#else
+	#include <sys/types.h>
+	#include <sys/socket.h>
+	#include <netinet/in.h>
+	#include <netdb.h>
+	#include <arpa/inet.h>
+#endif
+#include <string.h>
+#include <stdlib.h>
+#include "datum.h"
+#include "structs.h"
+#include "vis_threading.h"
+#include "interp.h"
+
+#ifdef WIN32
+	#define VIS_CloseSocket(sock)	closesocket(sock)
+#else
+	#define VIS_CloseSocket(sock)	close(sock)
+#endif
+
+#define NET_SEARCH_BUFFER_SIZE 512
+
+typedef struct netbuffer {
+	char buffer[NET_SEARCH_BUFFER_SIZE];
+	int index;
+	struct netbuffer * next;	
+} netbuffer;
+/*
+typedef struct 
+{
+	int sockfd;
+	netbuffer * buffers;
+	VIS_CRITICAL_SECTION(lock)
+} net_client_data;*/
+
+int send_all(int sockfd, char * data, int len)
+{
+	int sent = 0;
+	int temp;
+	while(sent < len)
+	{
+		temp = send(sockfd, data+sent, len-sent, 0);
+		if(temp < 0)
+		{
+			DEBUGPUTS("send_all() failed\n");
+			return 0-sent;
+		}
+		sent += temp;
+	}
+	return sent;
+}
+
+int recv_all(int sockfd, char * data, int len)
+{
+	int temp;
+	int received = 0;
+	while(received < len)
+	{
+		temp = recv(sockfd, data, len-received, 0);
+		if(temp < 0)
+		{
+			return 0 - received;
+		}
+		received += temp;	
+	}
+	return received;
+}
+
+int net_client_new(datum ** params, queue_entry * worker_entry)
+{
+	int sockfd, i;
+	//net_client_data * net;
+	struct sockaddr_in dest;
+	struct hostent * h;
+	char * host = params[0]->c.generic.data;
+	int hostlen = params[0]->c.generic.len;
+	for(i = 0; i < hostlen; ++i)
+		if((host[i] < '0' || host[i] > '0') && host[i] != '.')
+		{
+			h = gethostbyname(host);
+			if(!h)
+			{
+				release_ref(params[0]);
+				release_ref(params[1]);
+				params[0] = NULL;
+				params[1] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, worker_entry->instance->def->program);
+				params[1]->c.integers.num_a = 0;
+				return 0;
+			}
+			host = inet_ntoa(*((struct in_addr *)h->h_addr));
+			break;
+		}
+	sockfd = socket(PF_INET, SOCK_STREAM, 0);
+	
+	dest.sin_family = AF_INET;
+	dest.sin_port = htons(params[1]->c.integers.num_a);
+	dest.sin_addr.s_addr = inet_addr(host);
+	memset(&(dest.sin_zero), '\0', 8);
+	
+	release_ref(params[0]);
+	release_ref(params[1]);
+	params[0] = params[1] = NULL;
+	
+	if(connect(sockfd, (struct sockaddr *)&dest, sizeof(struct sockaddr)) != 1)
+	{
+		params[0] = new_datum(BUILTIN_TYPE_NETCLIENT, 2, 0, worker_entry->instance->def->program);//sizeof(net_client_data));
+		params[0]->c.integers.num_a = sockfd;
+		/*net = params[0]->c.generic.data;
+		net->sockfd = sockfd;
+		net->buffers = NULL;*/
+		
+//		VIS_InitializeCriticalSection(net->lock);
+		DEBUGPUTS("Connection established\n");
+	}
+	else
+	{
+		params[1] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, worker_entry->instance->def->program);
+		params[1]->c.integers.num_a = 0;
+		DEBUGPUTS("connect() failed\n");
+	}
+	return 0;
+}
+
+int net_client_put_string(datum ** params, queue_entry * worker_entry)
+{
+	//net_client_data * net = params[0]->c.generic.data;
+	//int sockfd = net->sockfd;
+	int sockfd = params[0]->c.integers.num_a;
+	int to_send = params[1]->c.generic.len-1;
+	char * data = params[1]->c.generic.data;
+	int sent;
+	if(to_send)
+	{
+		sent = send_all(sockfd, data, to_send);
+		
+		if(sent != to_send)
+		{
+			release_ref(params[0]);
+			release_ref(params[1]);
+			params[0] = NULL;
+			params[1] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program);
+			params[1]->c.integers.num_a = 0-sent;
+			DEBUGPUTS("send() failed\n");
+			return 0;
+		}
+	}
+	DEBUGPRINTF("Sent %s\n", data);
+	release_ref(params[1]);
+	params[1] = NULL;
+	return 0;
+}
+
+int net_client_get_fstring(datum ** params, queue_entry * worker_entry)
+{
+	char * buf;
+	//net_client_data * net = params[0]->c.generic.data;
+	//int sockfd = net->sockfd;
+	int sockfd = params[0]->c.integers.num_a;
+	int to_receive = params[1]->c.integers.num_a;
+	int temp, received = 0;
+	datum * output = new_datum(BUILTIN_TYPE_STRING, 1, params[1]->c.integers.num_a+1, worker_entry->instance->def->program);
+	release_ref(params[1]);
+	buf = output->c.generic.data;
+	while(received < to_receive)
+	{
+		temp = recv(sockfd, buf+received, to_receive-received, 0);
+		if(temp < 0)
+		{
+			release_ref(params[0]);
+			params[0] = params[1] = NULL;
+			params[2] = output;
+			return 0;
+		}
+		received += temp;	
+	}
+	params[1] = output;
+	params[2] = NULL;
+	return 0;
+}
+
+int net_client_get_dstring(datum ** inputlist, queue_entry * worker_entry)
+{
+	BOOL found = FALSE;
+	netbuffer buf;
+	netbuffer * current, *first, *temp,*temp2;
+	int i,j,k,startk;
+	int found_entry;
+	int string_offset;
+	int search_offset;
+	netbuffer * search_start;
+	int search_start_offset;
+	int *search_offsets;
+	netbuffer ** search_starts;
+	int *search_start_offsets;
+	int read_bytes;
+	int buf_pos;
+	int sockfd = inputlist[0]->c.integers.num_a;
+	//net_client_data * net = inputlist[0]->c.generic.data;
+	
+	list_data * list;
+	if(inputlist[1]->company->type_id == BUILTIN_TYPE_LIST)
+	{
+		
+		list = ((list_data *)inputlist[1]->c.generic.data);
+		DEBUGPRINTF("Delimeter input is a list with %d entries.\n", list->num_entries);
+		search_offsets = malloc(sizeof(int) * (list->num_entries));
+		DEBUGPRINTF("Allocated %d bytes.\n", sizeof(int) * (list->num_entries));
+		search_starts = malloc(sizeof(netbuffer *) * (list->num_entries));
+		DEBUGPRINTF("Allocated %d bytes.\n", sizeof(netbuffer *) * (list->num_entries));
+		search_start_offsets = malloc(sizeof(int) * (list->num_entries));
+		DEBUGPRINTF("Allocated %d bytes.\n", sizeof(int) * (list->num_entries));
+		for(i = 0; i < list->num_entries; ++i)
+		{
+			DEBUGPRINTF("Setting search_offsets[%d] = 0.\n", i);
+			search_offsets[i] = 0;
+		}
+	}
+	search_offset = 0;
+		first = &buf;
+		first->next = NULL;
+		current = first;
+		current->index = 0;
+		first = current;
+		read_bytes = 1;
+		while(!found && read_bytes == 1)
+		{
+			buf_pos = 0;
+			for(i = 0; i < NET_SEARCH_BUFFER_SIZE && !found; ++i)
+			{
+				if(i >= buf_pos)
+				{
+					read_bytes = recv(sockfd, current->buffer+i, 1, 0);
+					if(read_bytes != 1)
+						break;
+					++buf_pos;
+				}
+				DEBUGPRINTF("Checking character #%d (%c)\n", i, current->buffer[i]);
+				switch(inputlist[1]->company->type_id)
+				{
+				case BUILTIN_TYPE_WHOLE:
+					if((int)current->buffer[i] == inputlist[1]->c.integers.num_a)
+					{
+						found = TRUE;
+						search_offset = 1;
+						search_start = current;
+						search_start_offset = i;
+					}
+					break;
+				case BUILTIN_TYPE_STRING:
+					DEBUGPRINTF("Comparing with character %d of delim: %c (%X)\n", search_offset, ((char *)inputlist[1]->c.generic.data)[search_offset], ((char *)inputlist[1]->c.generic.data)[search_offset]);
+					if(current->buffer[i] == ((char *)inputlist[1]->c.generic.data)[search_offset])
+					{
+						if(search_offset == 0)
+						{
+							search_start = current;
+							search_start_offset = i;
+						}
+						++search_offset;
+						DEBUGPRINTF("Search offset is: %d, delim len is: %d\n", search_offset, (inputlist[1]->c.generic.len-1));
+						if(search_offset == (inputlist[1]->c.generic.len-1))
+						{
+							found = TRUE;
+							DEBUGPUTS("Matched delim\n");
+						}
+					}
+					else
+					{
+						if(search_offset > 0)
+						{
+							current = search_start;
+							i = search_start_offset;
+						}
+						search_offset = 0;
+					}
+					break;
+				case BUILTIN_TYPE_LIST:
+					for(j = 0; j < list->num_entries; ++j)
+					{
+						DEBUGPRINTF("Testing list entry %d against character %d in buffer %d\n", j, i, current->index);
+						if(list->entries[j]->company->type_id == BUILTIN_TYPE_WHOLE && (int)current->buffer[i] == list->entries[j]->c.integers.num_a)
+						{
+							DEBUGPUTS("Matched whole number entry.\n");
+							found = TRUE;
+							found_entry = j;
+							search_offset = 1;
+							search_start = current;
+							search_start_offset = i;
+							break;
+						}
+						else if(list->entries[j]->company->type_id == BUILTIN_TYPE_STRING)
+						{
+							DEBUGPUTS("String entry.\n");
+							if(current->buffer[i] == ((char *)list->entries[j]->c.generic.data)[search_offsets[j]])
+							{
+								DEBUGPRINTF("%c in buffer matches character #%d in entry.\n", current->buffer[i], search_offsets[j]);
+								if(search_offsets[j] == 0)
+								{
+									search_starts[j] = current;
+									search_start_offsets[j] = i;
+								}
+								++search_offsets[j];
+								if(search_offsets[j] == (list->entries[j]->c.generic.len-1))
+								{
+									DEBUGPUTS("Entire string matched.\n");
+									found = TRUE;
+									found_entry = j;
+									search_offset = search_offsets[j];
+									search_start = search_starts[j];
+									search_start_offset = search_start_offsets[j];
+									break;
+								}
+							}
+							else if(search_offsets[j] > 0)
+							{
+								DEBUGPRINTF("%c in bufer does not match character #%d in entry.\n", current->buffer[i], search_offsets[j]);
+								temp = search_starts[j];
+								search_offsets[j] = 0;
+								startk = search_start_offsets[j];
+								while(temp && !found)
+								{
+									DEBUGPRINTF("Scanning block %d for possible missed match from %d to %d.\n", temp->index, startk, (temp == current ? i : NET_SEARCH_BUFFER_SIZE)-1);
+									for(k = startk; k < (temp == current ? i : NET_SEARCH_BUFFER_SIZE); ++k)
+									{
+										if(temp->buffer[k] == ((char *)list->entries[j]->c.generic.data)[search_offsets[j]])
+										{
+											if(!search_offsets[j])
+											{
+												search_starts[j] = temp;
+												search_start_offsets[j] = k;
+											}
+											++search_offsets[j];
+											if(search_offset == (list->entries[j]->c.generic.len-1))
+											{
+												found = TRUE;
+												found_entry = j;
+												search_start = search_starts[j];
+												search_start_offset = search_start_offsets[j];
+											}
+										}
+										else
+										{
+											if(search_offsets[j] > 0)
+											{
+												temp = search_starts[j];
+												k = search_start_offsets[j];
+											}
+											search_offsets[j] = 0;
+										}
+									}
+									startk = 0;
+									temp = temp->next;
+								}
+								
+							}
+							else
+								search_offsets[j] = 0;
+							
+						}
+					}
+					break;
+				}
+			}
+			if(!found && read_bytes == 1)
+			{
+				current->next = malloc(sizeof(netbuffer));
+				current->next->index = current->index+1;
+				//current->next->offset = current->next->filled = 0;
+				current->next->next = NULL;
+				current = current->next;
+			}
+		}
+	if(inputlist[1]->company->type_id == BUILTIN_TYPE_LIST)
+	{
+		VIS_FREE(search_offsets, "Get DString@Net Clinet, search offsets");
+		VIS_FREE(search_starts, "Get DString@Net Clinet, search starts");
+		VIS_FREE(search_start_offsets, "Get DString@Net Clinet, search start offsets");
+	}
+	if(found)
+	{
+		if(inputlist[1]->company->type_id == BUILTIN_TYPE_LIST)
+		{
+			inputlist[2] = add_ref(list->entries[found_entry]);
+			release_ref(inputlist[1]);
+		}
+		else
+			inputlist[2] = inputlist[1];
+		inputlist[3] = NULL;
+	}
+	else
+	{
+		release_ref(inputlist[1]);
+		inputlist[3] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, worker_entry->instance->def->program);
+		datum_set_yesno(inputlist[3], 0);
+		inputlist[2] = NULL;
+		release_ref(inputlist[0]);
+		inputlist[0] = NULL;
+	}
+	//Does this need to be here still or was it just working around another bug?
+	if(search_start_offset < 0)
+		search_start_offset = 0;
+	if(!found) {
+		search_start = current;
+		search_start_offset = i;
+	}
+	DEBUGPRINTF("Allocating string of length: %d = %d * %d + %d + 1\n", NET_SEARCH_BUFFER_SIZE * search_start->index + search_start_offset+1, NET_SEARCH_BUFFER_SIZE , search_start->index, search_start_offset);
+	inputlist[1] = new_datum(BUILTIN_TYPE_STRING, 1, NET_SEARCH_BUFFER_SIZE * search_start->index + search_start_offset+1, worker_entry->instance->def->program);
+	temp = first;
+	string_offset = 0;
+	while(temp)
+	{
+		DEBUGPRINTF("Copying from index %d to offset %X\n", temp->index, string_offset);
+		if(temp == search_start)
+		{
+			//if(found)
+			//{
+				temp->buffer[search_start_offset] = '\0';
+				memcpy(((char *)inputlist[1]->c.generic.data)+string_offset, temp->buffer, search_start_offset);
+				string_offset += search_start_offset;
+			/*}
+			else
+			{
+				memcpy(((char *)inputlist[1]->c.generic.data)+string_offset, temp->buffer, i);
+				string_offset += i;
+			}*/
+			break;
+		}
+		else
+		{
+			memcpy(((char *)inputlist[1]->c.generic.data)+string_offset, temp->buffer, NET_SEARCH_BUFFER_SIZE);
+			string_offset += NET_SEARCH_BUFFER_SIZE;
+		}
+		if(temp != first)
+		{
+			temp2 = temp->next;
+			VIS_FREE(temp, "Get DString@Net Client, buffer node");
+			temp = temp2;
+		}
+		else
+			temp = temp->next;
+	}
+	while(temp)
+	{
+		if(temp != first)
+		{
+			temp2 = temp->next;
+			VIS_FREE(temp, "Get DString@Net Client, buffer node");
+			temp = temp2;
+		}
+		else
+			temp = temp->next;
+	}
+	((char *)inputlist[1]->c.generic.data)[string_offset] = '\0';
+	DEBUGPRINTF("Retrieved: %s\ninputlist[0] = %X\n", inputlist[1]->c.generic.data, inputlist[0]);
+	return 0;
+}
+
+int net_client_put_raw(datum ** params, queue_entry * entry)
+{
+	int sockfd = params[0]->c.integers.num_a;
+	int sent;
+	if(params[1]->union_type == 1 && params[1]->c.generic.len)
+	{
+		sent = send_all(sockfd, params[1]->c.generic.data, params[1]->c.generic.len);
+		if(sent <= 0)
+		{
+			release_ref(params[0]);
+			release_ref(params[1]);
+			params[0] = NULL;
+			params[1] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, entry->instance->def->program);
+			params[1]->c.integers.num_a = 0-sent;
+			return 0;
+		}
+	}
+	release_ref(params[1]);
+	params[1] = NULL;
+	return 0;
+}
+
+int net_client_get_raw(datum ** params, queue_entry * entry)
+{
+	int sockfd = params[0]->c.integers.num_a;
+	int got;
+	params[1] = copy_datum(params[1], 0);
+	if(params[1]->union_type == 1 && params[1]->c.generic.len)
+	{
+		got = recv_all(sockfd, params[1]->c.generic.data, params[1]->c.generic.len);
+		if(got <= 0)
+		{
+			release_ref(params[0]);
+			release_ref(params[1]);
+			params[0] = params[1] = NULL;
+			params[2] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, entry->instance->def->program);
+			params[2]->c.integers.num_a = 0-got;
+			return 0;
+		}
+	}
+	params[2] = NULL;
+	return 0;
+}
+
+typedef struct
+{
+	int sockfd;
+	datum * callback;
+	program * program;
+} net_listen_data;
+
+DWORD WINAPI listen_thread(net_listen_data * listen)
+{
+	worker_datum * work = listen->callback->c.generic.data;
+	struct sockaddr_in client_addy;
+	int addy_len;
+	int newsock;
+	int i;
+	queue_entry entry;
+	datum * params[32];
+	BOOL netparam;
+	worker_instance inst;
+	entry.worker_num = 0;
+	entry.instance = &inst;
+	inst.def = listen->program->defs->deflist;//Use Main
+	inst.caller_instance = NULL;
+	inst.trans = NULL;
+	inst.num_workers = inst.num_wires = 0;
+	VIS_InitializeCriticalSection(inst.counter_lock);
+
+	while(execute_active)
+	{
+		addy_len = sizeof(client_addy);
+		newsock = accept(listen->sockfd, (struct sockaddr *)&client_addy, &addy_len);
+		if(newsock != -1)
+		{
+			netparam = FALSE;
+			for(i = 0; i < work->def->num_inputs; ++i)
+				if(work->params[i])
+					params[i] = add_ref(work->params[i]);
+				else if(!netparam)
+				{
+					params[i] = new_datum(BUILTIN_TYPE_NETCLIENT, 2, 0, listen->program);
+					params[i]->c.integers.num_a = newsock;
+					netparam = TRUE;
+				}
+				else
+					params[i] = NULL;
+			//Make sure that our fake instance is never cleaned up
+			inst.in_progress_count = inst.in_queue_count = 1000;
+			execute_def(work->def, entry, params, NULL);
+		}
+	}
+	release_ref(listen->callback);
+	VIS_CloseSocket(listen->sockfd);
+	VIS_FREE(listen, "Net listener object");
+	return 0;
+}
+
+int vis_net_listenport(datum ** params, queue_entry * entry)
+{
+	int junk;
+	struct sockaddr_in my_address;
+	int port = params[0]->c.integers.num_a;
+	net_listen_data * listener = malloc(sizeof(net_listen_data));
+	release_ref(params[0]);
+	
+	DEBUGPUTS("calling socket\n");
+	listener->callback = params[1];
+	listener->sockfd = socket(PF_INET, SOCK_STREAM, 0);
+	listener->program = entry->instance->def->program;
+	if(listener->sockfd == -1)
+	{
+		release_ref(params[1]);
+		VIS_FREE(listener, "net listener object");
+		params[1] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, entry->instance->def->program);
+		params[1]->c.integers.num_a = 0;
+		params[0] = NULL;
+		return 0;
+	}
+	DEBUGPRINTF("Socket: %X\n", listener->sockfd);
+	
+	my_address.sin_family = AF_INET;
+	my_address.sin_port = htons(port);
+	my_address.sin_addr.s_addr = INADDR_ANY;
+	memset(&(my_address.sin_zero), '\0', 8);
+	
+	DEBUGPRINTF("Calling bind on port: %d\n", port);
+	junk = bind(listener->sockfd, (struct sockaddr *)&my_address, sizeof(struct sockaddr));
+	DEBUGPRINTF("Bind returned: %d\n", junk);
+	if(junk == -1)
+	{
+		perror("bind");
+		DEBUGPUTS("bind failed, releasing ref to callback worker\n");
+		release_ref(params[1]);
+		DEBUGPUTS("Closing socket\n");
+		DEBUGPRINTF("Socket: %X\n", listener->sockfd);
+		VIS_CloseSocket(listener->sockfd);
+		DEBUGPUTS("Freeing listener data\n");
+		VIS_FREE(listener, "net listener object");
+		DEBUGPUTS("Allocating error output\n");
+		params[1] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, entry->instance->def->program);
+		params[1]->c.integers.num_a = 0;
+		params[0] = NULL;
+		return 0;
+	}
+	
+	DEBUGPUTS("Calling listen\n");
+	if(listen(listener->sockfd, 10) == -1)
+	{
+		release_ref(params[1]);
+		VIS_CloseSocket(listener->sockfd);
+		VIS_FREE(listener, "net listener object");
+		params[1] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, entry->instance->def->program);
+		params[1]->c.integers.num_a = 0;
+		params[0] = NULL;
+		return 0;
+	}
+	DEBUGPUTS("Creating new thread\n");
+	VIS_NewThread(listen_thread, listener);
+	params[0] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, entry->instance->def->program);
+	params[0]->c.integers.num_a = 0;
+	params[1] = NULL;
+	return 0;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/number.c	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,350 @@
+#include <stdlib.h>
+#include "datum.h"
+#include "structs.h"
+#ifdef SEGA
+long atol(const char * string)
+{
+	int i = 0;
+	BOOL neg_flag = FALSE;
+	long value = 0.0;
+	while(string[i] != '\0')
+	{
+		if(string[i] >= '0' && string[i] <= '9')
+		{
+			value *= 10;
+			value += string[i] - '0';
+		}
+		else if(string[i] == '-')
+			neg_flag = TRUE;
+		else if(string[i] != ' ' && string[i] != '\n' && string[i] != '\r' && string[i] != '\t')
+		{
+			break;
+		}
+		++i;
+	}
+	if(neg_flag)
+				value = 0-value;
+	return value;
+}
+#endif
+
+int vis_stringtoint(datum ** inputlist, queue_entry * worker_entry)
+{
+	datum * output;
+	int result = atol(inputlist[0]->c.generic.data);
+	VIS_EnterCriticalSection(inputlist[0]->lock);
+		if(inputlist[0]->ref_count == 1)
+		{
+	VIS_LeaveCriticalSection(inputlist[0]->lock);
+			VIS_FREE(inputlist[0]->c.generic.data, "<String@Whole Number, Freeing string for reuse as integer object");
+			inputlist[0]->company = worker_entry->instance->def->program->companylist + BUILTIN_TYPE_WHOLE;
+			inputlist[0]->union_type = 2;
+		}
+		else
+		{
+	VIS_LeaveCriticalSection(inputlist[0]->lock);
+			release_ref(inputlist[0]);
+			inputlist[0] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program);
+		}
+	inputlist[0]->c.integers.num_a = result;
+	return 0;
+}
+
+int vis_whole_fromhex(datum ** inputlist, queue_entry * worker_entry)
+{
+	int i;
+	int result = 0;
+	char * data = inputlist[0]->c.generic.data;
+	for(i = 0; i < inputlist[0]->c.generic.len-1; ++i)
+	{
+		result <<= 4;
+		if(data[i] >= '0' && data[i] <= '9')
+			result |= data[i] - '0';
+		else if(data[i] >= 'A' && data[i] <= 'F')
+			result |= data[i] - 'A' + 0xA;
+		else if(data[i] >= 'a' && data[i] <= 'f')
+			result |= data[i] - 'a' + 0xA;
+	}
+	release_ref(inputlist[0]);
+	inputlist[0] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program);
+	inputlist[0]->c.integers.num_a = result;
+	return 0;
+}
+
+int vis_whole_add(datum ** inputlist, queue_entry * worker_entry)
+{
+	datum * output;
+	int ref_count;
+	//VIS_PROFILE_START(PROF_ADDWHOLE);
+	VIS_EnterCriticalSection(inputlist[0]->lock);
+		ref_count = inputlist[0]->ref_count;
+	VIS_LeaveCriticalSection(inputlist[0]->lock);
+	if(ref_count == 1)
+		output = inputlist[0];
+	else
+	{
+		VIS_EnterCriticalSection(inputlist[1]->lock);
+			ref_count = inputlist[1]->ref_count;
+		VIS_LeaveCriticalSection(inputlist[1]->lock);
+		if(ref_count == 1)
+			output = inputlist[1];
+		else
+			output = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program);
+	}
+	
+	output->c.integers.num_a = inputlist[0]->c.integers.num_a + inputlist[1]->c.integers.num_a;
+	if(output == inputlist[0])
+		release_ref(inputlist[1]);
+	else if(output == inputlist[1])
+		release_ref(inputlist[0]);
+	else
+	{
+		release_ref(inputlist[0]);
+		release_ref(inputlist[1]);
+	}
+	inputlist[0] = output;
+	//VIS_PROFILE_END(PROF_ADDWHOLE);
+	return 0;
+}
+
+int vis_whole_subtract(datum ** inputlist, queue_entry * worker_entry)
+{
+	datum * output;
+	output = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program);
+	output->c.integers.num_a = inputlist[0]->c.integers.num_a - inputlist[1]->c.integers.num_a;
+	release_ref(inputlist[0]);
+	release_ref(inputlist[1]);
+	inputlist[0] = output;
+	return 0;
+}
+
+int vis_whole_mult(datum ** inputlist, queue_entry * worker_entry)
+{
+	inputlist[0] = copy_datum(inputlist[0], 0);
+	inputlist[0]->c.integers.num_a *= inputlist[1]->c.integers.num_a;
+	release_ref(inputlist[1]);
+	return 0;
+}
+
+int vis_whole_div(datum ** inputlist, queue_entry * worker_entry)
+{
+	inputlist[0] = copy_datum(inputlist[0], 0);
+	inputlist[0]->c.integers.num_a /= inputlist[1]->c.integers.num_a;
+	release_ref(inputlist[1]);
+	return 0;
+}
+
+int vis_wholeequal(datum ** inputlist, queue_entry * worker_entry)
+{
+	datum * output;
+	//VIS_PROFILE_START(PROF_EQUALWHOLE);
+	output = new_datum(BUILTIN_TYPE_YESNO, 2, 0, worker_entry->instance->def->program);
+	datum_set_yesno(output, inputlist[0]->c.integers.num_a == inputlist[1]->c.integers.num_a);
+	release_ref(inputlist[0]);
+	release_ref(inputlist[1]);
+	//VIS_PROFILE_END(PROF_EQUALWHOLE);
+	inputlist[0] = output;
+	return 0;
+}
+
+int vis_whole_or(datum ** inputlist, queue_entry * worker_entry)
+{
+	inputlist[0] = copy_datum(inputlist[0], 0);
+	inputlist[0]->c.integers.num_a |= inputlist[1]->c.integers.num_a;
+	release_ref(inputlist[1]);
+	return 0;
+}
+
+int vis_whole_and(datum ** inputlist, queue_entry * worker_entry)
+{
+	inputlist[0] = copy_datum(inputlist[0], 0);
+	inputlist[0]->c.integers.num_a &= inputlist[1]->c.integers.num_a;
+	release_ref(inputlist[1]);
+	return 0;
+}
+
+int vis_whole_lsh(datum ** inputlist, queue_entry * worker_entry)
+{
+	inputlist[0] = copy_datum(inputlist[0], 0);
+	inputlist[0]->c.integers.num_a <<= inputlist[1]->c.integers.num_a;
+	release_ref(inputlist[1]);
+	return 0;
+}
+
+int vis_whole_rsh(datum ** inputlist, queue_entry * worker_entry)
+{
+	inputlist[0] = copy_datum(inputlist[0], 0);
+	inputlist[0]->c.integers.num_a >>= inputlist[1]->c.integers.num_a;
+	release_ref(inputlist[1]);
+	return 0;
+}
+
+
+int vis_greaterint(datum ** inputlist, queue_entry * worker_entry)
+{
+	int result;
+	if(inputlist[0]->c.integers.num_a > inputlist[1]->c.integers.num_a)
+		result = 1;
+	else
+		result = 0;
+		
+	release_ref(inputlist[0]);
+	release_ref(inputlist[1]);
+	inputlist[0] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, worker_entry->instance->def->program);
+	datum_set_yesno(inputlist[0], result);
+	return 0;
+}
+
+int vis_lesserint(datum ** inputlist, queue_entry * worker_entry)
+{
+	int result, ref_count;
+	//VIS_PROFILE_START(PROF_LESSERWHOLE);
+	if(inputlist[0]->c.integers.num_a < inputlist[1]->c.integers.num_a)
+		result = 1;
+	else
+		result = 0;
+	VIS_EnterCriticalSection(inputlist[0]->lock);
+		ref_count = inputlist[0]->ref_count;
+	VIS_LeaveCriticalSection(inputlist[0]->lock);
+	if(ref_count == 1)
+	{
+		release_ref(inputlist[1]);
+		inputlist[0]->company = worker_entry->instance->def->program->companylist + BUILTIN_TYPE_YESNO;
+		inputlist[0]->union_type = 2;
+	}
+	else
+	{
+		VIS_EnterCriticalSection(inputlist[1]->lock);
+			ref_count = inputlist[1]->ref_count;
+		VIS_LeaveCriticalSection(inputlist[1]->lock);
+		if(ref_count == 1)
+		{
+			release_ref(inputlist[0]);
+			inputlist[0] = inputlist[1];
+			inputlist[0]->company = worker_entry->instance->def->program->companylist + BUILTIN_TYPE_YESNO;
+			inputlist[0]->union_type = 2;
+		}
+		else
+		{
+			release_ref(inputlist[0]);
+			release_ref(inputlist[1]);
+			inputlist[0] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, worker_entry->instance->def->program);
+		}
+	}
+	//datum_set_yesno(inputlist[0], result);
+	inputlist[0]->c.integers.num_a = result;
+	//VIS_PROFILE_END(PROF_LESSERWHOLE);
+	return 0;
+}
+#ifndef WIN32
+double atof(const char * string)
+{
+	int i = 0;
+	BOOL neg_flag = FALSE;
+	double value = 0.0;
+	double divisor = 10;
+	while(string[i] != '\0' && string[i] != '.')
+	{
+		if(string[i] >= '0' && string[i] <= '9')
+		{
+			value *= 10.0;
+			value += string[i] - '0';
+		}
+		else if(string[i] == '-')
+			neg_flag = TRUE;
+		else if(string[i] != ' ' && string[i] != '\n' && string[i] != '\r' && string[i] != '\t')
+			return value;
+		++i;
+	}
+	if(string[i] != '\0')
+	{
+		++i;
+		while(string[i] != '\0' && string[i] >= 0 && string[i] <= 9)
+		{
+			value += ((double)(string[i] - '0'))/divisor;
+			divisor *= 10;
+		}
+	}
+	return value;
+}
+#endif
+
+int vis_stringtoreal(datum ** inputlist, queue_entry * worker_entry)
+{
+	datum * output;
+	output = new_datum(BUILTIN_TYPE_REAL, 3, 0, worker_entry->instance->def->program);
+	output->c.real = atof(inputlist[0]->c.generic.data);
+	release_ref(inputlist[0]);
+	inputlist[0] = output;
+	return 0;
+}
+
+int vis_real_add(datum ** inputlist, queue_entry * worker_entry)
+{
+	datum * output;
+	output = new_datum(BUILTIN_TYPE_REAL, 3, 0, worker_entry->instance->def->program);
+	output->c.real = inputlist[0]->c.real + inputlist[1]->c.real;
+	release_ref(inputlist[0]);
+	release_ref(inputlist[1]);
+	inputlist[0] = output;
+	return 0;
+}
+
+int vis_real_subtract(datum ** inputlist, queue_entry * worker_entry)
+{
+	datum * output;
+	output = new_datum(BUILTIN_TYPE_REAL, 3, 0, worker_entry->instance->def->program);
+	output->c.real = inputlist[0]->c.real - inputlist[1]->c.real;
+	release_ref(inputlist[0]);
+	release_ref(inputlist[1]);
+	inputlist[0] = output;
+	return 0;
+}
+
+
+int vis_realequal(datum ** inputlist, queue_entry * worker_entry)
+{
+	datum * output = new_datum(BUILTIN_TYPE_YESNO, 2, 0, worker_entry->instance->def->program);
+	datum_set_yesno(output, inputlist[0]->c.real == inputlist[1]->c.real);
+	release_ref(inputlist[0]);
+	release_ref(inputlist[1]);
+	inputlist[0] = output;
+	return 0;
+}
+
+int vis_greaterreal(datum ** inputlist, queue_entry * worker_entry)
+{
+	int result;
+	if(inputlist[0]->c.real > inputlist[1]->c.real)
+		result = 1;
+	else
+		result = 0;
+	release_ref(inputlist[0]);
+	release_ref(inputlist[1]);
+	inputlist[0] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, worker_entry->instance->def->program);
+	datum_set_yesno(inputlist[0], result);
+	return 0;
+}
+
+int vis_lesserreal(datum ** inputlist, queue_entry * worker_entry)
+{
+	int result;
+	if(inputlist[0]->c.real < inputlist[1]->c.real)
+		result = 1;
+	else
+		result = 0;
+	release_ref(inputlist[0]);
+	release_ref(inputlist[1]);
+	inputlist[0] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, worker_entry->instance->def->program);
+	datum_set_yesno(inputlist[0], result);
+	return 0;
+}
+
+int vis_real_div(datum ** inputlist, queue_entry * worker_entry)
+{
+	inputlist[0] = copy_datum(inputlist[0], 0);
+	inputlist[0]->c.real /= inputlist[1]->c.real;
+	release_ref(inputlist[1]);
+	return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pair.rhope	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,42 @@
+/*
+	This example program defines a new object type Pair with two properties and one worker
+*/
+
+//We're importing extendlib for access to Pretty Print
+Import extendlib.rhope
+
+//Blueprint statements define new object types
+Blueprint Pair
+{
+	//We define two fields here First and Second
+	First
+	Second
+}
+
+//There's nothing special about worker's named New. It's just a convention.
+New@Pair[first,second:out]
+{
+	//The Build worker creates a new unpopulated object of a given type based on its blueprint
+	out <- [[Build["Pair"]
+	//Here we set the properties of the new object, First and Second, to the values passed to the constructor
+	]First <<[first]
+	]Second <<[second]
+}
+
+//Rhope has no concept of operators; everything is a worker. Here we define a worker for adding two Pairs
++@Pair[left,right:sum]
+{
+	//Get the sum of the two fields
+	first <- [[left]First >>] + [[right]First >>]
+	second <- [[left]Second >>] + [[right]Second >>]
+	//Return a modified Pair
+	sum <-	[[left]First <<[first]]Second <<[second]
+}
+
+Main[]
+{
+	a <- New@Pair[2,3]
+	b <- New@Pair[5,-1]
+	//Pretty Print can print out user defined objects and most builtin objects in a readable format
+	Pretty Print[[a]+[b], ""]
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/parser.c	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,1633 @@
+#include "structs.h"
+#include "visuality.h"
+#include "debugmacros.h"
+#ifdef WIN32
+	#include "windows.h"
+#endif
+#include <stdio.h>
+#include "interp.h"
+#include "parser.h"
+#include <string.h>
+#include <stdlib.h>
+
+extern int num_workers;
+extern int num_wires;
+
+/*#ifdef SEGA
+#define NUM_WORKERS_START	40
+#define NUM_WIRES_START		80
+#else
+#define NUM_WORKERS_START	1024
+#define NUM_WIRES_START		2048
+#endif*/
+#define NUM_WORKERS_START 	20
+#define NUM_WIRES_START		40
+//TODO: Figure out why setting those defines to 16 and 32 respectively causes problems
+
+BOOL is_whitespace(char c)
+{
+	if(c == ' ' || c == '\t' || c == '\n' || c == '\r')
+		return TRUE;
+	return FALSE;
+}
+
+company * create_company(program * prog, char * name, int num_workers, int num_rooms, BOOL buildable)
+{
+	company * this_comp = &(prog->companylist[prog->num_companies]);
+	DEBUGPRINTF("create_company %s with %d workers and %d rooms\n", name, num_workers, num_rooms);
+	this_comp->type_id = prog->num_companies++;
+	strncpy(this_comp->name, name, 256);
+	this_comp->name[255] = '\0';
+	if(num_workers)
+		this_comp->methodlist = MALLOC(sizeof(worker_def *) * num_workers, "company methodlist");
+	else
+		this_comp->methodlist = NULL;
+	this_comp->num_methods = 0;//num_workers;
+	this_comp->method_storage = num_workers;
+	if(num_rooms)
+	{
+		this_comp->room_list = MALLOC(sizeof(company_room) * num_rooms, "company roomlist");
+		DEBUGPRINTF("Allocated %d bytes at %X for room_list\n", sizeof(company_room) * num_rooms, this_comp->room_list);
+	}
+	else
+		this_comp->room_list = NULL;
+	this_comp->num_rooms = 0;//num_rooms;
+	this_comp->room_storage = num_rooms;
+	if(buildable)
+		this_comp->build_size = 0;
+	else
+		this_comp->build_size = -1;
+	VIS_InitializeCriticalSection(this_comp->lock);
+	return this_comp;
+}
+
+int add_method(company * this_comp, worker_def * def)
+{
+	worker_def ** temp;
+	int i;
+	DEBUGPUTS("add_method: ");
+	DEBUGPRINTF("%s\n", def->name);
+	VIS_EnterCriticalSection(this_comp->lock);
+	if(this_comp->method_storage - this_comp->num_methods <= 0)
+	{
+		if(this_comp->method_storage < 2)
+			this_comp->method_storage = 4;
+		else
+			this_comp->method_storage = this_comp->method_storage + ((this_comp->method_storage) >> 1);
+		temp = MALLOC(sizeof(worker_def *) * this_comp->method_storage, "company method storage");
+		for(i = 0; i < this_comp->num_methods; ++i)
+			temp[i] = this_comp->methodlist[i];
+		VIS_FREE(this_comp->methodlist, "company methodlist");
+		this_comp->methodlist = temp;
+	}
+	i = this_comp->num_methods;
+	this_comp->methodlist[this_comp->num_methods++] = def;
+	DEBUGPRINTF("%s now has %d methods\n", this_comp->name, this_comp->num_methods);
+	VIS_LeaveCriticalSection(this_comp->lock);
+	return i;
+}
+int room_build_sizes[] = {0, sizeof(char), sizeof(short), sizeof(long), sizeof(float), sizeof(double), -1, -1, -1, -1, -1, sizeof(datum *), 0};
+int add_comp_room(company * this_comp, char * name, int set_func, int get_func, short set_func_type, short get_func_type)
+{
+	company_room * temp;
+	int i;
+	int min_build_size;
+	VIS_EnterCriticalSection(this_comp->lock);
+	DEBUGPRINTF("add_comp_room: %s", name);
+	DEBUGPRINTF(", num_rooms: %d, room_storage: %d\n", this_comp->num_rooms, this_comp->room_storage);
+	if(this_comp->room_storage - this_comp->num_rooms <= 0)
+	{
+		if(this_comp->room_storage < 2)
+			this_comp->room_storage = 4;
+		else
+			this_comp->room_storage = this_comp->room_storage + ((this_comp->room_storage) >> 1);
+		temp = MALLOC(sizeof(company_room) * this_comp->room_storage, "company room storage");
+		memcpy(temp, this_comp->room_list, sizeof(company_room)*this_comp->num_rooms);
+		VIS_FREE(this_comp->room_list, "company room list");
+		this_comp->room_list = temp;
+	}
+	if(this_comp->build_size >= 0)
+	{
+		DEBUGPRINTF("get_func_type: %d, room_build_sizes[%d] = %d\n", get_func_type, get_func_type, room_build_sizes[get_func_type]);
+		if(get_func_type && get_func_type != ROOM_WORKER && get_func == -1)
+			get_func = this_comp->build_size;
+		if(set_func_type && set_func_type != ROOM_WORKER && set_func == -1)
+			set_func = this_comp->build_size;
+		if(room_build_sizes[set_func_type])
+			if(room_build_sizes[set_func_type] > room_build_sizes[get_func_type])
+				min_build_size = room_build_sizes[set_func_type] + set_func;
+			else
+				min_build_size = room_build_sizes[get_func_type] + get_func;
+		else if(room_build_sizes[get_func_type])
+			min_build_size = room_build_sizes[get_func_type] + get_func;
+		if(min_build_size > this_comp->build_size)
+			this_comp->build_size = min_build_size;	
+	}
+	i = this_comp->num_rooms;
+	DEBUGPUTS("Copying name\n");
+	this_comp->room_list[this_comp->num_rooms++].name = MALLOC(strlen(name) + 1, "company room name");
+	strcpy(this_comp->room_list[i].name, name);
+	DEBUGPUTS("Setting func types\n");
+	this_comp->room_list[i].set_func_type = set_func_type;
+	this_comp->room_list[i].get_func_type = get_func_type;
+	DEBUGPRINTF("Setting funcs: get = %d, set = %d\n", get_func, set_func);
+	//TODO: Change the signature of this function so that get_func and set_func are void * so we can safely pass in pointers for future get_func types
+	this_comp->room_list[i].get_func = (void *)get_func;
+	this_comp->room_list[i].set_func = (void *)set_func;
+	DEBUGPRINTF("Build size is now: %d\n", this_comp->build_size);
+	DEBUGPUTS("before return\n");
+	VIS_LeaveCriticalSection(this_comp->lock);
+	return i;
+}
+
+worker_def * create_worker(program * prog, char * name, int num_inputs, int num_outputs, short type)
+{
+	custom_worker * aworker;
+	int i, j;
+	int thisdef;
+	worker_def * deflist;
+	DEBUGPRINTF("create_worker: %s with %d inputs and %d outputs\n", name, num_inputs, num_outputs);
+	if(!strcmp(name, "Main"))
+	{
+		thisdef = 0;
+		deflist = prog->defs->deflist;
+	}
+	else
+	{
+		if(prog->current->num_defs >= prog->current->defs_storage) {
+			prog->current->next = MALLOC(sizeof(defchunk) + (START_DEF_STORAGE - 1) * sizeof(worker_def), "worker def storage");
+			prog->current = prog->current->next;
+			prog->current->defs_storage = START_DEF_STORAGE;
+			prog->current->num_defs = 0;
+			prog->current->next = NULL;
+		}
+		if(prog->current == prog->defs && prog->current->num_defs == 0)
+			prog->current->num_defs = 1;
+		thisdef = prog->current->num_defs;
+		deflist = prog->current->deflist;
+	}
+	DEBUGPRINTF("new deflist index: %d\n", thisdef);
+	if(type & USER_FLAG && (type & TYPE_MASK) == WORKER_TYPE)
+	{
+		//puts("Creating custom worker.");
+		aworker = MALLOC(sizeof(custom_worker), "custom worker implementation");
+		aworker->num_workers = 0;
+		aworker->num_wires = 0;
+		aworker->workerlist = MALLOC(sizeof(worker)*NUM_WORKERS_START, "custom worker workerlist");
+		aworker->worker_storage = NUM_WORKERS_START;
+		aworker->wirelist = MALLOC(sizeof(wire)*NUM_WIRES_START, "custom worker wirelist");
+		aworker->wire_storage = NUM_WIRES_START;
+		aworker->workers_to_wires_up = MALLOC(sizeof(int)*(NUM_WIRES_START+1),"custom worker workers to wires up");
+		aworker->workers_to_wires_down = MALLOC(sizeof(int)*(NUM_WIRES_START+1),"custom worker workers to wires down");
+		aworker->dirty = TRUE;
+		VIS_InitializeCriticalSection(aworker->lock);
+		deflist[thisdef].implement_func = aworker;
+	}
+	DEBUGPUTS("Setting properties\n");
+	deflist[thisdef].num_inputs = num_inputs;
+	deflist[thisdef].num_outputs = num_outputs;
+	deflist[thisdef].type = type;
+	DEBUGPUTS("Calling malloc\n");
+	deflist[thisdef].name = MALLOC(strlen(name)+1, "worker def name");
+	DEBUGPRINTF("malloc return: %X, calling strcpy\n", deflist[thisdef].name);
+	strcpy(deflist[thisdef].name, name);
+	DEBUGPUTS("strcpy done\n");
+	
+	if(num_inputs)
+		deflist[thisdef].input_types = MALLOC(sizeof(short) * num_inputs, "worker def input types");
+	else
+		deflist[thisdef].input_types = NULL;
+	if(num_outputs)
+		deflist[thisdef].output_types = MALLOC(sizeof(short) * num_outputs, "worker def output types");
+	else
+		deflist[thisdef].output_types = NULL;
+	for(i = 0; i < num_inputs; ++i)
+		deflist[thisdef].input_types[i] = ANY_TYPE;
+	deflist[thisdef].num_stores = 0;
+	deflist[thisdef].uses_stores = NULL;
+	deflist[thisdef].transaction_flags = TRANSACTION_RETRY;
+	if(thisdef >= prog->current->num_defs)
+		prog->current->num_defs = thisdef+1;
+	for(i = 0; name[i] != '\0'; ++i)
+	{
+		if(name[i] == '@')
+		{
+			DEBUGPRINTF("Name ends in %s\n", name+i);
+			for(j = 0; j < prog->num_companies; ++j)
+			{
+				if(!strcmp(name+i+1, prog->companylist[j].name))
+				{
+					DEBUGPRINTF("Worker is a method of company %d, ", j);
+					DEBUGPRINTF("%s\n", prog->companylist[j].name);
+					add_method(prog->companylist+j, deflist+thisdef);
+					break;
+				}
+			}
+			break;
+		}
+	}
+	deflist[thisdef].program = prog;
+	return deflist + thisdef;
+}
+
+int find_worker(char * name, int * num_inputs, int * num_outputs, program * prog, worker_def ** def)
+{
+	int i;
+	int term;
+	int len;
+	defchunk * current;
+	worker_def * temp;
+	DEBUGPRINTF("Calling strlen on name: %X\n", name);
+	len = strlen(name);
+	DEBUGPRINTF("find_worker: %s\n", name);
+	if(len >= 2 && !strcmp(name+len-2, ">>"))
+	{
+		DEBUGPUTS("Get property\n");
+		term = len-2;
+		for(i = term-1; i > 0; --i)
+		{
+			if(name[i] == ' ')
+				term = i;
+			else
+				break;
+		}
+		DEBUGPRINTF("term: %d\n", term);
+		name[term] = '\0';
+		DEBUGPRINTF("name: %s\n", name);
+		if(num_inputs);
+			*num_inputs = 1;
+		if(num_outputs)
+			*num_outputs = 1;
+		return -1;
+	}
+	if(len >= 2 && !strcmp(name+len-2, "<<"))
+	{
+		DEBUGPUTS("Set property\n");
+		term = len-2;
+		for(i = term-1; i > 0; --i)
+		{
+			if(name[i] == ' ')
+				term = i;
+			else
+				break;
+		}
+		DEBUGPRINTF("term: %d\n", term);
+		name[term] = '\0';
+		DEBUGPRINTF("name: %s\n", name);
+		if(num_inputs);
+			*num_inputs = 2;
+		if(num_outputs)
+			*num_outputs = 1;
+		return -2;
+	}
+	current = prog->defs;
+	while(current)
+	{
+		for(i = 0; i < current->num_defs; ++i)
+		{
+			if(current->deflist[i].name && !strcmp(current->deflist[i].name, name))
+			{
+				DEBUGPRINTF("Found worker #%d\n", i);
+				if(num_inputs)
+					*num_inputs = current->deflist[i].num_inputs;
+				if(num_outputs)
+					*num_outputs = current->deflist[i].num_outputs;
+				if(def)
+					*def = current->deflist + i;
+				return i;
+			}
+		}
+		current = current->next;
+	}
+	if(num_inputs && num_outputs)
+	{
+		for(i = 1; i < prog->num_companies; ++i)
+		{
+			temp = find_method(i, name, *num_inputs, prog);
+			if(temp && temp->num_outputs >= *num_outputs)
+			{
+				*def = create_worker(prog, name, temp->num_inputs, temp->num_outputs, MAGIC_TYPE);
+				return 1;
+			}
+		}
+	}
+	else
+	{
+		for(i = 1; i < prog->num_companies; ++i)
+		{
+			temp = find_method_noinputcheck(i, name, prog);
+			if(temp)
+			{
+				*def = create_worker(prog, name, temp->num_inputs, temp->num_outputs, MAGIC_TYPE);
+				return 1;
+			}
+		}
+	}
+	DEBUGPUTS("Could not find worker\n");
+	return -3;
+}
+
+int generic_add_to_def(worker_def * parent, char * name,int display_type, int type, int num_inputs, int num_outputs, double xpos, double ypos)
+{
+	int returnval;
+	worker * temp;
+	VIS_EnterCriticalSection(parent->implement_func->lock);
+		if(parent->implement_func->num_workers >= parent->implement_func->worker_storage) {
+			parent->implement_func->worker_storage = parent->implement_func->num_workers + (parent->implement_func->num_workers >> 1);
+			parent->implement_func->workerlist = realloc(parent->implement_func->workerlist, parent->implement_func->worker_storage * sizeof(worker));
+		}
+		strcpy(parent->implement_func->workerlist[parent->implement_func->num_workers].name, name);
+		parent->implement_func->workerlist[parent->implement_func->num_workers].type=type;
+		parent->implement_func->workerlist[parent->implement_func->num_workers].num_inputs = num_inputs;
+		parent->implement_func->workerlist[parent->implement_func->num_workers].num_outputs = num_outputs;
+		parent->implement_func->workerlist[parent->implement_func->num_workers].null_input = FALSE;
+		parent->implement_func->workerlist[parent->implement_func->num_workers].magic_cache_implement = NULL;
+		parent->implement_func->workerlist[parent->implement_func->num_workers].magic_cache_type = 0;
+		VIS_InitializeCriticalSection(parent->implement_func->workerlist[parent->implement_func->num_workers].lock);
+		parent->implement_func->dirty = TRUE;
+		//puts("end generic_add_to_def");
+		DEBUGPRINTF("generic_add_to_def: %s with type %d and num_inputs %d and num_outputs %d returned %d\n", name, type, num_inputs, num_outputs, parent->implement_func->num_workers);
+		returnval =  parent->implement_func->num_workers++;
+	VIS_LeaveCriticalSection(parent->implement_func->lock);
+	return returnval;
+}
+
+int add_worker_to_def(worker_def * parent, worker_def * worker, double xpos, double ypos)
+{
+	int list_index;
+	list_index = generic_add_to_def(parent, worker->name, TRAPEZOID, WORKER, worker->num_inputs, worker->num_outputs, xpos, ypos);
+
+	parent->implement_func->workerlist[list_index].value_index = worker;
+	return list_index;
+}
+
+int add_get_comp_room(worker_def * parent, char * name, double xpos, double ypos)
+{
+	return generic_add_to_def(parent, name, RECTANGLE, GET_COMP, 1, 2, xpos, ypos);
+}
+
+int add_set_comp_room(worker_def * parent, char * name, double xpos, double ypos)
+{
+	return generic_add_to_def(parent, name, RECTANGLE, SET_COMP, 2, 1, xpos, ypos);
+}
+
+int add_global(worker_def * parent, char * name, double xpos, double ypos, int type)
+{
+	int i,j;
+	int thisdef;
+	int num_in, num_out;
+	if(type == SET_GLOBAL)
+	{
+		num_in = 1;
+		num_out = 0;
+		parent->transaction_flags |= TRANSACTION_WRITE;
+	}
+	else
+	{
+		num_in = 0;
+		num_out = 1;
+	}
+	thisdef = generic_add_to_def(parent, name, RECTANGLE, type, num_in, num_out, xpos, ypos);
+	for(i = 0; name[i+1] != '\0'; ++i)
+	{
+		if(name[i] == ':' && name[i+1] == ':')
+		{
+			parent->implement_func->workerlist[thisdef].value_index = (void *)-1;
+			if(i > 0)
+			{
+				for(j = 0; j < parent->num_stores; ++j)
+				{
+					if(strlen(parent->uses_stores[j]) == i && !memcmp(parent->uses_stores[j], name, i))
+					{
+						parent->implement_func->workerlist[thisdef].value_index = (void *)j;
+						break;
+					}
+				}
+				if(parent->implement_func->workerlist[thisdef].value_index < 0)
+				{
+					name[i] = '\0';
+					printf("Error: Worker %s is not declared to use global store %s but references it.\n", parent->name, name);
+					exit(-1);
+				} 
+			}
+			else if(type == SET_GLOBAL)
+				parent->implement_func->workerlist[thisdef].value_index = 0;
+			parent->implement_func->workerlist[thisdef].io_num = i+2;
+			break;
+		}
+	}
+	return thisdef;
+}
+
+int add_global_get(worker_def * parent, char * name, double xpos, double ypos)
+{
+	return add_global(parent, name, xpos, ypos, GET_GLOBAL);
+}
+
+int add_global_set(worker_def * parent, char * name, double xpos, double ypos)
+{
+	return add_global(parent, name, xpos, ypos, SET_GLOBAL);
+}
+
+int find_object(worker_def * def, char * name, int type)
+{
+	int i;
+	for(i = 0; i < def->implement_func->num_workers; ++i)
+		if(!strcmp(def->implement_func->workerlist[i].name, name) && def->implement_func->workerlist[i].type == 1)
+			break;
+	if(i < def->implement_func->num_workers)
+		return i;
+	return -1;
+}
+
+int create_find_room(worker_def * def, char * name, double xpos, double ypos)
+{
+	int found = find_object(def, name, ROOM);
+	if(found >= 0)
+		return found;
+	return generic_add_to_def(def, name, RECTANGLE, ROOM, 1, 1, xpos, ypos);
+}
+
+int add_constant(worker_def * def, char * value, double xpos, double ypos)
+{
+	int index = generic_add_to_def(def, value, RECTANGLE, CONSTANT, 0, 1, xpos, ypos);
+	def->implement_func->workerlist[index].value_index = get_constant(value, -1, def->program);
+	return index;
+}
+
+int add_input_num(worker_def * def, char * name, int input_num, double xpos, double ypos)
+{
+	int i;
+	unsigned short * temp_types;
+	int found;
+	if(def->num_inputs <= input_num)
+	{
+		temp_types = def->input_types;
+		def->input_types = MALLOC(sizeof(short)*(input_num+1), "worker def input types");
+		if(temp_types) {
+			memcpy(def->input_types, temp_types, sizeof(short)*def->num_inputs);
+			VIS_FREE(temp_types, "temp types?");
+		}
+		for(i = def->num_inputs; i <= input_num; ++i)
+			def->input_types[i] = ANY_TYPE;
+		def->num_inputs = input_num+1;
+	}
+	found = generic_add_to_def(def, name, RECTANGLE, INPUT, 0, 1, xpos, ypos);
+	def->implement_func->workerlist[found].io_num = input_num;
+	return found;
+}
+int add_input(worker_def * def, char * name, double xpos, double ypos)
+{
+	
+	int input_num;
+	int i;
+	for(i = 0; name[i] != 0; ++i)
+		if(name[i] == '(')
+		{
+			input_num = atol(name+i+1);
+			break;
+		}
+	return add_input_num(def, name, input_num, xpos, ypos);
+}
+
+int add_output_num(worker_def * def, char * name, int output_num, double xpos, double ypos)
+{
+	int i;
+	unsigned short * temp_types;
+	int found;
+	if(def->num_outputs <= output_num)
+	{
+		temp_types = def->output_types;
+		def->output_types = MALLOC(sizeof(short)*(output_num+1), "worker def output types");
+		if(temp_types)
+		{
+			memcpy(def->output_types, temp_types, sizeof(short)*def->num_outputs);
+			VIS_FREE(temp_types, "temp types?");
+		}
+		for(i = def->num_outputs; i <= output_num; ++i)
+			def->output_types[i] = ANY_TYPE;
+		def->num_outputs = output_num+1;
+	}
+	found = generic_add_to_def(def, name, RECTANGLE, OUTPUT, 1, 0, xpos, ypos);
+	def->implement_func->workerlist[found].io_num = output_num;
+	return found;
+}
+int add_output(worker_def * def, char * name, double xpos, double ypos)
+{
+	int output_num;
+	int i;
+	
+	for(i = 0; name[i] != 0; ++i)
+		if(name[i] == '(')
+		{
+			output_num = atol(name+i+1);
+			break;
+		}
+	return add_output_num(def, name, output_num, xpos, ypos);
+}
+
+int create_find_output(worker_def * def, char * name, double xpos, double ypos)
+{
+	int output_num;
+	int i;
+	unsigned short * temp_types;
+	int found = find_object(def, name, OUTPUT);
+	if(found >= 0)
+		return found;
+	return add_output(def, name, xpos, ypos);
+}
+
+void add_wire(worker_def * def, int start, int output_num, int end, int input_num)
+{
+	VIS_EnterCriticalSection(def->implement_func->lock);
+		if(def->implement_func->num_wires >= def->implement_func->wire_storage) {
+			def->implement_func->wire_storage = def->implement_func->num_wires + (def->implement_func->num_wires >> 1);
+			def->implement_func->wirelist = realloc(def->implement_func->wirelist, def->implement_func->wire_storage * sizeof(wire));
+			def->implement_func->workers_to_wires_up = realloc(def->implement_func->workers_to_wires_up, (def->implement_func->wire_storage+1) * sizeof(int));
+			def->implement_func->workers_to_wires_down = realloc(def->implement_func->workers_to_wires_down, (def->implement_func->wire_storage+1) * sizeof(int));
+		}
+		def->implement_func->wirelist[def->implement_func->num_wires].start_worker = start;
+		def->implement_func->wirelist[def->implement_func->num_wires].end_worker = end;
+		def->implement_func->wirelist[def->implement_func->num_wires].output_num = output_num;
+		def->implement_func->wirelist[def->implement_func->num_wires].input_num = input_num;
+		def->implement_func->dirty = TRUE;
+		++def->implement_func->num_wires;
+		if(input_num == -1)
+		{
+			def->implement_func->workerlist[end].null_input = TRUE;
+		}
+	VIS_LeaveCriticalSection(def->implement_func->lock);
+}
+
+int process_expression(worker_def * def, int num_outputs, char ** outvars, int num_inputs, char ** inputs, char * workername, BOOL worker_expr, int block_depth, int * block_workers, int * block_output, int last_worker)
+{
+	int i,j;
+	int current;
+	int this_worker;// = ++return_worker;
+	int expected_in, expected_out;
+	int input_num=-1;
+	int worker_num;
+	worker_def * call_def;
+	BOOL block_attach=FALSE;
+	BOOL room = FALSE;
+	BOOL global_flag;
+	if(worker_expr)
+	{
+		DEBUGPUTS("calling find_worker\n");
+		expected_in = num_inputs;
+		expected_out = num_outputs;
+		worker_num = find_worker(workername, &expected_in, &expected_out, def->program, &call_def);
+		DEBUGPRINTF("\nWorker %s with %d inputs and %d outputs expects %d inputs and %d outputs\n", workername, num_inputs, num_outputs, expected_in, expected_out);
+		if(worker_num >= 0)
+			this_worker = add_worker_to_def(def, call_def, 1.0, 1.0);
+		else if(worker_num == -1)
+			this_worker = add_get_comp_room(def, workername, 1.0, 1.0);
+		else if(worker_num == -2)
+			this_worker = add_set_comp_room(def, workername, 1.0, 1.0);
+		else
+		{
+			ERRORPRINTF("Could not find a worker named %s or a method of the same name with %d inputs and at least %d outputs\n", workername, num_inputs, num_outputs);
+			for(i = 0; i < num_inputs; ++i)
+			{
+				ERRORPRINTF("Input %d was %s\n", i, inputs[i]);
+			}
+			exit(-1);
+		}
+	}
+	else
+	{
+		if(workername[0] == '{' || workername[0] == '"' || (workername[0] >= '0' && workername[0] <= '9') || strcmp(workername, "Yes") == 0 || strcmp(workername, "No") == 0)
+		{
+			//Constant expression
+			this_worker = add_constant(def, workername, 1.0, 1.0);
+		}
+		/*else if(workername[0] == '"')
+		{
+			//printf("\nString %s\n", workername);
+			workername[strlen(workername)-1] = '\0';
+			this_worker = add_constant(def, workername+1, 1.0, 1.0);
+		}
+		else if(workername[0] >= '0' && workername[0] <= '9')
+		{
+			//printf("\nNumber %s\n", workername);
+			this_worker = add_constant(def, workername, 1.0, 1.0);
+		}
+		else if(strcmp(workername, "Yes") == 0 || strcmp(workername, "No") == 0)
+		{
+			this_worker = add_constant(def, workername, 1.0, 1.0);
+		}*/
+		else
+		{
+			for(i = 0; workername[i] != 0; ++i)
+				if(workername[i] == '(')
+				{
+					input_num = atol(workername + i+1);
+					break;
+				}
+			if(input_num >= 0)
+			{
+				//printf("\nInput %d %s\n", input_num, workername);
+				this_worker = add_input(def, workername, 1.0, 1.0);
+			}
+			else
+			{
+				room = TRUE;
+				//printf("\nRoom %s\n", workername);
+				for(i = 0; i < strlen(workername)-1; ++i)
+				{
+					if(workername[i] == ':' && workername[i+1] == ':')
+					{
+						room = FALSE;
+						break;
+					}
+				}
+				if(room)
+					this_worker = create_find_room(def, workername, 1.0, 1.0);
+				else
+					this_worker = add_global_get(def, workername, 1.0, 1.0);
+				
+			}
+		}
+	}
+	for(i = 0; i < num_inputs; ++i)
+		if(inputs[i])
+		{
+			if(!strcmp(inputs[i], "~")) 
+			{
+				//printf("Input %d = ~ (parent block)\n", i);
+				if(!block_depth)
+				{
+					printf("Error: Reference to parent block (~) for input %d of worker %s, but block depth is 0", i, workername);
+					exit(-2);
+				}
+				add_wire(def, block_workers[block_depth-1], block_output[block_depth-1], this_worker, i);
+				block_attach = TRUE;
+			}
+			else
+			{
+				DEBUGPRINTF("Processing input %d (%s)\n", i, inputs[i]);
+				if(block_depth)
+					current = parse_body(def, inputs[i], strlen(inputs[i]), block_depth, block_output, block_workers);
+				else
+					current = parse_body(def, inputs[i], strlen(inputs[i]), 0, NULL, NULL);
+				add_wire(def, current, 0, this_worker, i);
+			}
+		}
+		else
+		{
+			//printf("Input %d = last_worker(%d)\n", i, last_worker);
+			add_wire(def, last_worker, 0, this_worker, i);
+		}
+	for(i = 0; i < num_outputs; ++i)
+	{
+		global_flag = FALSE;
+		//printf("Output %d = %s\n", i, outvars[i]);
+		for(j = 0; outvars[i][j] != '\0'; ++j)
+			if(outvars[i][j] == '(')
+				break;
+			else if(outvars[i][j] == ':' && outvars[i][j+1] == ':')
+				break;				
+		if(outvars[i][j] == '\0')
+			current = create_find_room(def, outvars[i], 2.0, 2.0);
+		else if(outvars[i][j] == ':')
+			current = add_global_set(def, outvars[i], 2.0, 2.0);
+		else
+			current = create_find_output(def, outvars[i], 2.0, 2.0);
+		add_wire(def, this_worker, i, current, 0);
+	}
+	
+	//printf("Current blockdepth: %d\n", block_depth);
+	if(block_depth > 0)
+	{
+		//printf("Block Worker: %d\nBlock Output: %d\n", block_workers[block_depth-1], block_output[block_depth-1]);
+		if(worker_expr && num_inputs < expected_in)
+		{
+			if(block_attach)
+				printf("Warning: Worker %s is attached to block both explicityly and implicity (i.e. at least one input was stated as ~, but there are still unsatisfied inputs)\n", workername);
+			if(expected_in - num_inputs > 1)
+				printf("Warning: More than one input of worker %s implicitly tied to block (%d inputs implicitly tied)", workername, expected_in - num_inputs);
+			for(i = num_inputs; i < expected_in; ++i)
+				add_wire(def, block_workers[block_depth-1], block_output[block_depth-1], this_worker, i);
+				
+		}
+		else if(!block_attach && !room)
+		{
+			add_wire(def, block_workers[block_depth-1], block_output[block_depth-1], this_worker, -1);
+			//def->implement_func->workerlist[this_worker].null_input = TRUE;
+		}
+	} 
+	else  if(worker_expr && num_inputs < expected_in)
+	{
+		ERRORPRINTF("Error: Worker %s expects %d input(s), but was only given %d input(s)\n", workername, expected_in, num_inputs);
+		exit(-1);
+	}
+	//printf("Returning %d\n\n", this_worker);
+	return this_worker;
+}
+typedef enum {NULL_STATE, OUT_STATE, BETWEEN_OUT, BEFORE_WORK, PRE_IN_STATE, BETWEEN_PRE_IN, WORK_STATE, IN_STATE, BETWEEN_IN, AFTER_IN, BLOCK_FIND, LINE_COMMENT_STATE} parse_state;
+char state_txt[12][20] = {"Null","Out","Between Out","Before Work","Pre Input","Between Pre-Input","Worker","Input","Between Input","After Input","Block Find"};
+int parse_body(worker_def * def, char * code, int len, int prev_block_depth, int * prev_block_output, int * prev_block_workers)
+{
+	char * outputs[32];
+	char * inputs[32];
+	char * worker;
+	short saw_line=0;
+	int num_inputs=0, num_outputs=0;
+	int left_bracket=0;
+	int left_curly=0;
+	int block_depth = 0;
+	int block_workers[32];
+	int block_output[32];
+	int last_worker = 0;
+	BOOL worker_expr = FALSE;
+	BOOL in_string = FALSE;
+	BOOL literal = FALSE;
+	BOOL do_curly = FALSE;
+	BOOL saw_newline = FALSE;
+	int i,j;
+	int start;
+	int line_comment_start;
+	parse_state state = NULL_STATE;
+	parse_state old_state;
+	DEBUGPRINTF("code: %X\n", code);
+	//printf("prev_block_depth: %d\n", prev_block_depth);
+	for(i=0; i < len; ++i)
+	{
+		//printf("i: %d, code[i]: '%c', state: %s(%d)\n", i, code[i], state_txt[state],state);
+		DEBUGPRINTF("i: %d, code[i]: '%c', state: %s(%d), left_bracket: %d, num_inputs: %d\n", i, code[i], state_txt[state],state, left_bracket, num_inputs);
+		if(!in_string)
+		{
+			if(state != LINE_COMMENT_STATE)
+			{
+				if(code[i] == '/' && code[i+1] == '/')
+				{
+					old_state = state;
+					state = LINE_COMMENT_STATE;
+					line_comment_start = i;
+					i += 2;
+				}
+				else if(code[i] == '[')
+					++left_bracket;
+				else if(code[i] == ']')
+					--left_bracket;
+				else if(code[i] == '{')
+					do_curly = TRUE;
+				else if(code[i] == '}')
+					--left_curly;
+				else if(code[i] == '"')
+				{
+					in_string = TRUE;
+					//continue;
+				}
+			}
+			if(left_curly == 0)
+			{
+				switch(state)
+				{
+				case NULL_STATE:
+					
+					if(code[i] == '[')
+					{
+						//puts("worker_expr = TRUE");
+						worker_expr = TRUE;
+						state = BETWEEN_PRE_IN;
+					}
+					else if(code[i] == ':' && code[i+1] == '|')
+					{
+						++i;
+						state = BLOCK_FIND;
+					}
+					else if(code[i] == '|' && code[i+1] == ':')
+					{
+						block_workers[block_depth] = last_worker;
+						block_output[block_depth++] = 0;
+						//puts("Found |: increasing block depth");
+						++i;
+					}
+					else if(!is_whitespace(code[i]))
+					{
+						start = i;
+						for(j = i; j < len-1; ++j)
+							if(code[j] == '<' && code[j+1] == '-')
+							{
+								state = OUT_STATE;
+								--i;
+								break;
+							}
+							else if(code[j] == '[' || code[j] == '\n' || (code[j] == '|' && code[j+1] == ':') || code[j] == '#' || code[j] == '"')
+							{
+								state = WORK_STATE;
+								break;
+							}
+						if(state == NULL_STATE)
+							state = WORK_STATE;
+					}
+					break;
+				case OUT_STATE:
+					if(code[i] == ',' || (code[i] == '<' && code[i+1] == '-'))
+					{
+						outputs[num_outputs++] = code + start;
+						for(j = i-1; j > start; --j)
+							if(!is_whitespace(code[j]))
+								break;
+						if(code[i] == ',')
+							state = BETWEEN_OUT;
+						else
+						{
+							state = BEFORE_WORK;
+							++i;
+						}
+						code[j+1] = '\0';
+					}
+					break;
+				case BETWEEN_OUT:
+					if(!is_whitespace(code[i]))
+					{
+						start = i;
+						state = OUT_STATE;
+						--i;
+					}
+					break;
+				case BEFORE_WORK:
+					if(code[i] == '[')
+					{
+						//puts("worker_expr = TRUE");
+						worker_expr = TRUE;
+						state = BETWEEN_PRE_IN;
+					}
+					else if(code[i] == ':' && code[i+1] == '|')
+					{
+						start = i;
+						while(i < len && (code[i] != '\n' || saw_line < 5))
+						{
+							if(code[i] == '\n')
+								++saw_line;
+							++i;
+						}
+						code[i] = '\0';
+						ERRORPRINTF("Error: Expected a worker name, but found a closing bracket (:|) instead at:\n%s", code + start);
+						exit(-1);
+					}
+					else if(!is_whitespace(code[i]))
+					{
+						start = i;
+						state = WORK_STATE;
+					}
+					break;
+				case PRE_IN_STATE:
+					if((code[i] == ',' && left_bracket == 1) || (code[i] == ']' && left_bracket == 0) )
+					{
+						inputs[num_inputs++] = code + start;
+						for(j = i-1; j > start; --j)
+							if(!is_whitespace(code[j]))
+								break;
+						if(code[i] == ',')
+							state = BETWEEN_PRE_IN;
+						else
+							state = BEFORE_WORK;
+						code[j+1] = '\0';
+					}
+					break;
+				case BETWEEN_PRE_IN:
+					if(code[i] == ']')
+					{
+						state = BEFORE_WORK;
+					}
+					else if(!is_whitespace(code[i]))
+					{
+						start = i;
+						state = PRE_IN_STATE;
+					}
+					break;
+				case WORK_STATE:
+					if(code[i] == '[' || code[i] == '#' || (code[i] == '|' && code[i+1] == ':') || (code[i] == ':' && code[i+1] == '|') || code[i] == '\n')
+					{
+						for(j = i-1; j > start; --j)
+							if(!is_whitespace(code[j]))
+								break;
+						
+						worker = code+start;
+			
+						if(code[i] == '[')
+						{
+							code[j+1] = '\0';
+						//	puts("Worker to Between Input");
+						//	puts("worker_expr = TRUE;");
+							worker_expr = TRUE;
+							state = BETWEEN_IN;
+						}
+						else if(code[i] == '#' || code[i] == '\n')
+						{
+							code[j+1] = '\0';
+						//	puts("Worker to Null State(#)");
+							//printf("worker_expr: %d\n", worker_expr);
+							if(block_depth)
+								last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, block_depth, block_workers, block_output, last_worker);
+							else
+								last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, prev_block_depth, prev_block_workers, prev_block_output, last_worker);
+							num_inputs = 0;
+							num_outputs = 0;
+							worker_expr = FALSE;
+							state = NULL_STATE;
+						}
+						else if(code[i] == ':')
+						{
+							code[j+1] = '\0';
+							if(block_depth)
+								last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, block_depth, block_workers, block_output, last_worker);
+							else
+								last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, prev_block_depth, prev_block_workers, prev_block_output, last_worker);
+							num_inputs = 0;
+							num_outputs = 0;
+							worker_expr = FALSE;
+							state = BLOCK_FIND;
+							++i;
+						}
+						else
+						{
+							//puts("Worker to Null State(else)");
+							code[j+1] = '\0';
+							if(block_depth)
+								last_worker = block_workers[block_depth] = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, block_depth, block_workers, block_output, last_worker);
+							else
+								last_worker = block_workers[block_depth] = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, prev_block_depth, prev_block_workers, prev_block_output, last_worker);
+							block_output[block_depth++] = 0;
+							//puts("Found |:, increasinb block depth");
+							num_inputs = 0;
+							num_outputs = 0;
+							worker_expr = FALSE;
+							state = NULL_STATE;
+							++i;
+						}
+						
+					}
+					break;
+				case BETWEEN_IN:
+					if(code[i] == ']')
+					{
+						state = AFTER_IN;
+					}
+					else if(!is_whitespace(code[i]))
+					{
+						start = i;
+						state = IN_STATE;
+					}
+					break;
+				case IN_STATE:
+					if((code[i] == ',' && left_bracket == 1) || (code[i] == ']' && left_bracket == 0) )
+					{
+						inputs[num_inputs++] = code + start;
+						for(j = i-1; j > start; --j)
+							if(!is_whitespace(code[j]))
+								break;
+						
+						if(code[i] == ',')
+							state = BETWEEN_IN;
+						else
+							state = AFTER_IN;
+						code[j+1] = '\0';
+					}
+					break;
+				case AFTER_IN:
+					//puts("AFTER_IN test");
+					if(code[i] == '\n')
+						saw_newline = TRUE;
+					if(code[i] == '|' && code[i+1] == ':')
+					{
+						if(block_depth)
+							last_worker = block_workers[block_depth] = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, block_depth, block_workers, block_output, last_worker);
+						else
+							last_worker = block_workers[block_depth] = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, prev_block_depth, prev_block_workers, prev_block_output, last_worker);
+						block_output[block_depth++] = 0;
+						//puts("Found |: increasing block depth");
+						state = NULL_STATE;
+						num_inputs = 0;
+						num_outputs = 0;
+						worker_expr = FALSE;
+						++i;
+					}
+					else if(code[i] == '#')
+					{
+						if(block_depth)
+							last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, block_depth, block_workers, block_output, last_worker);
+						else
+							last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, prev_block_depth, prev_block_workers, prev_block_output, last_worker);
+						state = NULL_STATE;
+						num_inputs = 0;
+						num_outputs = 0;
+						worker_expr = FALSE;
+					}
+					else if(code[i] == '[')
+					{
+						if(saw_newline)
+						{
+							if(block_depth)
+								last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, block_depth, block_workers, block_output, last_worker);
+							else
+								last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, prev_block_depth, prev_block_workers, prev_block_output, last_worker);
+							saw_newline = FALSE;
+							state = NULL_STATE;
+							num_inputs = 0;
+							num_outputs = 0;
+							worker_expr = FALSE;
+							--left_bracket;
+							--i;
+						}
+						else
+						{
+							puts("Error: Too many input blocks at");
+							code[i+1] = '\0';
+							for(j = i-1; j > 0; --j)
+							if(code[j] == '\n')
+							{
+								++j;
+								break;
+							}
+							puts(code + j);
+							exit(-1);
+						}
+					}
+					else if(!is_whitespace(code[i]))
+					{
+						if(block_depth)
+							last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, block_depth, block_workers, block_output, last_worker);
+						else
+							last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, prev_block_depth, prev_block_workers, prev_block_output, last_worker);
+						if(saw_newline)
+						{
+							saw_newline = FALSE;
+							num_inputs = 0;
+						}
+						else
+						{
+							num_inputs = 1;
+							inputs[0] = NULL;
+						}
+						state = NULL_STATE;
+						
+						num_outputs = 0;
+						worker_expr = FALSE;
+						--i;
+					}
+					break;
+				case BLOCK_FIND:
+					if(code[i] == '|' && code[i+1] == ':')
+					{
+						//puts("Found |: increasing output number (not block depth)");
+						++block_output[block_depth-1];
+						++i;
+						state = NULL_STATE;
+					}
+					else if(!is_whitespace(code[i]))
+					{
+						//puts("Found :| without another |: following; decreasing block depth");
+						--block_depth;
+						if(code[i] == '[')
+							--left_bracket;
+						--i;
+						num_inputs = 0;
+						state = NULL_STATE;
+						
+					}
+					break;
+				case LINE_COMMENT_STATE:
+					if(code[i+1] == '\n')
+					{
+						for(;line_comment_start <= i; ++line_comment_start)
+							code[line_comment_start] = ' ';
+						state = old_state;
+					}
+					break;
+				}
+			}
+			if(do_curly)
+			{
+				++left_curly;
+				do_curly = FALSE;
+			}
+		}
+		else if(literal)
+			literal = FALSE;
+		else if(code[i] == '"')
+			in_string = FALSE;
+		else if(code[i] == '\\')
+			literal = TRUE;
+	}
+	//printf("State at end of code chunk: %s(%d)\n", state_txt[state], state);
+	if((state != BLOCK_FIND && block_depth != 0) || (state == BLOCK_FIND && block_depth > 1))
+	{
+		ERRORPRINTF("Syntax Error: Missing %d block close symbol(s) (:|)\n", block_depth);
+		exit(-1);
+	}
+	else
+	{
+		switch(state)
+		{
+			case WORK_STATE:
+				for(j = i-1; j > start; --j)
+					if(!is_whitespace(code[j]))
+						break;
+					
+				worker = code+start;
+				code[j+1] = '\0';
+			case AFTER_IN:
+				if(block_depth)
+					last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, block_depth, block_workers, block_output, last_worker);
+				else
+					last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, prev_block_depth, prev_block_workers, prev_block_output, last_worker);
+				break;
+			case BLOCK_FIND:
+			case NULL_STATE:
+				break;
+			default:
+				printf("Syntax Error: State is %s but there are no more characters left to process.\n", state_txt[state]);
+				puts(code + start);
+				exit(-1);
+		}
+	}
+	return last_worker;
+}
+typedef struct parse_worker
+{
+	char * worker_name;
+	int num_inputs;
+	int num_outputs;
+	worker_def * def;
+	char * block;
+	int block_len;
+	struct parse_worker * next;
+} parse_worker;
+
+void parse_company(char * name, char * code, int len, program * prog)
+{
+	char * type_name;
+	char * field_name;
+	int i;
+	int part_start;
+	int part_end;
+	int type;
+	company * comp;
+	BOOL saw_newline;
+	field_name = type_name = NULL;
+	comp = create_company(prog, name, 0, 0, TRUE);
+	i = 0;
+	while(i < len)
+	{
+		saw_newline = FALSE;
+		part_start = -1;
+		for(; i < len; ++i)
+		{
+			DEBUGPRINTF("i: %d, code[i]: %c ", i, code[i]);
+			if(part_start < 0)
+			{
+				if(!is_whitespace(code[i]))
+					part_end = part_start = i;
+			}
+			else if(code[i] == ':' && code[i-1] == ':')
+			{
+				type_name = code + part_start;
+				type_name[part_end - part_start-1] = '\0';
+				part_start = -1;
+				++i;
+				break;
+			}
+			else if(!is_whitespace(code[i]))
+			{
+				DEBUGPUTS("Not whitespace\n");
+				if(saw_newline)
+				{
+					code[part_end] = '\0';
+					add_comp_room(comp, code + part_start, -1, -1, ROOM_VIS_REF, ROOM_VIS_REF);
+					--i;
+					part_start = -1;
+					saw_newline = FALSE;
+				}
+				else
+					part_end = i+1;
+			}
+				
+			else if(code[i] == '\n')
+			{
+				DEBUGPUTS("saw newline\n");
+				saw_newline = TRUE;
+			}
+		}
+		if(i >= len && part_start >= 0 && part_end > part_start)
+		{
+			code[part_end] = '\0';
+			add_comp_room(comp, code + part_start, -1, -1, ROOM_VIS_REF, ROOM_VIS_REF);
+			part_start = -1;
+		}
+		for(; i < len; ++i)
+		{
+			DEBUGPRINTF("i: %d, code[i]: %c ", i, code[i]);
+			if(part_start < 0)
+			{
+				if(!is_whitespace(code[i]))
+					part_end = part_start = i;
+				DEBUGPRINTF("part_start: %d\n", part_start);
+			}
+			else if(!is_whitespace(code[i]))
+			{
+				DEBUGPRINTF("part_end: %d\n", part_end);
+				part_end = i+1;
+			}
+			else if(code[i] == '\n')
+			{
+				DEBUGPRINTF("saw newline, type name: %s\n", type_name);
+				if(!strcmp("Byte", type_name))
+					type = ROOM_BYTE;
+				else if(!strcmp("Word", type_name))
+					type = ROOM_SHORT;
+				else if(!strcmp("Long", type_name))
+					type = ROOM_LONG;
+				else
+					type = ROOM_VIS_REF;
+				code[part_end] = '\0';
+				add_comp_room(comp, code + part_start, -1, -1, type, type);
+				break;
+			}
+		}
+	}
+	if(part_start >= 0 && part_end > part_start)
+	{
+		if(!strcmp("Byte", type_name))
+			type = ROOM_BYTE;
+		else if(!strcmp("Word", type_name))
+			type = ROOM_SHORT;
+		else if(!strcmp("Long", type_name))
+			type = ROOM_LONG;
+		else
+			type = ROOM_VIS_REF;
+		code[part_end] = '\0';
+		add_comp_room(comp, code + part_start, -1, -1, type, type);
+	}
+}
+
+void import(char * filename, program * prog)
+{
+	int size;
+	char * code;
+	FILE * imp;
+	imp = fopen(filename, "rb");
+	if(imp)
+	{
+		fseek(imp, 0, SEEK_END);
+		size = ftell(imp);
+		fseek(imp, 0, SEEK_SET);
+		code = MALLOC(size, "code from imported file");
+		fread(code, 1, size, imp);
+		DEBUGPRINTF("Read %d bytes\n", size);
+		parse(code, size, prog);
+		DEBUGPUTS("Finished parsing import file\n");
+		VIS_FREE(code, "code buffer");
+		fclose(imp);
+	}
+	else
+	{
+		ERRORPRINTF("Warning: Could not open import file: %s\n", filename);
+	}
+}
+
+typedef enum {NULL_PARSE, WORKER_STATE, BLOCK_STATE, STRING_STATE, LITERAL_STATE, LIST_STATE, LIST_STRING, LIST_LITERAL, LINE_COMMENT} super_state;
+char super_state_txt[9][30] = {"Null", "Worker", "Block", "String", "String Literal", "List", "String in List", "String Literal in List", "Single Line Comment"};
+void parse(char * code, int len, program * prog)
+{
+	parse_worker *list=NULL, *current=NULL, *temp;
+	short saw_line = 0;
+	int i,j,k;
+	int block_count = 0;
+	int start;
+	int end;
+	int num_inputs;
+	int num_outputs;
+	int company_len, import_len;
+	char * worker_name;
+	int left_curly=0;
+	int block_done = -1;
+	int comp_start, comp_end;
+	char * company_name;
+	char * comp_block;
+	int comp_block_len;
+	int num_uses;
+	char * importfiles[32];
+	int num_imported = 0;
+	super_state old_state;
+	char ** uses_names = NULL;
+	BOOL lastwasspace = FALSE;
+	super_state state = NULL_PARSE;
+	company_len = strlen("Company");
+	import_len = strlen("Import");
+	for(i = 0; i < len; ++i)
+	{
+		DEBUGPRINTF("i: %d, code[i]: %c, state: %s(%d)\n", i, code[i], super_state_txt[state], state);
+		if(code[i] == '/' && code[i+1] == '/' && state != STRING_STATE && state != LIST_STRING)
+		{
+			old_state = state;
+			state = LINE_COMMENT;
+			i += 2;
+		}
+		switch(state)
+		{
+			case NULL_PARSE:
+				if(len - i >= import_len && !memcmp("Import", code + i, import_len))
+				{
+					start = end = -1;
+					for(j = i+import_len; j < len && code[j] != '\n'; ++j)
+					{
+						if(start < 0)
+						{
+							if(!is_whitespace(code[j]))
+								start = j; 
+						}
+						else
+						{
+							if(!is_whitespace(code[j]))
+								end = j;
+						}
+					}
+					if(end < 0)
+					{
+						puts("Error: Import statement with no file name");
+						exit(-1);
+					}
+					++end;
+					code[end] = '\0';
+					i = end;
+					if(num_imported < 32)
+						importfiles[num_imported++] = code+start;
+					else
+					{
+						puts("Error: You cannot have more than 32 import statements in the same file");
+						exit(-1);
+					}
+				}
+				else if(code[i] == ':' && code[i+1] == '|')
+				{
+					start = i;
+					while((code[i] != '\n' || saw_line < 5) && i < len)
+					{
+						if(code[i] == '\n')
+							++saw_line;
+						++i;
+					}
+					code[i] = '\0';
+					ERRORPRINTF("Error: Unexpected closing bracket (:|) found:\n%s", code + start);
+					exit(-1);
+				}
+				else if(!is_whitespace(code[i]))
+				{
+					start = i;
+					state = WORKER_STATE;
+				}
+				break;
+			case WORKER_STATE:
+				if(is_whitespace(code[i]))
+					lastwasspace = TRUE;
+				else if(code[i] == '|' && code[i+1] == ':')
+				{
+					if(!strncmp(code+start, "Company",company_len) && is_whitespace(code[start+company_len]))
+					{
+						comp_start = -1;
+						comp_end = 0;
+						for(j = start+company_len+1; j < len-1; ++j)
+						{
+							if(comp_start >= 0)
+							{
+								if(code[j] == '|' && code[j+1] == ':')
+									break;
+								else if(!is_whitespace(code[j]))
+									comp_end = j+1;
+							}
+							else
+							{
+								if(!is_whitespace(code[j]))
+									comp_start = j;
+							}
+						}
+						if(comp_start >= 0 && comp_end > comp_start)
+						{
+							company_name = code + comp_start;
+							code[comp_end] = '\0';
+							comp_start = -1;
+							for(j = comp_end+1; j < len-1; ++j)
+							{
+								if(comp_start < 0)
+								{
+									if(code[j] == '|' && code[j+1] == ':')
+										comp_start = j+2;
+								}
+								else
+								{
+									if(code[j] == ':' && code[j+1] == '|')
+									{
+										comp_end = j;
+										break;
+									}
+								}
+							}
+							if(comp_start > 0)
+							{
+								comp_block = code+comp_start;
+								comp_block_len = comp_end-comp_start;
+								DEBUGPRINTF("Company block start: %d, end: %d, length: %d\n", comp_start, comp_end, comp_block_len);
+								code[comp_end] = '\0';
+								i = comp_end+1;
+								parse_company(company_name, comp_block, comp_block_len, prog);
+							}
+							else
+							{
+								printf("Error parsing Company, comp_start is %d\n", comp_start);
+							}
+							
+						}
+						else
+						{
+							puts("Error parsing Company\n");
+						}
+						state = NULL_STATE;
+						
+					}
+					else
+					{
+						for(j = i-1; j > start; --j)
+							if(code[j] != ' ' && code[j] != '\t' && code[j] != '\n' && code[j] != '\r')
+								break;
+						for(k = start; k <= j; ++k)
+							if(code[k] == '(')
+							{
+								code[k] = '\0';
+								num_inputs = atol(code + k + 1);
+							}
+							else if(code[k] == ',')
+								num_outputs = atol(code + k + 1);
+						worker_name = code + start;
+						//printf("Found worker def: %s with %d outputs and %d inputs\n", worker_name, num_outputs, num_inputs);
+						start = i+2;
+						++i;
+						num_uses = 0;
+						state = BLOCK_STATE;
+					}
+				}
+				else if(lastwasspace && !strncmp(code+i, "uses", 4))
+				{
+					for(j = i-1; j > start; --j)
+						if(code[j] != ' ' && code[j] != '\t' && code[j] != '\n' && code[j] != '\r')
+							break;
+					for(k = start; k <= j; ++k)
+						if(code[k] == '(')
+						{
+							code[k] = '\0';
+							num_inputs = atol(code + k + 1);
+						}
+						else if(code[k] == ',')
+							num_outputs = atol(code + k + 1);
+					worker_name = code + start;
+					num_uses = 1;
+					for(j = i + strlen("uses"); code[j] != '|' && j < len; ++j)
+						if(code[j] == ',')
+							++num_uses;
+					DEBUGPRINTF("num_uses: %d\n", num_uses);
+					i += strlen("uses");
+					uses_names = MALLOC(sizeof(char *) * num_uses, "uses stores names");
+					end = -1;
+					start = i;
+					j = 0;
+					while(code[i] != '|' && i < len)
+					{
+						if(code[i] == ',')
+						{
+							uses_names[j] = MALLOC(sizeof(char) * (end-start+1), "global store name for uses stores");
+							memcpy(uses_names[j], code+start, end-start);
+							uses_names[j][end-start] = '\0';
+							DEBUGPRINTF("uses: %s\n", uses_names[j]);
+							end = -1;
+							++j;
+						}
+						else if(code[i] != ' ' && code[i] != '\t' && code[i] != '\r' && code[i] != '\n')
+							end = i+1;
+						else if(end < 0)
+							start = i+1;
+						++i;
+					}
+					if(end >= 0)
+					{
+						uses_names[j] = MALLOC(sizeof(char) * (end-start+1), "global store name for uses stores");
+						memcpy(uses_names[j], code+start, end-start);
+						uses_names[j][end-start] = '\0';
+						DEBUGPRINTF("uses: %s\n", uses_names[j]);
+						end = -1;
+						++j;
+					}
+					start = i+2;
+					++i;
+					state = BLOCK_STATE;
+					
+				}
+				break;
+			case BLOCK_STATE:
+				//printf("Block count: %d\n", block_count);
+				if((i-block_done)>1 && code[i] == ':' && code[i-1] == '|')
+				{
+					++block_count;
+				}
+				else if(code[i] == '"') {
+					state = STRING_STATE;
+				}
+				else if(code[i] == '{') {
+					state = LIST_STATE;
+				}
+				else if(code[i] == '|' && code[i-1] == ':')
+				{
+					if(block_count == 0)
+					{
+						if(current)
+						{
+							current->next = MALLOC(sizeof(parse_worker),"parse worker");
+							current = current->next;
+						}
+						else
+						{
+							list = current = MALLOC(sizeof(parse_worker),"parse worker");
+						}
+						current->num_inputs = num_inputs;
+						current->num_outputs = num_outputs;
+						current->worker_name = worker_name;
+						current->block = code + start;
+						current->block_len = i-start-1;
+						current->next = NULL;
+						current->def = create_worker(prog, current->worker_name, current->num_inputs, current->num_outputs, USER_FLAG | WORKER_TYPE);
+						current->def->uses_stores = uses_names;
+						current->def->num_stores = num_uses;
+						uses_names = NULL;
+						num_uses = 0;
+						state = NULL_PARSE;
+						block_done = -1;
+					}
+					else
+					{
+						block_done = i;
+						--block_count;
+					}
+				}
+				break;
+			case STRING_STATE:
+				if(code[i] == '\\')
+					state = LITERAL_STATE;
+				else if(code[i] == '"')
+					state = BLOCK_STATE;
+				break;
+			case LITERAL_STATE:
+				state = STRING_STATE;
+				break;
+			case LIST_STATE:
+				if(code[i] == '{')
+					++left_curly;
+				else if(code[i] == '}')
+					if(left_curly)
+						--left_curly;
+					else
+						state = BLOCK_STATE;
+				else if(code[i] == '"')
+					state = LIST_STRING;
+				break;
+			case LIST_STRING:
+				if(code[i] == '\\')
+					state = LIST_LITERAL;
+				else if(code[i] == '"')
+					state = LIST_STATE;
+				break;
+			case LIST_LITERAL:
+				state = LIST_STRING;
+				break;
+			case LINE_COMMENT:
+				if(code[i+1] == '\n')
+					state = old_state;
+				break;
+		}
+	}
+	if(state != NULL_PARSE)
+	{
+		printf("Error: Current parse state is %s(%d) in first pass but there are no more characters to parse.\n", super_state_txt[state], state);
+		if(state == BLOCK_STATE)
+		{
+			printf("Worker %s appears to be missing a closing bracket (:|)\n", worker_name);
+		}
+		exit(-3);
+	}
+	for(i = 0; i < num_imported; ++i)
+	{
+		import(importfiles[i], prog);
+	}
+	current = list;
+	while(current)
+	{
+		DEBUGPRINTF("Processing worker %s with %d inputs and %d outputs\n\n", current->worker_name, current->num_inputs, current->num_outputs);
+		parse_body(current->def, current->block, current->block_len, 0, NULL, NULL);
+		temp = current;
+		current = current->next;
+		free(temp);
+	}
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/parser.h	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,27 @@
+#ifndef	PARSER_H__
+#define	PARSER_H__
+
+#include "structs.h"
+
+worker_def * create_worker(program * prog, char * name, int num_inputs, int num_outputs, short type);
+int find_worker(char * name, int * num_inputs, int * num_outputs, program * prog, worker_def ** def);
+int generic_add_to_def(worker_def * parent, char * name,int display_type, int type, int num_inputs, int num_outputs, double xpos, double ypos);
+int add_worker_to_def(worker_def * parent, worker_def * worker, double xpos, double ypos);
+int find_object(worker_def * def, char * name, int type);
+int create_find_room(worker_def * def, char * name, double xpos, double ypos);
+int add_constant(worker_def * def, char * value, double xpos, double ypos);
+int add_input(worker_def * def, char * name, double xpos, double ypos);
+int add_input_num(worker_def * def, char * name, int input_num, double xpos, double ypos);
+int add_output_num(worker_def * def, char * name, int input_num, double xpos, double ypos);
+int add_output(worker_def * def, char * name, double xpos, double ypos);
+int create_find_output(worker_def * def, char * name, double xpos, double ypos);
+void add_wire(worker_def * def, int start, int output_num, int end, int input_num);
+int process_expression(worker_def * def, int num_outputs, char ** outvars, int num_inputs, char ** inputs, char * workername, BOOL worker_expr, int block_depth, int * block_workers, int * block_output, int last_worker);
+int parse_body(worker_def * def, char * code, int len, int prev_block_depth, int * prev_block_output, int * prev_block_workers);
+company * create_company(program * prog, char * name, int num_workers, int num_rooms, BOOL buildable);
+int add_method(company * this_comp, worker_def * def);
+void parse(char * code, int len, program * prog);
+
+
+#endif	//PARSER_H__
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/parser.vistxt	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,1320 @@
+Import extendlib.vistxt
+
+
+
+Company Parser
+|:
+	Arg Begin
+	Arg End
+	Line Comment
+	Comment Begin
+	Comment End
+	Assign
+	Block Begin
+	Block End
+	Blueprint Type Delim
+	Empty Block
+	Binary Operator
+	String Begin
+	String End
+	String Escape 
+	List Begin
+	List End
+	List Delim
+	In Out Delim
+	Do Worker
+	Index Begin
+	Index End
+	Previous
+	Block Val
+	Set Field
+	Get Field
+	Import
+	Blueprint
+	Global Separator
+	Uses
+	Hex Escape
+	Escape Map
+:|
+
+New@Parser(0,1)
+|:
+	out(0) <- [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[Build["Parser"]
+	]Arg Begin << ["["]
+	]Arg End <<["]"]
+	]Line Comment <<["//"]
+	]Comment Begin <<["/*"]
+	]Comment End <<["*/"]
+	]Assign <<["<-"]
+	]Block Begin <<["{"]
+	]Block End <<["}"]
+	]Blueprint Type Delim <<[":"]
+	]Empty Block <<[";"]
+	]Binary Operator <<["`"]
+	]String Begin <<["\""]
+	]String End <<["\""]
+	]String Escape <<["\\"]
+	]List Begin <<["("]
+	]List End <<[")"]
+	]List Delim <<[","]
+	]In Out Delim <<[":"]
+	]Do Worker <<["$"]
+	]Index Begin <<["("]
+	]Index End <<[")"]
+	]Previous <<["@"]
+	]Set Field <<["<<"]
+	]Get Field <<[">>"]
+	]Import <<["Import"]
+	]Blueprint <<["Blueprint"]
+	]Global Separator <<["::"]
+	]Hex Escape <<["x"]
+	]Uses <<["uses"]
+	]Escape Map <<[[[[New@Dictionary[]]Set["n","\n"]]Set["r","\r"]]Set["t","\t"]]
+:|
+
+Company Output Reference
+|:
+	Index
+	Output Number
+:|
+
+New@Output Reference(2,1)
+|:
+	out(0) <- [[Build["Output Reference"]]Index <<[index(0)]]Output Number <<[num(1)]
+:|
+
+Add Pipe Reference(3,1)
+|:
+	reflist <- [refs(0)]Index[name(1)] |::|
+	|:
+		reflist <- New@List[]
+	:|
+	out(0) <- [refs(0)]Set[name(1), [reflist]Append[reference(2)]]
+:|
+
+Assignment Save Reference(5,1)
+|:
+	[[parse worker(3)]Outputs >>]Find[assignment(1)]
+	|:
+		out(0) <- refs(0)
+	:||:
+		out(0) <- Add Pipe Reference[refs(0), assignment(1), New@Output Reference[index(4), output num(2)]]
+	:|
+:|
+
+Company Parse Program
+|:
+	Workers
+	Imports
+	Blueprints
+	Errors
+:|
+
+New@Parse Program(0,1)
+|:
+	out(0) <- [[[Build["Parse Program"]
+	]Workers <<[New@Dictionary[]]
+	]Imports <<[New@Dictionary[]]
+	]Blueprints <<[New@Dictionary[]]
+:|
+
+Company Blueprint Definition
+|:
+	Name
+	Fields
+:|
+
+New@Blueprint Definition(2,1)
+|:
+	out(0) <- [[Build["Blueprint Definition"]]Name << [name(0)]]Fields <<[fields(1)]
+:|
+
+Company Parse Worker
+|:
+	Name
+	Inputs
+	Outputs
+	Line Number
+	Trees
+	Uses Stores
+:|
+
+New@Parse Worker(4,1)
+|:
+	out(0) <- [[[[[[Build["Parse Worker"]]Name <<[name(0)]]Inputs <<[inputs(1)]]Outputs <<[outputs(2)]]Line Number <<[line(3)]]Trees <<[New@List[]]]Uses Stores <<[New@List[]]
+:|
+
+Company Worker Node
+|:
+	Name
+	Params
+	Assignments
+	Blocks
+	Index
+:|
+
+New@Worker Node(2,1)
+|:
+	out(0) <- [[[[Build["Worker Node"]]Name <<[name(0)]]Params <<[params(1)]]Assignments <<[New@List[]]]Blocks <<[New@List[]]
+:|
+
+Add List Helper(6,3)
+|:
+	,nextworker,nextrefs <- [[list(0)]Index[key(3)]]Add to Worker[worker(1), program(2), parse worker(4), refs(5)]
+	|: nextlist <- [list(0)]Set[key(3), ~] :|
+	[list(0)]Next[key(3)]
+	|:
+		list(0),worker(1),refs(2) <- Add List Helper[nextlist, nextworker, program(2), ~, parse worker(4), nextrefs]
+	:||:
+		list(0) <- Val[nextlist]
+		worker(1) <- Val[nextworker]
+		refs(2) <- Val[nextrefs]
+	:|
+:|
+
+Add List to Worker(5,3)
+|:
+	[list(0)]First
+	|:
+		list(0),worker(1),refs(2) <- Add List Helper[list(0), worker(1), program(2), ~, parse worker(3), refs(4)]
+	:||:
+		list(0) <- list(0)
+		worker(1) <- worker(1)
+		refs(2) <- refs(4)
+	:|
+:|
+
+_Add Blocks to Worker(6,3)
+|:
+	block, next worker, nextrefs <- Add List to Worker[[blocks(0)]Index[key(4)], worker(1), program(2), parse worker(3), refs(5)]
+	next blocks <- [blocks(0)]Set[key(4), block]
+	[blocks(0)]Next[key(4)]
+	|:
+		blocks(0),worker(1),refs(2) <- _Add Blocks to Worker[next blocks, next worker, program(2), parseworker(3), ~, nextrefs]
+	:||:
+		blocks(0) <- Val[next blocks]
+		worker(1) <- Val[next worker]
+		refs(2) <- Val[nextrefs]
+	:|
+:|
+
+Add Blocks to Worker(5,3)
+|:
+	[blocks(0)]First
+	|:
+		blocks(0), worker(1), refs(2) <- _Add Blocks to Worker[blocks(0), worker(1), program(2), parse worker(3), ~, refs(4)]
+	:||:
+		blocks(0) <- blocks(0)
+		worker(1) <- worker(1)
+		refs(2) <- refs(4)
+	:|
+:|
+
+Add to Worker@Worker Node(5,3)
+|:
+	[program(2)]Find Worker[[node(0)]Name >>]
+	|:
+		after worker <- [worker(1)]Add Worker Call[~] |::|
+		|:
+			assignment refs <- Fold[[["Assignment Save Reference"]Set Input[3, parse worker(3)]]Set Input[4, ~], refs(4), [node(0)]Assignments >>]
+			[node(0)]Index <<[~]
+			|: 
+				params list, params worker, params refs <- Add List to Worker[[~]Params >>, after worker, program(2), parse worker(3), assignment refs]
+				block list, worker(1), refs(2) <- Add Blocks to Worker[[~]Blocks >>, params worker, program(2), parse worker(3), params refs]
+				node(0) <- [[~]Params <<[params list]]Blocks <<[block list]
+			:|
+		:|
+	:||:
+		Print[["Error: Could not find a worker named "]Append[[node(0)]Name >>]]
+	:|
+:|
+
+Add Multi Wire(5,1)
+|:
+	out(0) <- [worker(0)]Add Wire[[ref(1)]Index >>, [ref(1)]Output Number >>, end index(3), input num(4)]
+:|
+
+Add Param Wire(7,1)
+|:
+	param worker, start index, output num <- [param(1)]Add Wires[worker(0), blocks(4), parse worker(5), assignments(6)] |::|
+	|:
+		out(0) <- [param worker]Add Wire[start index, output num, end index(3), input num(2)]
+	:||::||:
+		out(0) <- Fold[[["Add Multi Wire"]Set Input[3, end index(3)]]Set Input[4, input num(2)], param worker, ~]
+	:|
+:|
+
+_Add Block Wire(6,1)
+|:
+	out(0) <- [node(1)]Add Wires[worker(0), blocks(3), parse worker(4), assignments(5)]
+:|
+
+Add Block Wire(7,1)
+|:
+	blocks <- [existing blocks(4)]Append[New@Output Reference[parent index(3), output num(2)]]
+	out(0) <- Fold[[[["_Add Block Wire"]Set Input[3, blocks]]Set Input[4, parse worker(5)]]Set Input[5, assignments(6)], worker(0), block nodes(1)]
+	//out(0) <- [param(1)]Add Wires[worker(0), blocks]
+:|
+
+Assignments Add Wires(5,1)
+|:
+	[[parse worker(3)]Outputs >>]Find[assignment(1)]
+	|:
+		,output index <- [worker(0)]Add Output[assignment(1), ~]
+		|:
+			worker(0) <- [~]Add Wire[start index(4), output num(2), output index, 0]
+		:|
+	:||:
+		//Ugly hack alert!
+		If[[asignment(1)]Contains["::"]]
+		|:
+			parts <- [assignment(1)]Split["::"]
+			,global index <- [worker(0)]Add Global Set[[parts]Index[0], [parts]Index[1]]
+			|:
+				worker(0) <- [~]Add Wire[start index(4), output num(2), global index, 0]
+			:|
+		:||:
+			worker(0) <- worker(0)
+		:|
+	:|
+:|
+
+Has Block@Worker Node(1,2)
+|:
+	out(0) <- Yes
+:|
+
+_Has Block Params(2,1)
+|:
+	param <- [param list(0)]Index[key(1)]
+	out(0) <- [param]Has Block |::|
+	|:
+		[param list(0)]Next[key(1)]
+		|:
+			out(0) <- _Has Block Params[param list(0), ~]
+		:||:
+			out(0) <- No
+		:|
+	:|
+	
+:|
+
+Has Block Params(1,1)
+|:
+	[param list(0)]First
+	|:
+		out(0) <- _Has Block Params[param list(0), ~]
+	:||:
+		out(0) <- No
+	:|
+:|
+
+Add Wires@Worker Node(5,4)
+|:
+	worker(0),index(1),num(2) <- Add Wires Worker or Field[node(0), worker(1), blocks(2), parse worker(3), assignments(4)]
+:|
+
+Add Wires Worker or Field(5,4)
+|:
+	Fold[[["Assignments Add Wires"]Set Input[3, parse worker(3)]]Set Input[4, [node(0)]Index >>], worker(1), [node(0)]Assignments >>]
+	|: Fold[[[[["Add Block Wire"]Set Input[3, [node(0)]Index >>]]Set Input[4, blocks(2)]]Set Input[5, parse worker(3)]]Set Input[6, assignments(4)], ~, [node(0)]Blocks >>]
+	|: params worker <- Fold[[[[["Add Param Wire"]Set Input[3, [node(0)]Index >>]]Set Input[4, blocks(2)]]Set Input[5, parse worker(3)]]Set Input[6, assignments(4)], ~, [node(0)]Params >>] :|:|
+	If[Has Block Params[[node(0)]Params >>]]
+	|:
+		worker(0) <- Val[params worker]
+	:||:
+		[blocks(2)]Peek
+		|:
+			worker(0) <- [params worker]Add Wire[[~]Index >>, [~]Output Number >>, [node(0)]Index >>, [0]-[1]]
+		:||:
+			worker(0) <- Val[params worker]
+		:|
+	:|
+	index(1) <- [node(0)]Index >>
+	num(2) <- 0
+:|
+
+Company Field Node
+|:
+	Name
+	Params
+	Assignments
+	Blocks
+	Index
+	Set?
+:|
+
+Has Block@Field Node(1,2)
+|:
+	has block(0) <- Yes
+:|
+
+New@Field Node(3,1)
+|:
+	out(0) <- [[[[[Build["Field Node"]]Name <<[name(0)]]Assignments <<[New@List[]]]Blocks <<[New@List[]]]Set? <<[set(2)]]Params <<[params(1)]
+:|
+
+Add to Worker@Field Node(5,3)
+|:
+	If[[node(0)]Set? >>]
+	|:
+		after worker,index <- [worker(1)]Add Object Set[[node(0)]Name >>]
+	:||:
+		after worker,index <- [worker(1)]Add Object Get[[node(0)]Name >>]
+	:|
+	index
+	|:
+		assignment refs <- Fold[[["Assignment Save Reference"]Set Input[3, parse worker(3)]]Set Input[4, ~], refs(4), [node(0)]Assignments >>]
+		[node(0)]Index <<[~]
+		|: 
+			params list, params worker, params refs <- Add List to Worker[[~]Params >>, after worker, program(2), parse worker(3), assignment refs]
+			block list, worker(1), refs(2) <- Add Blocks to Worker[[~]Blocks >>, params worker, program(2), parse worker(3), params refs]
+			node(0) <- [[~]Params <<[params list]]Blocks <<[block list]
+		:|
+	:|
+:|
+
+Add Wires@Field Node(5,4)
+|:
+	worker(0),index(1),num(2) <- Add Wires Worker or Field[node(0), worker(1), blocks(2), parse worker(3), assignments(4)]
+:|
+
+Company Named Pipe Node
+|:
+	Name
+	Assignments
+	Blocks
+	Index
+:|
+
+Has Block@Named Pipe Node(1,2)
+|:
+	If[[[node(0)]Index >>] < [0]]
+	|:
+		//~ should really be a parser parameter
+		If[[[node(0)]Name >>] = ["~"]]
+		|:
+			has block(0) <- Yes
+		:||:
+			no block(1) <- No
+		:|
+	:||:
+		has block(0) <- Yes
+	:|
+:|
+
+New@Named Pipe Node(1,1)
+|:
+	out(0) <- [[[Build["Named Pipe Node"]]Name <<[name(0)]]Assignments <<[New@List[]]]Blocks <<[New@List[]]
+:|
+
+Add to Worker@Named Pipe Node(5,3)
+|:
+	[[parse worker(3)]Inputs >>]Find[[node(0)]Name >>]
+	|:
+		after add <- [worker(1)]Add Input[[node(0)]Name >>, ~] |::|
+		|:
+			assign refs <- Fold[[["Assignment Save Reference"]Set Input[3, parse worker(3)]]Set Input[4, ~], refs(4), [node(0)]Assignments >>]
+			index node <- [node(0)]Index <<[~]
+		:|
+	:||:
+		after add <- worker(1)
+		index node <- [node(0)]Index <<[[0]-[1]]
+		//TODO: Handle assignments from a named pipe that isn't an input
+		assign refs <- refs(4)
+	:|
+	block list, worker(1), refs(2) <- Add Blocks to Worker[[node(0)]Blocks >>, after add, program(2), parse worker(3), assign refs]
+	node(0) <- [index node]Blocks <<[block list]
+:|
+
+Add Wires@Named Pipe Node(5,4)
+|:
+	reflist(3) <- [assignments(4)]Index[[node(0)]Name >>]
+	|: 
+		//TODO: Fix support for a named pipe with a block
+		worker(0) <- worker (1)
+	:||:
+		If[[[node(0)]Name >>] = ["~"]]
+		|:
+			wires worker <- worker(1)
+			[blocks(2)]Peek
+			|:
+				my index <- [~]Index >>
+				num(2) <- [~]Output Number >>
+			:||:
+				//TODO: Propagate an error rather than printing it out
+				Print["Error, block reference symbol (~) located outside of a block"]
+			:|
+		:||:
+			If[[[node(0)]Index >>] < [0]]
+			|:
+				Print[[[["Error, reference to named pipe "]Append[[node(0)]Name >>]]Append[" that was never assigned to in worker "]]Append[[parse worker(3)]Name >>]]
+			:||:
+				my index <- [node(0)]Index >>
+				num(2) <- 0
+				assignments worker <- Fold[[["Assignments Add Wires"]Set Input[3, parse worker(3)]]Set Input[4, [node(0)]Index >>], worker(1), [node(0)]Assignments >>]
+				[blocks(2)]Peek
+				|:
+					wires worker <- [assignments worker]Add Wire[[~]Index >>, [~]Output Number >>, [node(0)]Index >>, [0]-[1]]
+				:||:
+					wires worker <- Val[assignments worker]
+				:|
+			:|
+		:|
+	:|
+	index(1) <- my index
+	
+	worker(0) <- Fold[[[[["Add Block Wire"]Set Input[3, my index]]Set Input[4, blocks(2)]]Set Input[5, parse worker(3)]]Set Input[6, assignments(4)], wires worker, [node(0)]Blocks >>]
+:|
+
+Company Global Node
+|:
+	Store
+	Name
+	Assignments
+	Blocks
+	Index
+:|
+
+New@Global Node(2,1)
+|:
+	out(0) <- [[[[Build["Global Node"]]Store <<[store(0)]]Name <<[name(1)]]Assignments <<[New@List[]]]Blocks <<[New@List[]]
+:|
+
+Add to Worker@Global Node(5,3)
+|:
+	out worker(1) <- [worker(1)]Add Global Get[[node(0)]Store >>, [node(0)]Name >>] |::|
+	|:
+		refs(2) <- Fold[[["Assignment Save Reference"]Set Input[3, parse worker(3)]]Set Input[4, ~], refs(4), [node(0)]Assignments >>]
+		out node(0) <- [node(0)]Index <<[~]
+	:|
+	refs(2) <- refs(4)
+:|
+
+Add Wires@Global Node(5,4)
+|:
+	worker(0),index(1),num(2) <- Add Wires Literal or Global[node(0), worker(1), blocks(2), parse worker(3), assignments(4)]
+:|
+
+Has Block@Global Node(1,2)
+|:
+	out(0) <- Yes
+:|
+
+Company Literal Node
+|:
+	Value
+	Assignments
+	Blocks
+	Index
+:|
+
+Has Block@Literal Node(1,2)
+|:
+	out(0) <- Yes
+:|
+
+New@Literal Node(1,1)
+|:
+	out(0) <- [[[Build["Literal Node"]]Value <<[value(0)]]Assignments <<[New@List[]]]Blocks <<[New@List[]]
+:|
+
+Add to Worker@Literal Node(5,3)
+|:
+	out worker(1) <- [worker(1)]Add Constant[[node(0)]Value >>] |::|
+	|:
+		refs(2) <- Fold[[["Assignment Save Reference"]Set Input[3, parse worker(3)]]Set Input[4, ~], refs(4), [node(0)]Assignments >>]
+		out node(0) <- [node(0)]Index <<[~]
+	:|
+:|
+
+Add Wires@Literal Node(5,4)
+|:
+	worker(0),index(1),num(2) <- Add Wires Literal or Global[node(0), worker(1), blocks(2), parse worker(3), assignments(4)]
+:|
+
+Add Wires Literal or Global(5,4)
+|:
+	assignments worker <- Fold[[["Assignments Add Wires"]Set Input[3, parse worker(3)]]Set Input[4, [node(0)]Index >>], worker(1), [node(0)]Assignments >>]
+	[blocks(2)]Peek
+	|:
+		worker(0) <- [assignments worker]Add Wire[[~]Index >>, [~]Output Number>>, [node(0)]Index >>, [0]-[1]]
+	:||:
+		worker(0) <- Val[assignments worker]
+	:|
+	index(1) <- [node(0)]Index >>
+	num(2) <- 0
+:|
+
+Company Block Node
+|:
+	Number
+:|
+
+Company Parse Error
+|:
+	Type
+	Text
+	Line Number
+:|
+
+New@Parse Error(3,1)
+|:
+	out(0) <- [[[Build["Parse Error"]]Type <<[type(0)]]Text <<[text(1)]]Line Number <<[number(2)]
+:|
+
+Filter Empty(1,1)
+|:
+	If[[[string(0)]Length] > [0]]
+	|:
+		out(0) <- Yes
+	:||:
+		out(0) <- No
+	:|
+:|
+
+Company Blueprint Field
+|:
+	Name
+	Type
+:|
+
+New@Blueprint Field(2,1)
+|:
+	out(0) <- [[Build["Blueprint Field"]]Name <<[name(0)]]Type <<[type(1)]
+:|
+
+Process Blueprint Field(3,1)
+|:
+	parts <- [field(1)]Split[delim(2)]
+	If[[[parts]Length] > [1]]
+	|:
+		out(0) <- [list(0)]Append[New@Blueprint Field[[parts]Index[1], [parts]Index[0]]]
+	:||:
+		out(0) <- [list(0)]Append[New@Blueprint Field[[parts]Index[0], "Any Type"]]
+	:|
+:|
+
+Block Comment(4,1)
+|:
+	If[[block count(3)] > [0]]
+	|:
+		after, before <- [string(0)]Get DString[[[New@List[]]Append[begin comment(1)]]Append[end comment(2)]] |::| |::|
+		|:
+			If[[~] = [begin comment(1)]]
+			|:
+				out(0) <- Block Comment[after, begin comment(1), end comment(2), [block count(3)]+[1]]
+			:||:
+				out(0) <- Block Comment[after, begin comment(1), end comment(2), [block count(3)]-[1]]
+			:|
+		:||:
+			//No match
+			out(0) <- ""
+		:|
+	:||:
+		out(0) <- string(0)
+	:|
+:|
+
+Line Comment(1,1)
+|:
+	[string(0)]Get DString["\n"]
+	|:
+		out(0) <- ["\n"]Append[~]
+	:| |::| |::| |:
+		out(0) <- ""
+	:|
+:|
+
+_Get Comment DString(6,4)
+|:
+	after,before,delim,nomatch(3) <- [string(0)]Get DString[delims(1)]
+	|:
+		If[[delim] = [line comment(2)]]
+		|:
+			after comment <- Line Comment[after]
+		:||:
+			If[[delim] = [begin comment(3)]]
+			|:
+				after comment <- Block Comment[after, begin comment(3), end comment(4), 1]	
+			:||:
+				rest(0) <- Val[after]
+				before(1) <- [prev before(5)]Append[before]
+				delim(2) <- Val[delim]
+			:|
+		:|
+	:| |::| |::| |:
+		before(1) <- [prev before(5)]Append[before]
+	:|
+	
+	after comment
+	|:
+		rest(0),more before,delim(2),nomatch(3) <- _Get Comment DString[~, delims(1), line comment(2), begin comment(3), end comment(4), prev before(5)]
+		before(1) <- [before]Append[more before]
+	:|
+		
+:|
+
+Get Comment DString(3,4)
+|:
+	line comment <- [params(2)]Line Comment >>
+	begin comment <- [params(2)]Comment Begin >>
+	end comment <- [params(2)]Comment End >>
+	all delims <- [[[delims(1)]As List]Append[begin comment]]Append[line comment]
+	rest(0), before(1), delim(2), not found(3) <- _Get Comment DString[string(0), delims(1), line comment, begin comment, end comment, ""]
+:|
+
+Comment Left Trim(3,1)
+|:
+	line comment <- [params(2)]Line Comment >>
+	
+	end comment <- [params(2)]Comment End >>
+	trimmed <- Left Trim[string(0), trim chars(1)]
+	If[[trimmed]Starts With[line comment]]
+	|:
+		,after delim <- [trimmed]Slice[[line comment]Length]
+		out(0) <- Comment Left Trim[Line Comment[after delim], trim chars(1), params(2)]
+	:||:
+		begin comment <- [params(2)]Comment Begin >>
+		If[[trimmed]Starts With[begin comment]]
+		|:
+			,after delim <- [trimmed]Slice[[line comment]Length]
+			out(0) <- Comment Left Trim[Block Comment[after delim, begin comment, end comment, 1], trim chars(1), params(2)]
+		:||:
+			out(0) <- Val[trimmed]
+		:|
+	:|
+:|
+
+Blueprint(4,1)
+|:
+	,whitespace name <- [string(0)]Get Comment DString[[params(1)]Block Begin >>, params(1)]
+	|:	
+		,no blueprint <- [whitespace name]Slice[ [[params(1)]Blueprint >>]Length ]
+		name <- Trim[no blueprint, "\r\n\t "]
+		name lines <- 0//[Count Substring[left, "\n"]] + [Count Substring[right, "\n"]]
+		,body <- [~]Get Comment DString[ [params(1)]Block End >>, params(1)]
+		|:
+			body lines <- [body]Split["\n"]
+			more lines <- [[[body lines]Length] - [1]] + [name lines]
+			fields <- Fold[["Process Blueprint Field"]Set Input[2, [params(1)]Blueprint Type Delim >>], New@List[], Filter[Map[body lines, ["Trim"]Set Input[1,"\n\r\t "]], "Filter Empty"]]
+			new tree <- [tree(2)]Blueprints << [ [[tree(2)]Blueprints >>]Set[name, New@Blueprint Definition[name, fields]] ]
+			out(0) <- Null[~, params(1), new tree, [lines(3)] + [more lines]]
+		:| |::| |:
+			out(0) <- [tree(2)]Errors <<[ [[tree(2)]Errors >>]Append[New@Parse Error["Error",[["Blueprint is missing an block close symbol \""]Append[[params(1)]Block End >>]]Append["\""], lines(3)]] ]
+		:|
+		
+	:| |::| |:
+		out(0) <- [tree(2)]Errors <<[ [[tree(2)]Errors >>]Append[New@Parse Error["Error",[["Blueprint is missing an block open symbol \""]Append[[params(1)]Block Begin >>]]Append["\""], lines(3)]] ]
+	:|
+:|
+
+Parse Import(4,1)
+|:
+	[line]Slice[ [[params(1)]Import >>]Length ] |::|
+	|:
+		filename <- Trim[~, " \n\r\t"]
+	:|
+	new tree <- [tree(2)]Imports <<[ [[tree(2)]Imports >>]Set[filename, Yes] ]
+	,line <- [string(0)]Get Comment DString["\n", params(1)]
+	|:
+		out(0) <- Null[~, params(1), new tree, [lines(3)] + [1]]
+	:| |::| |:
+		out(0) <- Val[new tree]
+	:|
+:|
+
+Get Expression Blocks(3,2)
+|:
+	check block <- Comment Left Trim[string(0), "\n\r\t ", params(1)]
+	If[[check block]Starts With[[params(1)]Block Begin >>]]
+	|:
+		,begin block <- [check block]Slice[[[params(1)]Block Begin >>]Length]
+		trees, after block <- Worker Body[begin block, params(1), New@List[]]
+		blocks(0), after(1) <- Get Expression Blocks[after block, params(1), [blocks(2)]Append[trees]]
+	:||:
+		If[[check block]Starts With[[params(1)]Empty Block >>]]
+		|:
+			blocks(0) <- blocks(2)
+			,after(1) <- [check block]Slice[[[params(1)]Empty Block >>]Length]
+		:||:
+			blocks(0) <- blocks(2)
+			after(1) <- Val[check block]
+		:|
+	:|
+:|
+
+Parse Escape(2,2)
+|:
+	code,rest <- [string(0)]Slice[1]
+	If[[code] = [[params(1)]Hex Escape >>]]
+	|:
+		hex,after(1) <- [rest]Slice[2]
+		char(0) <- [""]Put Byte[From Hex@Whole Number[hex]]
+	:||:
+		after(1) <- Val[rest]
+		char(0) <- [[params(1)]Escape Map >>]Index[code] |::|
+		|:
+			char(0) <- Val[code]
+		:|
+	:|
+:|
+
+Parse String(3,2)
+|:
+	delims <- [[New@List[]]Append[[params(1)]String End >>]]Append[[params(1)]String Escape >>]
+	after, before, delim <- [string(0)]Get Comment DString[delims, params(1)]
+	|:
+		If[[delim] = [[params(1)]String End >>]]
+		|:
+			value(0) <- [current(2)]Append[before]
+			after(1) <- Val[after]
+		:||:
+			char,after escape <- Parse Escape[after, params(1)]
+			value(0),after(1) <- Parse String[after escape, params(1), [[current(2)]Append[before]]Append[char]]
+		:|
+	:|
+:|
+
+Parse List(3,2)
+|:
+	trimmed <- Comment Left Trim[string(0), "\r\n\t ", params(1)]
+	If[[trimmed]Starts With[[params(1)]List End >>]]
+	|:
+		value(0) <- list(2)
+		,after(1) <- [trimmed]Slice[[[params(1)]List End >>]Length]
+	:||:
+		If[[trimmed]Starts With[[params(1)]List Delim >>]]
+		|:
+			,el string <- [trimmed]Slice[[[params(1)]List Delim >>]Length]
+		:||:
+			el string <- Val[trimmed]
+		:|
+		element,after el <- Named Pipe or Literal[el string, params(1)]
+		value(0),after(1) <- Parse List[after el, params(1), [list(2)]Append[[element]Get Value]]
+	:|
+:|
+
+Get Value@Literal Node(1,1)
+|:
+	out(0) <- [node(0)]Value >>
+:|
+
+Get Value@Named Pipe Node(1,1)
+|:
+	out(0) <- node(0)
+:|
+
+Parse Number(2,2)
+|:
+	delims <- [[[[{" ","\t","\n","\r"}]Append[[params(1)]List Delim >>]]Append[[params(1)]Block Begin >>]]Append[[params(1)]Arg End >>]]Append[[params(1)]List End >>]
+	after delim,valstring <- [string(0)]Get Comment DString[delims, params(1)] |::| |::|
+	|:
+		after(1) <- [~]Append[after delim]
+	:||:
+		after(1) <- ""
+	:|
+	first two,rest <- [valstring]Slice[2]
+	If[[first two] = ["0x"]]
+	|:
+		value(0) <- From Hex@Whole Number[rest]
+	:||:
+		If[[valstring]Contains["."]]
+		|:
+			value(0) <- <String@Real Number[valstring]
+		:||:
+			value(0) <- <String@Whole Number[valstring]
+		:|
+	:|
+:|
+
+Named Pipe or Literal(2,2)
+|:
+	name <- Comment Left Trim[string(0), "\n\r\t ", params(1)]
+	If[[name]Starts With[[params(1)]String Begin >>]]
+	|:
+		,string begin <- [name]Slice[[[params(1)]String Begin >>]Length]
+		value,after(1) <- Parse String[string begin, params(1), ""]
+	:||:
+		If[[name]Starts With[[params(1)]List Begin >>]]
+		|:
+			,list start <- [name]Slice[[[params(1)]List Begin >>]Length]
+			value,after(1) <- Parse List[list start, params(1), New@List[]]
+		:||:
+			If[[[name]Slice[1]]In["-0123456789"]]
+			|:
+				value,after(1) <- Parse Number[name, params(1)]
+			:||:
+				delims <- [[[[[[{"\n"}]Append[[params(1)]Block Begin >>]]Append[[params(1)]Block End >>]]Append[[params(1)]Empty Block >>]]Append[[params(1)]Arg End >>]]Append[[params(1)]List Delim >>]]Append[[params(1)]List End >>]
+				,before,delim <- [name]Get Comment DString[delims, params(1)]
+				|:
+					after(1) <- [delim]Append[~]
+				:| |::| |::| |: 
+					after(1) <- ""
+				:|
+				If[[before] = ["Yes"]]
+				|:
+					yesno <- Yes
+				:||:
+					If[[before] = ["No"]]
+					|:
+						yesno <- No
+					:||:
+						If[[before] = [""]]
+						|:
+							Print[[["Found "]Append[delim]]Append[" where a named pipe or literal was expected"]]
+						:||:
+							If[[before]Contains[[params(1)]Global Separator >>]]
+							|:
+								parts <- [before]Split[[params(1)]Global Separator >>]
+								out(0) <- New@Global Node[Right Trim[[parts]Index[0],"\r\n\t "], Trim[[parts]Index[1], "\r\n\t "]]
+							:||:
+								out(0) <- New@Named Pipe Node[Right Trim[before,"\r\n\t "]]
+							:|
+						:|
+					:|
+				:|
+				out(0) <- New@Literal Node[yesno]
+			:|
+		:|
+	:|
+	out(0) <- New@Literal Node[value]
+:|
+
+Parse Arguments(3,2)
+|:
+	args <- Comment Left Trim[string(0), "\r\n\t ", params(1)]
+	If[[args]Starts With[[params(1)]List Delim >>]]
+	|:
+		[args]Slice[[[params(1)]List Delim >>]Length] |::| 
+		|:
+			final args <- Comment Left Trim[~, "\r\n\t ", params(1)]
+		:|
+	:||:
+		If[[args]Starts With[[params(1)]Arg End >>]]
+		|:
+			args(0) <- arglist(2)
+			,after(1) <- [args]Slice[[[params(1)]Arg End >>]Length]
+		:||:
+			final args <- Val[args]
+		:|
+	:|
+	arg, after arg <- Parse Expression[final args, params(1)]
+	args(0), after(1) <- Parse Arguments[after arg, params(1), [arglist(2)]Append[arg]]
+:|
+
+Worker or Field(3,1)
+|:
+	get field <- [params(2)]Get Field >>
+	If[[name(0)]Ends With[get field]]
+	|:
+		field <- Right Trim[[name(0)]Slice[[[name(0)]Length] - [[get field]Length]], "\n\r\t "]
+		out(0) <- New@Field Node[field, args(1), No]
+	:||:
+		set field <- [params(2)]Set Field >>
+		If[[name(0)]Ends With[set field]]
+		|:
+			field <- Right Trim[[name(0)]Slice[[[name(0)]Length] - [[set field]Length]], "\n\r\t "]
+			out(0) <- New@Field Node[field, args(1), Yes]
+		:||:
+			out(0) <- New@Worker Node[name(0), args(1)]
+		:|
+	:|
+:|
+
+Prefix(4,2)
+|:	
+	//Parse argument list
+	more args,after(1) <- Parse Arguments[string(0), params(1), existing args(3)]
+	expression(0) <- Worker or Field[name(2), more args, params(1)]
+:|
+
+Postfix or Infix(2,2)
+|:
+	args, after args <- Parse Arguments[string(0), params(1), New@List[]]
+	delims <- [[[[[{"\n"}]Append[[params(1)]Arg Begin >>]]Append[[params(1)]Empty Block >>]]Append[[params(1)]Block Begin >>]]Append[[params(1)]Arg End >>]]Append[[params(1)]List Delim >>]
+	after,before,delim <- [after args]Get Comment DString[delims, params(1)]
+	|:
+		If[[delim] = [[params(1)]Arg Begin >>]]
+		|:
+			expression(0), after(1) <- Prefix[after, params(1), Trim[before,"\r\n\t "], args]
+		:||:
+			If[[delim] = [[params(1)]Empty Block >>]]
+			|:
+				after expression(1) <- Val[after]
+			:||:
+				,after expression(1) <- [after args]Slice[[before]Length]
+			:|
+			expression(0) <- Worker or Field[Trim[before,"\r\n\t "], args, params(1)]
+		:|
+	:|
+:|
+
+Parse Expression(2,2)
+|:
+	delims <- [[[[[[[{"\n"}]Append[[params(1)]Arg Begin >>]]Append[[params(1)]Arg End >>]]Append[[params(1)]Assign >>]]Append["\n"]]Append[[params(1)]Empty Block >>]]Append[[params(1)]Block End >>]]Append[[params(1)]String Begin >>]
+	after, before, delim <- [trimmed(0)]Get Comment DString[delims, params(1)]
+	|:
+		//If we find an arg begin token, we have a worker expression
+		If[[delim] = [[params(1)]Arg Begin >>]]
+		|:
+			maybe name <- Right Trim[before, "\r\t "]
+			//Prefix expressions will have the worker name before the first arg begin token
+			If[[maybe name] = [""]]
+			|:
+				expression, after expression <- Postfix or Infix[after, params(1)]
+			:||:
+				If[[maybe name]Contains[[params(1)]List Delim >>]]
+				|:
+					after expression <- [after literal]Append[[delim]Append[after]]
+					expression, after literal <- Named Pipe or Literal[Right Trim[before, "\r\n\t "], params(1)]
+				:||:
+					expression, after expression <- Prefix[after, params(1), maybe name, New@List[]]
+				:|
+			:|
+		:||:
+			If[[delim] = [[params(1)]Assign >>]]
+			|:
+				//Expressions starting with an assignment can be prefix, postfix or infix
+				//or they can be a simple literal or named pipe
+				assignments <- Map[[before]Split[[params(1)]List Delim >>], ["Trim"]Set Input[1,"\n\r\t "]]
+				,after blocks(1) <- Parse Expression[Comment Left Trim[after, " \n\r\t", params(1)], params(1)]
+				|:
+					final expression(0) <- [~]Assignments <<[assignments]
+				:|
+			:||:
+				//If[[delim] = [[params(1)]String Begin >>]]
+				//|:
+				//	If[[Trim[before, "\r\n\t "]] = [""]]
+				//	|:
+				//		expression, after expression <- Named Pipe or Literal[[delim]Append[after], params(1)]
+				//	:||:
+				//		after expression <- [after literal]Append[[delim]Append[after]]
+				//		expression, after literal <- Named Pipe or Literal[Right Trim[before, "\r\n\t "], params(1)]
+				//	:|
+				//:||:
+				//	after expression <- [after literal]Append[[delim]Append[after]]
+				//	expression, after literal <- Named Pipe or Literal[Right Trim[before, "\r\n\t "], params(1)]
+				//:|
+				expression, after expression <- Named Pipe or Literal[trimmed(0), params(1)]
+			:|
+		:|
+		//Any expression can be followed by one or more blocks mapping the inputs of other expressions
+		//to the outputs of the current one
+		blocks,after blocks(1) <- Get Expression Blocks[after expression, params(1), New@List[]]
+		final expression(0) <- [expression]Blocks <<[blocks]
+	:|
+:|
+
+Worker Body(3,2)
+|:
+	trimmed <- Comment Left Trim[string(0), "\n\r\t ", params(1)]
+	If[[trimmed]Starts With[[params(1)]Block End >>]]
+	|:
+		//We're done with this block, return
+		,after end(1) <- [trimmed]Slice[[[params(1)]Block End >>]Length]
+		trees(0) <- trees(2)
+	:||:
+		expression, after expression <- Parse Expression[trimmed, params(1)]
+		trees(0),after end(1) <- Worker Body[after expression, params(1), [trees(2)]Append[expression]]
+	:|
+:|
+
+Process Modifiers(3,1)
+|:
+	//Eventually this will need to be more sophisticated to handle more modifiers
+	trimmed <- Comment Left Trim[modifiers(2), "\n\r\t ", params(1)]
+	If[[trimmed]Starts With[[params(1)]Uses >>]]
+	|:
+		,after uses <- [trimmed]Slice[[[params(1)]Uses >>]Length]
+		,stores string <- [after uses]Get Comment DString["\n", params(1)]
+		out(0) <- [worker(0)]Uses Stores <<[Map[[stores string]Split[[params(1)]List Delim >>], ["Trim"]Set Input[1, "\r\n\t "]]]
+	:||:
+		out(0) <- worker(0)
+	:|
+:|
+
+Worker Name(4,1)
+|:
+	,whitespace name <- [string(0)]Get Comment DString[[params(1)]Arg Begin >>, params(1)]
+	|:
+		worker name <- Trim[whitespace name, "\n\r\t "]
+		in out <- [params(1)]In Out Delim >>
+		arg end <- [params(1)]Arg End >>
+		delims <- [[New@List[]]Append[in out]]Append[arg end]
+		after <- [~]Get Comment DString[delims, params(1)] |::| 
+		|:
+			arglist <- Trim[~,"\r\n\t "]
+		:||:
+			//check if there is an in/out separator
+			//if it isn't present, everything in the arglist is an input
+			If[[~] = [in out]]
+			|:
+				after arglist <- [after]Get Comment DString[arg end, params(1)] |::|
+				|:
+					output string <- Trim[~,"\n\r\t "]
+				:|
+			:||:
+				after arglist <- Val[after]
+				output string <- ""
+			:|
+			inputs <- Map[[arglist]Split[[params(1)]List Delim >>], ["Trim"]Set Input[1,"\n\r\t "]]
+			outputs <- Map[[output string]Split[[params(1)]List Delim >>], ["Trim"]Set Input[1,"\n\r\t "]]
+
+			New@Parse Worker[worker name, inputs, outputs, 0]
+			|:
+				body text, modifiers <- [after arglist]Get Comment DString[[params(1)]Block Begin >>, params(1)]
+				modified <- Process Modifiers[~, params(1), modifiers]
+				expression trees, after body <- Worker Body[body text, params(1), New@List[]]
+				worker <- [modified]Trees <<[expression trees]
+				new worker dict <- [[tree(2)]Workers >>]Set[worker name, worker]
+				out(0) <- Null[after body, params(1), [tree(2)]Workers <<[new worker dict], 0]
+			:|
+		:|
+	:||::||::||:
+		out(0) <- tree(2)
+	:|
+:|
+
+Null(4,1)
+|:
+	trimmed <- Comment Left Trim[string(0), " \n\r\t", params(1)]
+	current line <- 0//[lines(3)] + [Count Substring[whitespace, "\n"]]
+	If[[trimmed]Starts With[ [params(1)]Blueprint >> ]]
+	|:
+		out(0) <- Blueprint[trimmed, params(1), tree(2), current line]
+	:||:
+		If[[trimmed]Starts With[ [params(1)]Import >> ]]
+		|:
+			out(0) <- Parse Import[trimmed, params(1), tree(2), current line]
+		:||:
+			out(0) <- Worker Name[trimmed, params(1), tree(2), current line]
+		:|
+	:|
+:|
+
+Add Workers(3,1)
+|:
+	prog,worker <- [program(2)]New Worker[name(1)]
+	[worker]Set IO Counts[ [[[worker(0)]Index[name(1)]]Inputs >>]Length, [[[worker(0)]Index[name(1)]]Outputs >>]Length]
+	[workers(0)]Next[name(1)]
+	|:
+		out(0) <- Add Workers[workers(0), ~, prog]
+	:||:
+		out(0) <- Val[prog]
+	:|
+:|
+
+Add Wires Helper(5,1)
+|:
+	worker(0) <- [node(1)]Add Wires[worker(0), New@List[], parse worker(3), assignments(4)]
+:|
+
+Add Contents(3,2)
+|:
+	worker <- [[program(2)]Find Worker[name(1)]]Uses[[parse worker(0)]Uses Stores >>]
+	trees, contents worker, refs <- Add List to Worker[[parse worker(0)]Trees >>, worker, program(2), parse worker(0), New@Dictionary[]]
+	Fold[[["Add Wires Helper"]Set Input[3, parse worker(0)]]Set Input[4, refs], contents worker, trees]
+	out(0) <- [parse worker(0)]Trees <<[trees]
+	key(1) <- name(1)
+:|
+
+Add Blueprint Field(3,1)
+|:
+	out(0) <- [blueprint(0)]Add Field[[field(1)]Name >>, [field(1)]Type >>]
+:|
+
+Add Blueprint(2,1)
+|:
+	out(0) <- [prog(0)]New Blueprint[[def(1)]Name >>] |::|
+	|:	
+		Fold["Add Blueprint Field", ~, [def(1)]Fields >>]
+	:|
+:|
+
+_Tree to Program(2,1)
+|:
+	after blueprint <- Fold["Add Blueprint", program(1), [parse tree(0)]Blueprints >>]
+	[[parse tree(0)]Workers >>]First
+	|:
+		prog <- Add Workers[[parse tree(0)]Workers >>, ~, after blueprint]
+	:|
+	Key Value Map[[parse tree(0)]Workers >>, ["Add Contents"]Set Input[2, prog]]
+	out(0) <- prog
+:|
+
+Tree to Program(1,1)
+|:
+	out(0) <- _Tree to Program[parse tree(0), [New@Program[]]Add Builtins]
+:|
+
+Needs Imports(3,1)
+|:
+	If[not imported?(1)]
+	|:
+		out(0) <- [needs import(0)]Append[name(2)]
+	:||:
+		out(0) <- needs import(0)
+	:|
+:|
+
+Do Import(4,1)
+|:
+	file <- <String@File[file name(1)]
+	,text <- [file]Get FString[[file]Length]
+	after import <- Null[text, params(3), tree(0), 0]
+	out(0) <- [after import]Imports <<[ [[after import]Imports >>]Set[file name(1), No] ]
+:|
+
+Process Imports(2,1)
+|:
+	needs import <- Fold["Needs Imports", New@List[], [parse tree(0)]Imports >>]
+	If[[[needs import]Length] > [0]]
+	|:
+		import tree <- Fold[["Do Import"]Set Input[3, params(1)], parse tree(0), needs import]
+		out(0) <- Process Imports[import tree, params(1)]
+	:||:
+		out(0) <- parse tree(0)
+	:|
+:|
+
+_Init Used Store(2,1)
+|:
+	[dict(0)]Index[store name(1)]
+	|:
+		out(0) <- dict(0)
+	:||:
+		Init Store[store name(1)]
+		out(0) <- [dict(0)]Set[store name(1), Yes]
+	:|
+:|
+
+_Init Used Stores(2,1)
+|:
+	out(0) <- Fold["_Init Used Store", dict(0), [worker(1)]Uses Stores >>]
+:|
+
+Init Used Stores(1,1)
+|:
+	out(0) <- Fold["_Init Used Stores", existing stores(1), [parse tree(0)]Workers >>]
+:|
+
+Until End(1,1)
+|:
+	line <- Get Input[]
+	If[[line] = ["End"]]
+	|:
+		out(0) <- [text(0)]Append["\n"]
+	:||:
+		out(0) <- Until End[[[text(0)]Append["\n"]]Append[line]]
+	:|
+:|
+
+_REPL(3,0)
+|:
+	line <- Get Input[]
+	If[[line] = ["Begin"]]
+	|:
+		text <- Until End[""]
+		Null[text, params(0), New@Parse Program[], 0]
+		|:
+			define tree <- Process Imports[~, params(0)]
+			Init Used Stores[define tree, stores(2)]
+			|: _REPL[params(0), _Tree to Program[define tree, prog(1)], ~] :|
+		:|
+	:||:
+		If[[line]Starts With[[params(0)]Import >>]]
+		|:
+			Parse Import[[line]Append["\n"], params(0), New@Parse Program[], 0]
+			|:
+				import tree <- Process Imports[~, params(0)]
+				Init Used Stores[import tree, stores(2)]
+				|: _REPL[params(0), _Tree to Program[import tree, prog(1)], ~] :|
+			:|
+		:||:
+			trees <- Worker Body[[line]Append["}"], params(0), New@List[]]
+			tree <- [New@Worker Node["Val", [New@List[]]Append[[trees]Index[0]]]]Assignments <<[{"__out"}]
+			this stores <- [[tree]Gather Stores[params(0), New@Dictionary[]]]Keys
+			next stores <- Fold["_Init Used Store", stores(2), this stores]
+			|:
+			pworker <- [[New@Parse Worker["__Eval", New@List[], {"__out"}, 0]]Trees <<[[New@List[]]Append[tree]]]Uses Stores <<[this stores]
+			:|
+			[[prog(1)]Find Worker["__Eval"]]Clear
+			|: Add Contents[pworker, "__Eval", prog(1)]
+			|: Pretty Print[[[[prog(1)]Find Worker["__Eval"]]Do[New@List[]]]Index[0], ""]
+			|: _REPL[params(0), prog(1), next stores] :| :| :|
+		:|
+	:|
+:|
+
+REPL(1,0)
+|:
+	Print["Rhope Alpha 2\nCopyright 2008 by Michael Pavone\nEntering interactive mode\n"]
+	prog <- Tree to Program[Null["Val[in:out]\n{\n out <- in\n}\n__Eval[:__out]\n{\n}\n", params(0), New@Parse Program[], 0]]
+	_REPL[params(0), prog, New@Dictionary[]]
+:|
+
+Add If Store(3,1)
+|:
+	If[[name(1)]Contains[[params(2)]Global Separator >>]]
+	|:
+		parts <- [name(1)]Split[[params(2)]Global Separator >>]
+		out(0) <- [stores(0)]Set[[parts]Index[0], Yes]
+	:||:
+		out(0) <- stores(0)
+	:|
+:|
+
+Param Gather Stores(3,1)
+|:
+	out(0) <- [node(1)]Gather Stores[params(2), stores(0)]
+:|
+
+Gather Stores@Named Pipe Node(3,1)
+|:
+	out(0) <- Fold[["Add If Store"]Set Input[2, params(1)], stores(2), [node(0)]Assignments >>]
+:|
+
+Gather Stores@Global Node(3,1)
+|:
+	out(0) <- [stores(2)]Set[[node(0)]Store >>, Yes]
+:|
+
+Gather Stores@Worker Node(3,1)
+|:
+	//TODO: Handle blocks
+	store list <- Fold[["Param Gather Stores"]Set Input[2, params(1)], stores(2), [node(0)]Params >>]
+	out(0) <- Fold[["Add If Store"]Set Input[2, params(1)], store list, [node(0)]Assignments >>]
+:|
+
+Gather Stores@Field Node(3,1)
+|:
+	//TODO: Handle blocks
+	store list <- Fold[["Param Gather Stores"]Set Input[2, params(1)], stores(2), [node(0)]Params >>]
+	out(0) <- Fold[["Add If Store"]Set Input[2, params(1)], store list, [node(0)]Assignments >>]
+:|
+
+Gather Stores@Literal Node(3,1)
+|:
+	out(0) <- Fold[["Add If Store"]Set Input[2, params(1)], stores(2), [node(0)]Assignments >>]
+:|
+
+
+Main(1,0)
+|:
+	
+	[args(0)]Index[1]
+	|:
+		file <- <String@File[~]
+		,text <- [file]Get FString[[file]Length]
+		params <- New@Parser[]
+		Null[text, params, New@Parse Program[], 0]
+		|:
+			tree <- Process Imports[~, params]
+			Init Used Stores[tree, New@Dictionary[]]
+			|: [Tree to Program[tree]]Run[[args(0)]Tail[1]] :|
+		:|
+	:||:
+		REPL[New@Parser[]]
+	:|
+:|
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/readme.txt	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,93 @@
+Rhope Alpha 2 Readme
+
+Usage
+-----
+
+To invoke the Rhope interpreter in interactive mode simply type rhope or ./rhope at the command prompt in the appropriate directory
+
+To run a program, type rhope program.rhope. Files ending in a .rhope extension will be processed using the new parser. Files ending in a .vistxt extension will be processed using the old parser. (Note that on Windows, rhope.exe is compiled without GUI functionality and is a console mode program, rhope_gui.exe is compiled with GUI functionality and is a window mode program)
+
+The DS port always tries to run program.vistxt. Two binaries are provided, rhope.gnm.nds (patched for the Datel Games 'n' Music device) and rhope.nds (unpatched). If you aren't using the Datel device, you need to patch rhope.nds using dlditool for your device (or use an autopatching launcher).
+
+Example Programs
+----------------
+
+hello.rhope			The classic "Hello World!" program in Rhope
+fib.rhope			Naive recursive fibonacci
+calc.rhope			A simple 2 function calculator using the built-in GUI library (only works on Windows and Syllable)
+basicweb.rhope			Serves static files over HTTP using the included webserver library
+said.rhope			A simple example of using the included web framework (implements Paul Graham's Arc challenge)
+pair.rhope			Shows how to define a new object
+program.vistxt (DS only)	A simple demo for the DS port. Displays some graphics using a tile layer and a sprite.
+
+
+Included Libraries
+------------------
+
+extendlib.rhope			A number of utility workers written in Rhope
+webserver.rhope			A very basic (and incomplete) library for serving data over HTTP
+framework.rhope			A basic Web framework (uses webserver.rhope)
+dsvideo.vistxt (DS only)	Some utilities for interacting with the DS video hardware
+
+Other Files
+-----------
+
+parser.vistxt			The new parser written in Rhope
+extendlib.vistxt		Version of extendlib using the old syntax (needed for the parser)
+webserver.vistxt		Version of webserver library using the old syntax
+framework.vistxt		Version of the web framework using the old syntax
+
+Changes since Alpha 1
+---------------------
+
+ - Parser rewritten in Rhope
+ - The new parser implements an improved version of the syntax (no more |: and :| and no more positional arguments)
+ - New parser supports negative number literals and numbers expressed in hex (e.g. 0x42)
+ - Programs using the new parser no longer have to manually initialize global stores using Init Store[]
+ - Added a primitive interactive mode to the interpretter
+ - The interpretter now supports tail call optimization
+ - Get DString@String was implemented in the core interpretter and removed from extendlib for performance
+ - Added basic support for checkboxes and dropdowns in the Syllable port
+ - Added a "Blueprint" object that allows inspection and modification of object definitions
+ - Added a number of methods to the Worker object for constructing new workers to support the new parser
+ - Made a basic port to the Nintendo DS
+ - Fixed a bug that caused iteration over Dictionary objects to sometimes skip entries
+ - Fixed a bug that caused Get DString@File to return incorrect data
+ - Fixed a number of memory leaks
+ - Fixed a bug in the argument checking code that caused a crash when Rhope was invoked with no arguments
+ - Probably fixed other bugs that I've forgotten
+
+Building and Porting
+--------------------
+
+Generally speaking you just need to type make -f <makefile for your platform> to build Rhope or on Windows nmake /f <appropriate makefile>. On Syllable you can just type make with no arguments. The DS port is a bit more work. You need to copy the appropriate source files into a copy of the arm9 template from devkitPro and add a few defines to the CFLAGS in the default makefile (namely COMPILE_THREADS=0, NO_NET, CONSOLE and NINTENDO_DS).
+
+Rhope is fairly portable. makefile.linux should work without modification for any platform with pthreads, BSD sockets and GCC. If you define COMPILE_THREADS=0 then Rhope should compile on platforms without pthreads and if you define NO_NET it should compile on platforms without BSD sockets. 
+
+Copying
+-------
+
+Rhope is released under a BSD-style license. See copying.txt for the full text of the license.
+
+Notes
+-----
+
+The new parser is rather slow. This is particularly noticeable when running programs that use extendlib or the web framework. The new parser is also somewhat light in the error handling department. These issues will be addressed with time.
+
+The current transaction model isn't sufficient for all tasks. Future releases will add options for handling transactions to cover a wider range of uses.
+
+Known Issues
+------------
+
+ - Dictionary objects can't have an empty string as a key
+ - Can't use the -t switch in interactive mode
+ - Statements of the form foo <- bar don't work unless either bar is a parameter of the worker or foo is an output with the new parser
+ - statements of the form foo { ... do something ... } don't work with the new parser
+ - The interpreter will crash if you try to run a program that doesn't define Main
+ - DS port freezes after a while (possibly runs out of memory?)
+
+Contact
+-------
+
+Questions? Comments? Bugs? Flames? My email address is: pavone@retrodev.com
+You can also join the Rhope mailing list at http://groups.google.com/group/rhope
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/said.rhope	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,53 @@
+/*
+	This program implements Paul Graham's "Arc Challenge"
+	While I think the Arc Challenge is a little silly, it does provide a simple 
+	example of how to use the web framework I whipped up for the Rhope blog
+*/
+
+//The Import keyword causes another Rhope source file to be included
+//Here we import the Rhope web framework
+Import framework.rhope
+
+//Here we define an event handler that will get called when the user clicks the button
+//Event handlers get passed the current page tree and an event object
+Save Text[page,event:out]
+{
+	//First we store the value from the text box in a session variable
+	out <- [[[page]Set["said",[[page]Get Child By Name["foo"]]Value >>]
+	//Then we empty the page object
+	]Clear Children
+	//And we add a hyperlink
+	]Add Child[New@Web Link["Click Here","/said"]]
+}
+
+//This worker defines our page
+Said[page,query:out]
+{
+	//Here we try to retrieve the session variable "said"
+	[page]Index["said"]
+	{
+		//If it's present we display it on the page
+		out <- [page]Add Child[ ["You said: "]Append[~] ]
+	}{
+		//Otherwise we provide them with a form to enter a word
+		out <- [[[page]Add Child[New@Web Field["foo","","text"]]
+			]Add Child[
+				New@Web Button["blah","Click!"]
+			//The Set Handler call here attaches the worker Save Text to the click event for the page
+			//Events propagate can propagate themselves up the page hierarchy and handled wherever appropriate
+			]]Set Handler["click","Save Text"]
+	}
+}
+
+Main[]
+{
+	//Start Web starts the webserver and initializes the web framework
+	Start Web[
+		//It takes a dictionary mapping paths to Workers that define dynamic pages
+		//Rather than just passing the name of the Worker, we're passing a List of info
+		//that allows the framework to take care of some of the drudgework for us
+		//The first element in the list is the worker name, the second the page title 
+		//and the third element indicates whether this page will be using session data or not
+		[New@Dictionary[]]Set["/said",("Said","That's what she said",Yes)]
+	]
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/saveload.c	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,317 @@
+#include "interp.h"
+#include "structs.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+/*
+void save_program(char * filename)
+{
+	worker * aworkerlist;
+	wire * awirelist;
+	FILE * savefile;
+	int def_num, version = 1;
+	savefile = fopen(filename, "wb");
+	if(!savefile)
+		return;
+	//deflist[current_def].num_workers = num_workers;
+	//deflist[current_def].num_wires = num_wires;
+	fwrite(&version, 4, 1, savefile);
+	fwrite(&num_defs, 4, 1, savefile);
+	fwrite(deflist, sizeof(worker_def), num_defs, savefile);
+	for(def_num = 0; def_num < num_defs; ++def_num)
+	{
+		if(deflist[def_num].workerlist)
+		{
+			fwrite(&def_num, 4, 1, savefile);
+			//fwrite(&(deflist[def_num].num_workers), 4, 1, savefile);
+			fwrite(deflist[def_num].workerlist, sizeof(worker), deflist[def_num].num_workers, savefile);
+			//fwrite(&(deflist[def_num].num_wires), 4, 1, savefile);
+			fwrite(deflist[def_num].wirelist, sizeof(wire), deflist[def_num].num_wires, savefile);
+		}
+	}
+	def_num = -1;
+	fwrite(&def_num, 4, 1, savefile);
+	fclose(savefile);
+}*/
+
+program * new_program(int def_storage, int comp_storage)
+{
+	defchunk * defs = malloc(sizeof(defchunk) + (def_storage - 1) * sizeof(worker_def));
+	program * prog = malloc(sizeof(program));
+	defs->num_defs = 0;
+	defs->deflist[0].name = NULL;
+	defs->defs_storage = def_storage;
+	defs->next = NULL;
+	prog->current = prog->defs = defs;
+	//prog->deflist = malloc(sizeof(worker_def) * def_storage);
+	//prog->num_defs = 0;
+	//prog->defs_storage = def_storage;
+	prog->companylist = malloc(sizeof(company) * comp_storage);
+	prog->num_companies = 0;
+	prog->companies_storage = comp_storage;
+	prog->refcount = 1;
+	VIS_InitializeCriticalSection(prog->lock);
+	return prog;
+}
+
+int count_defs(defchunk * chunk)
+{
+	int total = 0;
+	while(chunk)
+	{
+		total += chunk->num_defs;
+		chunk = chunk->next;
+	}
+	return total;
+}
+
+void save_program(program * prog, char * filename)
+{
+	int version = 2;
+	int total_bytes = 0;
+	int zero = 0;
+	int i;
+	int num_defs;
+	unsigned char size;
+	custom_worker * aworker;
+	//worker_def * deflist = prog->deflist;
+	defchunk * defs = prog->defs;
+	defchunk * current = defs;
+	worker_def * deflist;
+	FILE * savefile;
+	savefile = fopen(filename, "wb");
+	fwrite(&version, 4, 1, savefile);
+	num_defs = count_defs(defs);
+	fwrite(&(num_defs), 4, 1, savefile);
+	while(current)
+	{
+		deflist = current->deflist;
+		for(i = 0; i < current->num_defs; ++i)
+		{
+			size = strlen(deflist[i].name);
+			fwrite(&size, 1, 1, savefile);
+			fwrite(deflist[i].name, 1, size, savefile);
+			total_bytes += (int)size + 1;
+		}
+		current = current->next;
+	}
+	if(total_bytes % 4 != 0)// pad to a 4 byte boundary
+		fwrite(&zero, 1, 4-(total_bytes % 4), savefile);
+	current = defs;
+	while(current)
+	{
+		deflist = current->deflist;
+		for(i = 0; i < current->num_defs; ++i)
+		{
+			if(deflist[i].type & USER_FLAG)
+			{
+				fwrite(&i, sizeof(int), 1, savefile);
+				fwrite(&(deflist[i].num_inputs), sizeof(short), 1, savefile);
+				fwrite(&(deflist[i].num_outputs), sizeof(short), 1, savefile);
+				fwrite(&(deflist[i].type), sizeof(short), 1, savefile);
+				fwrite(deflist[i].input_types, sizeof(short), deflist[i].num_inputs, savefile);
+				fwrite(deflist[i].output_types, sizeof(short), deflist[i].num_outputs, savefile);
+				total_bytes += sizeof(int) + (sizeof(short) * (3+deflist[i].num_inputs+deflist[i].num_outputs));
+				if(total_bytes % 4 != 0)// pad to a 4 byte boundary
+					fwrite(&zero, 1, 4-(total_bytes % 4), savefile);
+				if((deflist[i].type & TYPE_MASK) == WORKER_TYPE)
+				{
+					aworker = deflist[i].implement_func;
+					fwrite(&(aworker->num_workers), sizeof(int), 1, savefile);
+					fwrite(aworker->workerlist, sizeof(worker), aworker->num_workers, savefile);
+					fwrite(&(aworker->num_wires), sizeof(int), 1, savefile);
+					fwrite(aworker->wirelist, sizeof(wire), aworker->num_wires, savefile);
+				}
+			}
+		}
+		current = current->next;
+	}
+	i = -1;
+	fwrite(&i, sizeof(int), 1, savefile);
+	fclose(savefile);
+}
+
+program * load_program(char * filename)
+{
+	custom_worker * aworker;
+	int version;
+	int i,j;
+	int * def_lookup;
+	char name[256];
+	int total_bytes;
+	int file_defs;
+	unsigned char name_size;
+	FILE * loadfile;
+	char * code;
+	int size;
+	program * prog;
+	loadfile = fopen(filename, "rb");
+	if(!loadfile)
+	{
+		puts("Error: Could not open file");
+		fflush(stdout);
+		return NULL;
+	}
+	if(!strcmp(strrchr(filename,'.')+1, "vis"))
+	{
+		//TODO: Fixme
+		/*fread(&version, 4, 1, loadfile);
+		if(version != 2)
+		{
+			puts("Error: Can't read files of this version.");
+			return NULL;
+		}
+		
+		fread(&file_defs, 4, 1, loadfile);
+		def_lookup = malloc(sizeof(int) * file_defs);
+		total_bytes = 0;
+		prog = new_program(file_defs, START_COMP_STORAGE);
+		initworkers(prog);
+		for(i = 0; i < file_defs; ++i)
+		{
+			fread(&name_size, 1, 1, loadfile);
+			fread(name, 1, name_size, loadfile);
+			name[name_size] = '\0';
+			total_bytes += (int)name_size + 1;
+			for(j = 0; j < prog->num_defs; ++j)
+			{
+				if(!strcmp(name, prog->deflist[j].name))
+				{
+					def_lookup[i] = j;
+					break;
+				}
+			}
+			if(j >= prog->num_defs) //couldn't find it in the list
+			{
+				def_lookup[i] = prog->num_defs;
+				prog->deflist[prog->num_defs].name = malloc(name_size+1);
+				strcpy(prog->deflist[prog->num_defs].name, name);
+				++prog->num_defs;
+			}
+		}
+		if(total_bytes % 4 != 0)// pad to a 4 byte boundary
+			fread(&i, 1, 4-(total_bytes % 4), loadfile);
+		do
+		{
+			fread(&i, sizeof(int), 1, loadfile);
+			if(i >= 0)
+			{
+				i = def_lookup[i];
+				fread(&(prog->deflist[i].num_inputs), sizeof(short), 1, loadfile);
+				fread(&(prog->deflist[i].num_outputs), sizeof(short), 1, loadfile);
+				fread(&(prog->deflist[i].type), sizeof(short), 1, loadfile);
+				prog->deflist[i].input_types = malloc(sizeof(short) * (prog->deflist[i].num_inputs + prog->deflist[i].num_outputs));
+				prog->deflist[i].output_types = prog->deflist[i].input_types + prog->deflist[i].num_inputs;
+				fread(prog->deflist[i].input_types, sizeof(short), prog->deflist[i].num_inputs, loadfile);
+				fread(prog->deflist[i].output_types, sizeof(short), prog->deflist[i].num_outputs, loadfile);
+				total_bytes += sizeof(int) + (sizeof(short) * (3+prog->deflist[i].num_inputs+prog->deflist[i].num_outputs));
+				if(total_bytes % 4 != 0)// pad to a 4 byte boundary
+					fread(&j, 1, 4-(total_bytes % 4), loadfile);
+				if((prog->deflist[i].type & TYPE_MASK) == WORKER_TYPE)
+				{
+					aworker = malloc(sizeof(custom_worker));
+					prog->deflist[i].implement_func = aworker;
+					fread(&(aworker->num_workers), sizeof(int), 1, loadfile);
+					aworker->workerlist = malloc(sizeof(worker) * (aworker->num_workers + 512));
+					fread(aworker->workerlist, sizeof(worker), aworker->num_workers, loadfile);
+					fread(&(aworker->num_wires), sizeof(int), 1, loadfile);
+					aworker->wirelist = malloc(sizeof(wire) * (aworker->num_wires + 1024));
+					fread(aworker->wirelist, sizeof(wire), aworker->num_wires, loadfile);
+					aworker->workers_to_wires_down = malloc(sizeof(int) * (aworker->num_wires + 1024));
+					aworker->workers_to_wires_up = malloc(sizeof(int) * (aworker->num_wires + 1024));
+					for(j = 0; j < aworker->num_workers; ++j)
+						if(aworker->workerlist[j].type == 2)
+							aworker->workerlist[j].value_index = def_lookup[aworker->workerlist[j].value_index];
+				}
+			}
+		}while(i >= 0);*/
+	}
+	else
+	{
+		//Read text program
+		fflush(stdout);
+		fseek(loadfile, 0, SEEK_END);
+		size = ftell(loadfile);
+		fseek(loadfile, 0, SEEK_SET);
+		fflush(stdout);
+		code = malloc(size+1);
+		fread(code, 1, size, loadfile);
+		fclose(loadfile);
+//		num_defs = 0;
+		fflush(stdout);
+		prog = new_program(START_DEF_STORAGE, START_COMP_STORAGE);
+		initpredefworkers(prog);
+		fflush(stdout);	
+		parse(code, size, prog);
+		free(code);
+		
+//		num_workers = deflist[0].num_workers;
+//		num_wires = deflist[0].num_wires;
+	}
+	return prog;
+}
+
+/*
+void load_program(char * filename)
+{
+	worker * aworkerlist;
+	wire * awirelist;
+	FILE * loadfile;
+	char * code;
+	int size;
+	int def_num, version;
+	loadfile = fopen(filename, "rb");
+	if(!loadfile)
+	{
+		puts("Error: Could not open file");
+		return;
+	}
+	if(!strcmp(strrchr(filename,'.')+1, "vis"))
+	{
+		//Read binary program
+		fread(&version, 4, 1, loadfile);
+		if(version != 1)
+		{
+			puts("Error: Can't read files of this version.");
+			return;
+		}
+		//program * new_program = malloc(sizeof(program));
+	//	strcpy(program->filename, filename);
+		fread(&num_defs, 4, 1, loadfile);
+		//program->defs_storage = program->num_defs + 512;
+		//new_program->deflist = malloc(sizeof(worker_def) * (program->defs_storaage));
+		fread(deflist, sizeof(worker_def), num_defs, loadfile);
+		fread(&def_num, 4, 1, loadfile);
+		while(def_num >= 0 && !feof(loadfile))
+		{
+			deflist[def_num].workerlist = malloc((deflist[def_num].num_workers+512)*sizeof(worker));
+			fread(deflist[def_num].workerlist, sizeof(worker), deflist[def_num].num_workers, loadfile);
+			deflist[def_num].wirelist = malloc((deflist[def_num].num_wires+1024)*sizeof(wire));
+			fread(deflist[def_num].wirelist, sizeof(wire), deflist[def_num].num_wires, loadfile);
+			deflist[def_num].workers_to_wires_up = malloc((deflist[def_num].num_wires+1024)*sizeof(int));
+			deflist[def_num].workers_to_wires_down = malloc((deflist[def_num].num_wires+1024)*sizeof(int));
+			fread(&def_num, 4, 1, loadfile);
+		}
+		fclose(loadfile);
+		num_workers = deflist[0].num_workers;
+		num_wires = deflist[0].num_wires;
+		initpredefworkers();
+	}
+	else
+	{
+		//Read text program
+		fseek(loadfile, 0, SEEK_END);
+		size = ftell(loadfile);
+		fseek(loadfile, 0, SEEK_SET);
+		code = malloc(size+1);
+		fread(code, 1, size, loadfile);
+		num_defs = 0;
+		initpredefworkers();
+		parse(code, size);
+		num_workers = deflist[0].num_workers;
+		num_wires = deflist[0].num_wires;
+	}
+}*/
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/saveload.h	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,11 @@
+#ifndef	SAVELOAD_H__
+#define	SAVELOAD_H__
+
+#include "structs.h"
+
+void save_program(program * prog, char * filename);
+program * load_program(char * filename);
+program * new_program(int def_storage, int comp_storage);
+
+#endif //SAVELOAD_H__
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/string.c	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,360 @@
+#include "datum.h"
+#include "structs.h"
+#include "interp.h"
+#include <string.h>
+#include <stdlib.h>
+
+
+int vis_inttostring(datum ** inputlist, queue_entry * worker_entry)
+{
+	int i,j,val;
+	char temp_buf[12];
+	datum * output;
+	char * out_buf;
+	//sprintf(temp_buf, "%d", inputlist[0]->c.integers.num_a);
+	val = (inputlist[0]->c.integers.num_a >= 0 ? inputlist[0]->c.integers.num_a : 0-inputlist[0]->c.integers.num_a);
+	i = 0;
+	if(!val)
+		temp_buf[i++] = '0';
+
+	while(val > 0)
+	{
+		temp_buf[i] = (val % 10) + '0';
+		val /= 10;
+		++i;
+	}
+	if(inputlist[0]->c.integers.num_a < 0)
+	{
+		temp_buf[i] = '-';
+		++i;
+	}
+	release_ref(inputlist[0]);
+	inputlist[0] = new_datum(BUILTIN_TYPE_STRING, 1, i+1, worker_entry->instance->def->program);
+	out_buf = inputlist[0]->c.generic.data;
+	out_buf[i] = '\0';
+	j = 0;
+	--i;
+	while(i >= 0)
+	{
+		out_buf[j] = temp_buf[i];
+		++j;
+		--i;
+	}
+	//strcpy(inputlist[0]->c.generic.data, temp_buf);
+	return 0;
+	
+}
+
+#ifndef SEGA
+int vis_realtostring(datum ** inputlist, queue_entry * worker_entry)
+{
+	char temp_buf[30];//Is this enough?
+	datum * output;
+	sprintf(temp_buf, "%f", inputlist[0]->c.real);
+	release_ref(inputlist[0]);
+	inputlist[0] = new_datum(BUILTIN_TYPE_STRING, 1, strlen(temp_buf)+1, worker_entry->instance->def->program);
+	strcpy(inputlist[0]->c.generic.data, temp_buf);
+	return 0;
+	
+}
+#endif
+
+int vis_stringequal(datum ** inputlist, queue_entry * worker_entry)
+{
+	int result = strcmp(inputlist[0]->c.generic.data, inputlist[1]->c.generic.data);
+	release_ref(inputlist[0]);
+	release_ref(inputlist[1]);
+	inputlist[0] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, worker_entry->instance->def->program);
+	datum_set_yesno(inputlist[0], (result == 0 ? 1 : 0));
+	return 0;
+}
+
+int vis_append(datum ** inputlist, queue_entry * worker_entry)
+{
+	datum * output;
+	int temp_size = inputlist[0]->c.generic.len;
+	DEBUGPUTS("Begin vis_append\n");
+	
+	DEBUGPRINTF("Left: %s(%d)\n", inputlist[0]->c.generic.data, inputlist[0]->c.generic.len);
+	DEBUGPRINTF("Right: %s(%d)\n", inputlist[1]->c.generic.data, inputlist[1]->c.generic.len);
+	output = new_datum(BUILTIN_TYPE_STRING, 1, temp_size+inputlist[1]->c.generic.len-1, worker_entry->instance->def->program);
+	memcpy(output->c.generic.data, inputlist[0]->c.generic.data, temp_size-1);
+	memcpy(((char *)output->c.generic.data)+temp_size-1, inputlist[1]->c.generic.data, inputlist[1]->c.generic.len-1);
+	((char *)output->c.generic.data)[temp_size + inputlist[1]->c.generic.len-2]='\0';
+	DEBUGPRINTF("Appended string: %s(%d)\n", output->c.generic.data, output->c.generic.len);
+	release_ref(inputlist[0]);
+	release_ref(inputlist[1]);
+	inputlist[0] = output;
+	DEBUGPUTS("End vis_append\n");
+	
+	return 0;
+}
+
+int vis_yesnotostring(datum ** inputlist, queue_entry * worker_entry)
+{
+	int result = inputlist[0]->c.integers.num_a;
+	release_ref(inputlist[0]);
+	if(result)
+	{
+		inputlist[0] = new_datum(BUILTIN_TYPE_STRING, 1, 4, worker_entry->instance->def->program);
+		strcpy(inputlist[0]->c.generic.data, "Yes");
+	}
+	else
+	{
+		inputlist[0] = new_datum(BUILTIN_TYPE_STRING, 1, 3, worker_entry->instance->def->program);
+		strcpy(inputlist[0]->c.generic.data, "No");
+	}
+	return 0;
+}
+
+int vis_greaterstring(datum ** inputlist, queue_entry * worker_entry)
+{
+	int result;
+	if(strcmp(inputlist[0]->c.generic.data, inputlist[1]->c.generic.data) > 0)
+		result = 1;
+	else
+		result = 0;
+	release_ref(inputlist[0]);
+	release_ref(inputlist[1]);
+	inputlist[0] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, worker_entry->instance->def->program);
+	datum_set_yesno(inputlist[0], result);
+	return 0;
+}
+
+int vis_lesserstring(datum ** inputlist, queue_entry * worker_entry)
+{
+	int result;
+	if(strcmp(inputlist[0]->c.generic.data, inputlist[1]->c.generic.data) < 0)
+		result = 1;
+	else
+		result = 0;
+	release_ref(inputlist[0]);
+	release_ref(inputlist[1]);
+	inputlist[0] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, worker_entry->instance->def->program);
+	datum_set_yesno(inputlist[0], result);
+	return 0;
+}
+
+datum * make_string(const char * string, int len, program * prog)
+{
+	datum * output;
+	if(len < 0)
+		len = strlen(string);
+	output = new_datum(BUILTIN_TYPE_STRING, 1, len+1, prog);
+	memcpy(output->c.generic.data, string, len);
+	((char *)output->c.generic.data)[len] = '\0';
+	return output;
+}
+
+int vis_string_split(datum ** inputlist, queue_entry * worker_entry)
+{
+	int i, start=0, len = inputlist[0]->c.generic.len-1;
+	char * string = inputlist[0]->c.generic.data;
+	char * delim = inputlist[1]->c.generic.data;
+	int delimlen = inputlist[1]->c.generic.len-1;
+	int search_offset = 0;
+	datum * params[2];
+	params[0] = create_list(worker_entry->instance->def->program);
+	DEBUGPRINTF("Split@String: delim(%s) string(%s)\n", delim, string);
+	for(i = 0; i < len; ++i)
+	{
+		if(string[i] == delim[search_offset])
+		{
+			if(search_offset == (delimlen-1))
+			{
+				params[1] = make_string(string + start, i-start-(delimlen-1), worker_entry->instance->def->program);
+				DEBUGPRINTF("Appending %s(%d) to list\n", params[1]->c.generic.data, params[1]->c.generic.len);
+				vis_list_append(params, worker_entry);
+				start = i+1;
+				search_offset = 0;
+			}
+			else
+				++search_offset;
+		}
+		else if(search_offset > 0)
+		{
+			i = (i-search_offset+1);
+			search_offset = 0;
+		}
+	}
+	if(len)
+	{
+		params[1] = make_string(string + start, i-start, worker_entry->instance->def->program);
+		vis_list_append(params, worker_entry);
+	}
+	DEBUGPUTS("End Split@String\n");
+	
+	release_ref(inputlist[0]);
+	release_ref(inputlist[1]);
+	inputlist[0] = params[0];
+	return 0;
+}
+
+int vis_string_put_raw(datum ** inputlist, queue_entry * worker_entry)
+{
+	int old_len = inputlist[0]->c.generic.len;
+	char * data;
+	inputlist[0] = copy_datum(inputlist[0], old_len + inputlist[1]->c.generic.len);
+	data = inputlist[0]->c.generic.data;
+	memcpy(data + old_len - 1, inputlist[1]->c.generic.data, inputlist[1]->c.generic.len);
+	release_ref(inputlist[1]);
+	data[inputlist[0]->c.generic.len-1] = '\0';
+	return 0;
+}
+
+int vis_string_get_raw(datum ** inputlist, queue_entry * worker_entry)
+{
+	char * data = inputlist[0]->c.generic.data;
+	datum * output;
+	inputlist[1] = copy_datum(inputlist[1], 0);
+	memcpy(inputlist[1]->c.generic.data, data, inputlist[1]->c.generic.len);
+	output = make_string(data + inputlist[1]->c.generic.len, inputlist[0]->c.generic.len - inputlist[1]->c.generic.len - 1, worker_entry->instance->def->program);
+	release_ref(inputlist[0]);
+	inputlist[0] = output;
+	return 0;
+}
+
+int vis_string_slice(datum ** inputlist, queue_entry * worker_entry)
+{
+	char * string;
+	int index = inputlist[1]->c.integers.num_a;
+	release_ref(inputlist[1]);
+	if(index < (inputlist[0]->c.generic.len-1))
+	{
+		inputlist[1] = new_datum_comp(inputlist[0]->company, 1, inputlist[0]->c.generic.len-index);
+		memcpy(inputlist[1]->c.generic.data, (char *)(inputlist[0]->c.generic.data) + index, inputlist[0]->c.generic.len-index);
+		inputlist[0] = copy_datum(inputlist[0], index+1);
+		string = inputlist[0]->c.generic.data;
+		string[index] = '\0';
+	}
+	else
+	{
+		inputlist[1] = new_datum_comp(inputlist[0]->company, 1, 1);
+		string = inputlist[1]->c.generic.data;
+		string[0] = '\0';
+	}
+	return 0;
+}
+
+int vis_string_reverse(datum ** inputlist, queue_entry * worker_entry)
+{
+	int ref_count, i,j;
+	datum * output;
+	char *source, *dest, tmp;
+	VIS_EnterCriticalSection(inputlist[0]->lock);
+		ref_count = inputlist[0]->ref_count;
+	VIS_LeaveCriticalSection(inputlist[0]->lock);
+
+	if(ref_count > 1)
+		output = new_datum_comp(inputlist[0]->company, 1, inputlist[0]->c.generic.len);
+	else
+		output = inputlist[0];
+	source = inputlist[0]->c.generic.data;
+	
+	if(ref_count > 1)
+	{
+		dest = output->c.generic.data;
+		i = 0;
+		for(j = output->c.generic.len-2; j >= 0; --j)
+			dest[j] = source[i++];
+		release_ref(inputlist[0]);
+		inputlist[0] = output;
+	}
+	else
+	{
+		i = 0;
+		for(j = output->c.generic.len-2; j > i; --j)
+		{
+			tmp = source[i];
+			source[i++] = source[j];
+			source[j] = tmp;
+		}
+	}
+	return 0;
+}
+
+int vis_string_length(datum ** inputlist, queue_entry * worker_entry)
+{
+	int len = inputlist[0]->c.generic.len-1;
+	release_ref(inputlist[0]);
+	inputlist[0] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program);
+	inputlist[0]->c.integers.num_a = len;
+	return 0;
+}
+
+int vis_string_put_byte(datum ** inputlist, queue_entry * worker_entry)
+{
+	inputlist[0] = copy_datum(inputlist[0], inputlist[0]->c.generic.len + 1);
+	((unsigned char *)(inputlist[0]->c.generic.data))[inputlist[0]->c.generic.len - 2] = (unsigned char)inputlist[1]->c.integers.num_a;
+	((unsigned char *)(inputlist[0]->c.generic.data))[inputlist[0]->c.generic.len - 1] = '\0';
+	release_ref(inputlist[1]);
+	return 0;	
+}
+
+int vis_string_get_dstring(datum ** inputlist, queue_entry * worker_entry)
+{
+	datum ** delimlist;
+	int num_delims;
+	int i,len,delimlen;
+	char *current;
+	BOOL match=FALSE;
+	datum * temp;
+	if(inputlist[1]->company->type_id == BUILTIN_TYPE_LIST)
+	{
+		delimlist = ((list_data *)inputlist[1]->c.generic.data)->entries;
+		num_delims = ((list_data *)inputlist[1]->c.generic.data)->num_entries;
+		//TODO: check to make sure that all of the list entries are strings
+	}
+	else if(inputlist[1]->company->type_id == BUILTIN_TYPE_STRING) 
+	{
+		delimlist = inputlist+1;
+		num_delims = 1;
+	}
+	else
+	{
+		ERRORPUTS("Second argument to Get DString@String must be either a String or a List");
+		release_ref(inputlist[0]);
+		release_ref(inputlist[1]);
+		return -1;
+	}
+	current = inputlist[0]->c.generic.data;
+	len = inputlist[0]->c.generic.len - 1;
+	while(len && !match)
+	{
+		for(i = 0; i < num_delims; ++i)
+		{
+			delimlen = delimlist[i]->c.generic.len-1;
+			if(len >= delimlen && !memcmp(current, delimlist[i]->c.generic.data, delimlen))
+			{
+				match = TRUE;
+				//deal with the fact that we're going to adjust current and len even though we're done
+				--current;
+				++len;
+				break;
+			}
+		}
+		++current;
+		--len;
+	}
+	if(match)
+	{
+		inputlist[2] = add_ref(delimlist[i]);
+		release_ref(inputlist[1]);
+		inputlist[1] = make_string(inputlist[0]->c.generic.data, current - ((char *)inputlist[0]->c.generic.data), worker_entry->instance->def->program);
+		delimlen = inputlist[2]->c.generic.len-1;
+		temp = make_string(current+delimlen, len-delimlen, worker_entry->instance->def->program);
+		release_ref(inputlist[0]);
+		inputlist[0] = temp;
+		inputlist[3] = NULL;
+	}
+	else
+	{
+		release_ref(inputlist[1]);
+		inputlist[1] = inputlist[0];
+		inputlist[0] = NULL;
+		inputlist[2] = NULL;
+		inputlist[3] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, worker_entry->instance->def->program);
+		inputlist[3]->c.integers.num_a = 0;
+	}
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/structs.h	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,457 @@
+#ifndef _STRUCTS_H_
+#define _STRUCTS_H_
+
+#ifdef WIN32
+	#include <windows.h>
+#endif
+
+#ifndef BOOL
+	#define BOOL short
+	#define	TRUE	1
+	#define	FALSE	0
+#endif
+
+#ifndef DWORD
+	#define	DWORD	unsigned long
+#endif
+
+#ifndef	WINAPI
+	#define WINAPI
+#endif
+
+#ifndef LPVOID
+	#define LPVOID void *
+#endif
+#ifndef NULL
+	#define NULL 0
+#endif
+
+//#include "interp.h"
+#include "vis_threading.h"
+#include "datum.h"
+#define QUEUE_SIZE 512
+#include <stdio.h>
+
+#ifdef CPLUSPLUS
+extern "C" {
+#endif
+
+typedef struct
+{
+	int type;
+	int num_outputs;
+	int num_inputs;
+	char name[256];
+	int wire_up_lookup;
+	int wire_down_lookup;
+	void * value_index;//used to associate with a def
+	int io_num;
+	unsigned short magic_cache_type;
+	struct worker_def * magic_cache_implement;
+	VIS_CRITICAL_SECTION(lock)
+	BOOL null_input;
+} worker;
+
+typedef struct
+{
+	int start_worker;
+	int end_worker;
+	int output_num;
+	int input_num;
+} wire;
+
+
+typedef struct
+{
+	datum * value;
+	VIS_CRITICAL_SECTION(worker_lock)
+	int ready_count;
+	datum * params[32];
+} worker_instance_data;
+
+
+typedef struct
+{
+	datum *  data;
+} wire_instance_data;
+
+/*
+Moved to datum.h for stupid reasons
+typedef struct
+{
+	char filename[512];
+	struct worker_def * deflist;
+	int num_defs;
+	int defs_storage;
+	struct company * companylist;
+	int num_companies;
+	int companies_storage;
+} program;
+
+*/
+
+/*typedef struct worker_def
+{
+	worker_impl	implement_func;
+	char name[256];
+	int num_outputs;
+	int num_inputs;
+	unsigned short input_types[32];
+//	unsigned short output_types[32];
+//	int	parent_out_wires[32];
+	worker * workerlist;
+	int num_workers;
+	wire * wirelist;
+	int num_wires;
+	int * workers_to_wires_down;
+	int * workers_to_wires_up;
+//	struct worker_def * parent;
+//	int parent_attached_worker;
+//	int parent_attached_workerout;
+//	struct worker_def ** children;
+//	int num_children;
+	BOOL magic;
+	program program;
+} worker_def;*/
+/*
+typedef struct worker_def_file
+{
+	worker_impl	implement_func;
+	char name[256];
+	int num_outputs;
+	int num_inputs;
+	unsigned short input_types[32];
+//	unsigned short output_types[32];
+//	int	parent_out_wires[32];
+	worker * workerlist;
+	int num_workers;
+	wire * wirelist;
+	int num_wires;
+	int * workers_to_wires_down;
+	int * workers_to_wires_up;
+//	struct worker_def * parent;
+//	int parent_attached_worker;
+//	int parent_attached_workerout;
+//	struct worker_def ** children;
+//	int num_children;
+	BOOL magic;
+} worker_def;*/
+
+typedef struct
+{
+	worker * workerlist;
+	int num_workers;
+	int worker_storage;
+	wire * wirelist;
+	int num_wires;
+	int wire_storage;
+	int * workers_to_wires_down;
+	int * workers_to_wires_up;
+	VIS_CRITICAL_SECTION(lock)
+	BOOL dirty;
+} custom_worker;
+
+#define TRANSACTION_WRITE		0x8000
+#define TRANSACTION_TYPE_MASK	0xFF
+#define TRANSACTION_RETRY		0
+#define TRANSACTION_FORCE		1
+
+typedef struct worker_def
+{
+	custom_worker *	implement_func;	//points to either C function or "custom function struct"
+	char * name;
+	struct opt_entry * optimized;
+	int opt_count;
+	int num_stores;
+	char ** uses_stores;
+	unsigned short num_outputs;
+	unsigned short num_inputs;
+	unsigned short *input_types;
+	unsigned short *output_types;
+	unsigned short type;	//Magic, Builtin, Custom
+	unsigned short transaction_flags;
+#ifdef CPLUSPLUS
+//ugly hack alert!
+	program * prog;
+#else
+	program * program;
+#endif
+#ifdef USER_PROFILE
+	int count;
+	LARGE_INTEGER total;
+	LARGE_INTEGER worst;
+	VIS_CRITICAL_SECTION(lock)
+#endif
+} worker_def;
+
+typedef struct defchunk
+{
+	int num_defs;
+	int defs_storage;
+	struct defchunk * next;
+	worker_def deflist[1];
+} defchunk;
+
+typedef struct
+{
+	datum * name;
+	datum * data;
+	//short inuse;
+} global_store;
+
+typedef struct
+{
+	global_store * store;
+	datum * begin_data;
+	datum * instance_data;
+	VIS_CRITICAL_SECTION(lock)
+} global_store_use;
+
+typedef struct
+{
+	int num_stores;
+	datum * params[32];
+	global_store_use stores[1];
+} transaction;
+
+typedef struct worker_instance
+{
+	worker_def * def;
+	worker_instance_data * workerlist;
+	datum ** opt_results;
+	int num_workers;
+	wire_instance_data * wirelist;
+	int num_wires;
+	void (*callback)(struct worker_instance *, int, struct worker_instance *, void * data);
+	void * callback_data;
+	struct worker_instance * caller_instance;
+	int worker_in_caller;
+	int in_queue_count;
+	int in_progress_count;
+	int child_count;
+	transaction * trans;
+#ifdef USER_PROFILE
+	LARGE_INTEGER start;
+#endif // USER_PROFILE
+	VIS_CRITICAL_SECTION(counter_lock)
+} worker_instance;
+
+typedef void (*instance_callback)(worker_instance *, int, worker_instance *, void * data);
+
+typedef struct
+{
+	int worker_num;
+	worker_instance * instance;
+} queue_entry;
+
+typedef struct queue_section
+{
+	queue_entry entries[QUEUE_SIZE];
+	struct queue_section * last;
+	struct queue_section * next;
+} queue_section;
+
+#define ROOM_NO_ACCESS		0
+#define ROOM_BYTE			1
+#define ROOM_SHORT			2
+#define ROOM_LONG			3
+#define ROOM_SINGLE			4
+#define ROOM_DOUBLE			5
+//The param must be set to the max string length for these
+#define ROOM_CSTRING_STRUCT	6
+#define ROOM_PSTRING_STRUCT 7
+//Pointer types: For the following it's assumed that it's safe to free the current string
+#define ROOM_CSTRING		8
+#define ROOM_PSTRING		9
+//Will copy the contents of a complex value to the destination offset, or the union contents otherwise
+#define ROOM_VIS_OBJECT		10
+//Pointer to datum
+#define ROOM_VIS_REF		11
+//Use a worker to set/get the room
+#define	ROOM_WORKER			12
+
+#define PRIVATE_FLAG		0x8000
+#define ROOM_TYPE_MASK		0xFF
+
+typedef struct
+{
+	char * name;
+	void * set_func;
+	void * get_func;
+	int param;
+	unsigned short set_func_type;
+	unsigned short get_func_type;
+} company_room;
+
+typedef struct company
+{
+	char name[256];
+	worker_def ** methodlist;
+	int num_methods;
+	int method_storage;
+	company_room * room_list;
+	int num_rooms;
+	int room_storage;
+	int build_size;
+	unsigned short type_id;
+	VIS_CRITICAL_SECTION(lock)
+} company;
+
+typedef struct
+{
+	int num_entries;
+	datum * entries[1];
+} list_data;
+/*
+typedef struct ternary_node
+{
+	struct ternary_node * left;
+	struct ternary_node * right;
+	struct ternary_node * next;
+	datum * payload;
+	char letter;
+} ternary_node;
+*/
+
+typedef struct ternary_node
+{
+	int left;
+	int right;
+	int next;
+	datum * payload;
+	char letter;
+} ternary_node;
+
+typedef struct
+{
+	int num_entries;	//Number of entries currently in the dict
+	int num_nodes;		//Number of ternary nodes in the dict
+	int node_storage;	//Max number of nodes we can store in the dict
+	ternary_node nodes[1];
+} dict_data;
+
+typedef enum {FILE_NOSIZE, FILE_CLOSED, FILE_WRITE, FILE_READ, FILE_CANT_OPEN} file_status;
+typedef struct
+{
+	unsigned int size;
+#ifndef SEGA
+	FILE * file;
+#endif
+	VIS_CRITICAL_SECTION(lock)
+	int ref_count;
+	file_status status;
+	char name[1];
+} shared_file;
+typedef struct
+{
+	unsigned int offset;
+	shared_file * shared;
+} file_data;
+
+typedef struct
+{
+	datum * title;
+	double width;
+	double height;
+	datum * widget_dict;
+	datum * widget_xpos;
+	datum * widget_ypos;
+	datum * id_list;
+} vis_window;
+
+typedef struct
+{
+	datum * label;
+	datum * value;
+	double width;
+	double height;
+	int flags;
+	datum * handler_dict;
+	int selected_index;
+} vis_widget;
+
+typedef struct
+{
+	VIS_CRITICAL_SECTION(lock)
+	datum ** params;
+	BOOL done_flag;
+} def_done;
+
+typedef struct opt_entry
+{
+	worker_def * def;
+	int original_pos;
+	int * input_data;
+	int null_inputs;
+	int branch1;
+	int branch2;
+	int * output_refs;
+} opt_entry;
+
+typedef struct
+{
+	worker_def * def;
+	datum * params[32];
+} worker_datum;
+#define MIN_STACK_SIZE 512	//minimum stack size in longwords
+typedef struct stack_segment
+{
+	int size;
+	struct stack_segment *parent;
+	struct stack_segment *child;
+	unsigned long current_stack;//only used when stack is in the queue
+	unsigned int data[MIN_STACK_SIZE];
+} stack_segment;
+
+#define QUEUE_FUNC			0
+#define QUEUE_BUILTIN		1
+#define	QUEUE_BLOCK			2
+#define	QUEUE_BLOCK_WAIT	3
+
+typedef struct
+{
+	unsigned long * address;
+	void * params;
+	stack_segment * stack;
+	char	type;
+} virt_queue_entry;
+
+typedef struct virt_queue_segment
+{
+	struct virt_queue_segment * next;
+	struct virt_queue_segment * last;
+	virt_queue_entry entries[QUEUE_SIZE];
+} virt_queue_segment;
+
+typedef int (*worker_impl)(datum  **, queue_entry *);
+
+//extern worker_def deflist[100];
+//extern int num_defs;
+
+//extern datum data[4096];
+//extern int num_datum;
+
+extern wire wirelist[2048];
+extern int num_wires;
+
+extern worker workerlist[1024];
+extern int num_workers;
+
+extern int workers_to_wires_down[2048];
+extern int workers_to_wires_up[2048];
+
+#ifdef CPLUSPLUS
+}
+#endif
+
+
+#endif //_STRUCTS_H_
+
+
+
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/syl_generic.cpp	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,308 @@
+#include "syl_generic.h"
+#include "interp.h"
+#include "debugmacros.h"
+#include <gui/window.h>
+#include "syl_window.h"
+
+datum * get_callback(datum * handler_dict, char * name, worker_instance * instance)
+{
+	queue_entry entry;
+	datum * params[2];
+	params[0] = add_ref( handler_dict );
+	params[1] = make_string(name, -1, instance->def->prog);
+	entry.instance = instance;
+	vis_dict_index(params, &entry);
+	if(params[1])
+		release_ref(params[1]);
+	return params[0];
+}
+
+void GenericView::SetCallbacks()
+{
+	this->paint_worker = get_callback(this->handler_dict, "draw", instance);
+	this->mousemove_worker = get_callback(this->handler_dict, "mousemove", instance);
+	this->mousedown_worker = get_callback(this->handler_dict, "mousedown", instance);
+	this->mouseup_worker = get_callback(this->handler_dict, "mouseup", instance);
+}
+
+void GenericView::ResetCallbacks()
+{
+	release_ref(this->paint_worker);
+	release_ref(this->mousemove_worker);
+	release_ref(this->mousedown_worker);
+	release_ref(this->mouseup_worker);
+	SetCallbacks();
+}
+
+GenericView::GenericView(const os::Rect& cFrame, const os::String& cTitle, datum * widget_datum, worker_instance * instance) : os::View(cFrame, cTitle/*, os::CF_FOLLOW_LEFT | os::CF_FOLLOW_TOP, os::WID_WILL_DRAW | os::WID_CLEAR_BACKGROUND | os::WID_TRANSPARENT*/)
+{
+	datum * handler_dict;
+	this->widget_datum = widget_datum;
+	this->instance = instance;
+	this->handler_dict = ((vis_widget *)(widget_datum->c.generic.data))->handler_dict;
+	SetCallbacks();
+}
+
+void GenericView::DoCallback(datum * worker, const os::Rect& rect, datum ** extra_params, int num_extra)
+{
+	queue_entry entry;
+	generic_view_datum * view;
+	entry.instance = this->instance;
+	datum * params[32];
+	datum * list;
+	DEBUGPRINTF("program: %X\n", this->instance->def->prog);
+	params[0] = create_list(this->instance->def->prog);
+	params[1] = new_datum(BUILTIN_TYPE_SCREEN_CUSTOM, 1, sizeof(generic_view_datum), this->instance->def->prog);
+	DEBUGPUTS("Datum created\n");
+	DEBUGPRINTF("screen custom widget company name: %s\n", params[1]->company->name);
+	view = (generic_view_datum *)(params[1]->c.generic.data);
+	view->view = this;
+	view->update_rect = rect;
+	vis_list_append(params, &entry);
+	for(int i = 0; i < num_extra; ++i)
+	{
+		params[1] = extra_params[i];
+		vis_list_append(params, &entry);
+	}
+	list = params[0];
+	worker_populate_inputs(worker, list, params);
+	release_ref(list);
+	DEBUGPUTS("Calling execute_def_wait\n");
+	execute_def_wait(((worker_datum *)(worker->c.generic.data))->def, params);
+}
+void GenericView::Paint(const os::Rect& cUpdateRect)
+{
+	//DEBUGPUTS("GenericView::Paint\n");
+	//queue_entry entry;
+	//generic_view_datum * view;
+	if(this->paint_worker)
+	{
+		DoCallback(this->paint_worker, cUpdateRect, NULL, 0);
+		/*entry.instance = this->instance;
+		datum * params[32];
+		datum * list;
+		DEBUGPRINTF("program: %X\n", this->instance->def->prog);
+		params[0] = create_list(this->instance->def->prog);
+		params[1] = new_datum(BUILTIN_TYPE_SCREEN_CUSTOM, 1, sizeof(generic_view_datum), this->instance->def->prog);
+		DEBUGPUTS("Datum created\n");
+		DEBUGPRINTF("screen custom widget company name: %s\n", params[1]->company->name);
+		view = (generic_view_datum *)(params[1]->c.generic.data);
+		view->view = this;
+		view->update_rect = cUpdateRect;
+		vis_list_append(params, &entry);
+		list = params[0];
+		worker_populate_inputs(this->paint_worker, list, params);
+		release_ref(list);
+		DEBUGPUTS("Calling execute_def_wait\n");
+		execute_def_wait(((worker_datum *)(this->paint_worker->c.generic.data))->def, params);
+		//params[0] = add_ref(this->paint_worker);
+		//if(vis_worker_do(params, &entry) == 0)
+		//	release_ref(params[0]);*/
+	}
+	else
+		os::View::Paint(cUpdateRect);
+}
+
+void GenericView::DefaultPaint(const os::Rect& cUpdateRect)
+{
+	os::View::Paint(cUpdateRect);
+}
+
+void GenericView::MouseMove( const os::Point& newPos, int code, uint32 buttons, os::Message* msg)
+{
+	datum * params[2];
+	if(this->mousemove_worker)
+	{
+		params[0] = new_datum(BUILTIN_TYPE_REAL, 3, 0, this->instance->def->prog);
+		params[0]->c.real = newPos.x;
+		params[1] = new_datum(BUILTIN_TYPE_REAL, 3, 0, this->instance->def->prog);
+		params[1]->c.real = newPos.y;
+		DoCallback(this->mousemove_worker, os::Rect(0,0,0,0), params, 2);
+	}
+}
+
+void GenericView::MouseDown( const os::Point& pos, uint32 buttons)
+{
+	datum * params[3];
+	if(this->mousedown_worker)
+	{
+		DEBUGPRINTF("Mouse down worker: %X\n", this->mousedown_worker);
+		params[0] = new_datum(BUILTIN_TYPE_REAL, 3, 0, this->instance->def->prog);
+		params[0]->c.real = pos.x;
+		params[1] = new_datum(BUILTIN_TYPE_REAL, 3, 0, this->instance->def->prog);
+		params[1]->c.real = pos.y;
+		params[2] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, this->instance->def->prog);
+		params[2]->c.integers.num_a = buttons;
+		DoCallback(this->mousedown_worker, os::Rect(0,0,0,0), params, 3);
+	}
+}
+
+void GenericView::MouseUp( const os::Point& pos, uint32 buttons, os::Message* msg)
+{
+	datum * params[3];
+	if(this->mouseup_worker)
+	{
+		params[0] = new_datum(BUILTIN_TYPE_REAL, 3, 0, this->instance->def->prog);
+		params[0]->c.real = pos.x;
+		params[1] = new_datum(BUILTIN_TYPE_REAL, 3, 0, this->instance->def->prog);
+		params[1]->c.real = pos.y;
+		params[2] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, this->instance->def->prog);
+		params[2]->c.integers.num_a = buttons;
+		DoCallback(this->mouseup_worker, os::Rect(0,0,0,0), params, 3);
+	}
+}
+/*
+void GenericView::MakeFocus(bool give_focus)
+{
+	os_window * parent_wind = (os_window *)GetWindow();
+	if(parent_wind)
+		if(give_focus)
+			parent_wind->SetFocusNoHandler(this)
+		else if(parent_wind->GetFocusChild() == this)
+			parent_wind->SetFocusNoHandler(NULL);
+}
+*/
+extern "C"
+{
+	
+int vis_screen_custom_defaultpaint(datum ** params, queue_entry * entry)
+{
+	generic_view_datum * view = (generic_view_datum *)(params[0]->c.generic.data);
+	DEBUGPUTS("Calling Genericview::DefaultPaint\n");
+	view->view->DefaultPaint(view->update_rect);
+	DEBUGPUTS("Genericview::DefaultPaint returned\n");
+	return 0;
+}
+
+int vis_screen_custom_drawline(datum ** params, queue_entry * entry)
+{
+	DEBUGPRINTF("Draw line from %f,%f to %f,%f\n", params[1]->c.real,params[2]->c.real, params[3]->c.real,params[4]->c.real);
+	generic_view_datum * view = (generic_view_datum *)(params[0]->c.generic.data);
+	view->view->DrawLine(os::Point(params[1]->c.real,params[2]->c.real), os::Point(params[3]->c.real,params[4]->c.real));
+	DEBUGPUTS("finished calling DrawLine()\n");
+	release_ref(params[1]);
+	release_ref(params[2]);
+	release_ref(params[3]);
+	release_ref(params[4]);
+	return 0;
+}
+
+int vis_screen_custom_drawstring(datum ** params, queue_entry * entry)
+{
+	generic_view_datum * view = (generic_view_datum *)(params[0]->c.generic.data);
+	view->view->DrawString(os::Point(params[2]->c.real, params[3]->c.real), ((char *)(params[1]->c.generic.data)));
+	release_ref(params[1]);
+	release_ref(params[2]);
+	release_ref(params[3]);
+	return 0;
+}
+
+int vis_screen_custom_setdrawcolor(datum ** params, queue_entry * entry)
+{
+	generic_view_datum * view = (generic_view_datum *)(params[0]->c.generic.data);
+	view->view->SetFgColor(params[1]->c.integers.num_a, params[2]->c.integers.num_a, params[3]->c.integers.num_a, params[4]->c.integers.num_a);
+	release_ref(params[1]);
+	release_ref(params[2]);
+	release_ref(params[3]);
+	release_ref(params[4]);
+	return 0;
+}
+
+int vis_screen_custom_moveby(datum ** params, queue_entry * entry)
+{
+	generic_view_datum * view = (generic_view_datum *)(params[0]->c.generic.data);
+	view->view->MoveBy(os::Point(params[1]->c.real, params[2]->c.real));
+	view->view->Flush();
+	release_ref(params[1]);
+	release_ref(params[2]);
+	return 0;
+}
+
+int vis_screen_custom_sethandler(datum ** params, queue_entry * entry)
+{
+	datum * screen_datum;
+	generic_view_datum * view = (generic_view_datum *)(params[0]->c.generic.data);
+	screen_datum = params[0];
+	params[0] = view->view->handler_dict;
+	vis_dict_set(params, entry);
+	view->view->handler_dict = params[0];
+	params[0] = screen_datum;
+	view->view->ResetCallbacks();
+	return 0;
+}
+
+int vis_screen_custom_removehandler(datum ** params, queue_entry * entry)
+{
+	datum * screen_datum;
+	generic_view_datum * view = (generic_view_datum *)(params[0]->c.generic.data);
+	screen_datum = params[0];
+	params[0] = view->view->handler_dict;
+	vis_dict_remove(params, entry);
+	view->view->handler_dict = params[0];
+	params[0] = screen_datum;
+	view->view->ResetCallbacks();
+	return 0;
+}
+
+int vis_screen_custom_givefocus(datum ** params, queue_entry * entry)
+{
+	os::Window * wind;
+	generic_view_datum * view = (generic_view_datum *)(params[0]->c.generic.data);
+	wind = view->view->GetWindow();
+	if(wind)
+		wind->Unlock();
+	view->view->MakeFocus(params[1]->c.integers.num_a);
+	if(wind)
+		wind->Lock();
+	release_ref(params[1]);
+	return 0;
+}
+
+int vis_screen_custom_addwidget(datum ** params, queue_entry * entry)
+{
+	generic_view_datum * view = (generic_view_datum *)(params[0]->c.generic.data);
+	os_window * wind = (os_window *)(view->view->GetWindow());
+	//printf("Locking window: %X\n", wind);
+	wind->Unlock();
+	puts("Adding widget");
+	add_widget_shared((vis_window_shown *)(wind->vis_wind->c.generic.data), params[2], (char *)(params[1]->c.generic.data), params[3]->c.real, params[4]->c.real, entry, view->view);
+	puts("Unlocking window");
+	wind->Lock();
+	puts("Releasing refs");
+	release_ref(params[1]);
+	release_ref(params[2]);
+	release_ref(params[3]);
+	release_ref(params[4]);
+	return 0;
+}
+
+int vis_screen_custom_getwindow(datum ** params, queue_entry * entry)
+{
+	generic_view_datum * view = (generic_view_datum *)(params[0]->c.generic.data);
+	os_window * wind = (os_window *)(view->view->GetWindow());
+	release_ref(params[0]);
+	params[0] = add_ref(wind->vis_wind);
+	return 0;
+}
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/syl_generic.h	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,48 @@
+#ifndef SYL_GENERIC_H_
+#define SYL_GENERIC_H_
+
+#include <gui/view.h>
+#include "datum.h"
+#include "structs.h"
+
+class GenericView : public os::View
+{
+public:
+	GenericView(const os::Rect& cFrame, const os::String& cTitle, datum * widget_datum, worker_instance * instance);
+	void Paint(const os::Rect& cUpdateRect);
+	void DefaultPaint(const os::Rect& cUpdateRect);
+	void MouseMove( const os::Point& newPos, int code, uint32 buttons, os::Message* msg);
+	void MouseDown( const os::Point& pos, uint32 buttons);
+	void MouseUp( const os::Point& pos, uint32 buttons, os::Message* msg);
+//	void MakeFocus(bool give_focus);
+	void DoCallback(datum * worker, const os::Rect& rect, datum ** extra_params, int num_extra);
+	void ResetCallbacks();
+	datum * handler_dict;
+private:
+	void SetCallbacks();
+	datum * widget_datum;
+	datum * paint_worker;
+	datum * mousemove_worker;
+	datum * mousedown_worker;
+	datum * mouseup_worker;
+	worker_instance * instance;
+};
+
+typedef struct
+{
+	GenericView * view;
+	os::Rect update_rect;
+} generic_view_datum;
+
+#endif //SYL_GENERIC_H_
+
+
+
+
+
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/syl_window.cpp	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,561 @@
+#include <util/application.h>
+#include <util/message.h>
+#include <gui/button.h>
+#include <gui/textview.h>
+#include <gui/control.h>
+#include <gui/checkbox.h>
+#include <gui/dropdownmenu.h>
+#include <atheos/threads.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include "syl_window.h"
+#include "structs.h"
+#include "debugmacros.h"
+#include "syl_generic.h"
+
+os::Application *app;
+
+extern "C" {
+
+
+void app_thread(void * param)
+{
+	DEBUGPUTS("Before app->Run()\n");
+	app->Run();
+	DEBUGPUTS("After app->Run()\n");
+}
+
+//VIS_CRITICAL_SECTION_EXTERN(app_lock)
+extern short app_lock;
+
+void check_create_app()
+{
+	VIS_EnterCriticalSection(app_lock);
+		if(!app)
+		{
+			
+			app = new os::Application("mime type goes here");
+			resume_thread(spawn_thread("vis_app", (void *)app_thread, 1, 0, NULL));
+			DEBUGPUTS("Created application object\n");
+		}
+	VIS_LeaveCriticalSection(app_lock);
+}
+
+int vis_window_get_value(datum ** inputlist, queue_entry * worker_entry)
+{
+	datum * output = NULL, *name;
+	os::String val;
+	os::Control * control = NULL;
+	os::DropdownMenu * drop;
+	vis_window_shown * window = (vis_window_shown *)(inputlist[0]->c.generic.data);
+	name = add_ref(inputlist[1]);
+	inputlist[2] = inputlist[1];
+	
+	DEBUGPUTS("Entering window lock\n");
+	VIS_EnterCriticalSection(window->lock);
+		inputlist[1] = add_ref(window->widget_types);
+		vis_dict_index(inputlist+1, worker_entry);
+		if(inputlist[1])
+		{
+			switch(inputlist[1]->c.integers.num_a)
+			{
+			case BUILTIN_TYPE_INPUTBOX:
+				control = (os::Control *)(window->wind->FindView((char *)(name->c.generic.data)));
+				if(control)
+				{
+					DEBUGPUTS("Before GetValue\n");
+					val = control->GetValue().AsString();
+					output = make_string(val.c_str(), val.CountChars(), worker_entry->instance->def->prog);
+				}
+				break;
+			case BUILTIN_TYPE_CHECKBOX:
+				control = (os::Control *)(window->wind->FindView((char *)(name->c.generic.data)));
+				if(control)
+				{
+					output = new_datum(BUILTIN_TYPE_YESNO, 2, 0, worker_entry->instance->def->prog);
+					output->c.integers.num_a = control->GetValue().AsBool();
+				}
+				break;
+			case BUILTIN_TYPE_DROPDOWN:
+				drop = (os::DropdownMenu *)(window->wind->FindView((char *)(name->c.generic.data)));
+				if(drop)
+				{
+					val = drop->GetCurrentString();
+					output = make_string(val.c_str(), val.CountChars(), worker_entry->instance->def->prog);
+				}
+				break;
+			default:
+				printf("Unsupported widget type %d for Get Value\n", inputlist[1]->c.integers.num_a);
+				break;
+			}
+		}
+				
+	VIS_LeaveCriticalSection(window->lock);
+	DEBUGPUTS("Leaving window lock\n");
+	DEBUGPRINTF("window->wind: %X\n", window->wind);
+	DEBUGPRINTF("window->title: %X\n", window->title);
+	release_ref(inputlist[0]);
+	release_ref(inputlist[1]);
+	release_ref(name);
+	inputlist[0] = output;
+	return 0;
+}
+
+int vis_window_set_value(datum ** inputlist, queue_entry * worker_entry)
+{
+	datum *name, *value;
+	worker_def * converter;
+	os::String val;
+	os::Control * control = NULL;
+	os::DropdownMenu * drop;
+	vis_window_shown * window = (vis_window_shown *)(inputlist[0]->c.generic.data);
+	name = add_ref(inputlist[1]);
+	value = inputlist[2];
+	inputlist[2] = inputlist[1];
+	
+	DEBUGPUTS("Entering window lock\n");
+	VIS_EnterCriticalSection(window->lock);
+		inputlist[1] = add_ref(window->widget_types);
+		vis_dict_index(inputlist+1, worker_entry);
+		if(inputlist[1])
+		{
+			switch(inputlist[1]->c.integers.num_a)
+			{
+			case BUILTIN_TYPE_INPUTBOX:
+				control = (os::Control *)(window->wind->FindView((char *)(name->c.generic.data)));
+				if(control)
+				{
+					if(value->company->type_id != BUILTIN_TYPE_STRING)
+					{
+						converter = find_converter_method(BUILTIN_TYPE_STRING, value->company->type_id, worker_entry->instance->def->prog);
+						if(!converter)
+						{
+							if(worker_entry->instance) {
+								ERRORPRINTF("Error: Needed conversion from %s to %s for input %d of %s in worker %s\n", value->company->name, worker_entry->instance->def->prog->companylist[BUILTIN_TYPE_STRING].name, 2, "Set Value@Screen Window", worker_entry->instance->def->name);
+							} else {
+								ERRORPRINTF("Error: Needed conversion from %s to %s for input %d of %s\n", value->company->name, worker_entry->instance->def->prog->companylist[BUILTIN_TYPE_STRING].name, 2, "Set Value@Screen Window");
+							}
+							execute_active = FALSE;
+							VIS_PROFILE_END(PROF_PROCESS_WORKER);
+							return -3;
+						}
+						((worker_impl)(converter->implement_func))(&value, worker_entry);
+					}
+					control->SetValue(os::String((char *)(value->c.generic.data)), false);
+				}
+				break;
+			case BUILTIN_TYPE_CHECKBOX:
+				control = (os::Control *)(window->wind->FindView((char *)(name->c.generic.data)));
+				if(control)
+				{
+					if(value->company->type_id != BUILTIN_TYPE_YESNO)
+					{
+						converter = find_converter_method(BUILTIN_TYPE_YESNO, value->company->type_id, worker_entry->instance->def->prog);
+						if(!converter)
+						{
+							if(worker_entry->instance) {
+								ERRORPRINTF("Error: Needed conversion from %s to %s for input %d of %s in worker %s\n", value->company->name, worker_entry->instance->def->prog->companylist[BUILTIN_TYPE_YESNO].name, 2, "Set Value@Screen Window", worker_entry->instance->def->name);
+							} else {
+								ERRORPRINTF("Error: Needed conversion from %s to %s for input %d of %s\n", value->company->name, worker_entry->instance->def->prog->companylist[BUILTIN_TYPE_YESNO].name, 2, "Set Value@Screen Window");
+							}
+							execute_active = FALSE;
+							VIS_PROFILE_END(PROF_PROCESS_WORKER);
+							return -3;
+						}
+						((worker_impl)(converter->implement_func))(&value, worker_entry);
+					}
+					control->SetValue((bool)(value->c.integers.num_a), false);
+				}
+				break;
+			case BUILTIN_TYPE_DROPDOWN:
+				drop = (os::DropdownMenu *)(window->wind->FindView((char *)(name->c.generic.data)));
+				if(drop)
+				{
+					if(value->company->type_id != BUILTIN_TYPE_STRING)
+					{
+						converter = find_converter_method(BUILTIN_TYPE_STRING, value->company->type_id, worker_entry->instance->def->prog);
+						if(!converter)
+						{
+							if(worker_entry->instance) {
+								ERRORPRINTF("Error: Needed conversion from %s to %s for input %d of %s in worker %s\n", value->company->name, worker_entry->instance->def->prog->companylist[BUILTIN_TYPE_STRING].name, 2, "Set Value@Screen Window", worker_entry->instance->def->name);
+							} else {
+								ERRORPRINTF("Error: Needed conversion from %s to %s for input %d of %s\n", value->company->name, worker_entry->instance->def->prog->companylist[BUILTIN_TYPE_STRING].name, 2, "Set Value@Screen Window");
+							}
+							execute_active = FALSE;
+							VIS_PROFILE_END(PROF_PROCESS_WORKER);
+							return -3;
+						}
+						((worker_impl)(converter->implement_func))(&value, worker_entry);
+					}
+					drop->SetCurrentString(os::String((char *)(value->c.generic.data)));
+				}
+				break;
+			default:
+				printf("Unsupported widget type %d for Get Value\n", inputlist[1]->c.integers.num_a);
+				break;
+			}
+		}
+				
+	VIS_LeaveCriticalSection(window->lock);
+
+	release_ref(inputlist[1]);
+	release_ref(value);
+	return 0;
+}
+
+os::Message * handler_widget_to_window(vis_widget * widget, vis_window_shown * window_show, char * handler_name, queue_entry * entry, bool make_message)
+{
+	datum * params[3];
+	params[0] = add_ref(widget->handler_dict);
+	params[1] = make_string(handler_name, -1, entry->instance->def->prog);
+	DEBUGPUTS("Looking up click handler\n");
+	vis_dict_index(params, entry);
+	//if no handler is found, make sure to release output 2
+	if(params[1])
+		release_ref(params[1]);
+	if(params[0] || !make_message)
+	{
+		DEBUGPRINTF("Appending %X to handler list\n", params[0]);
+		params[1] = params[0];
+		params[0] = window_show->handler_list;
+		vis_list_append(params, NULL);
+		window_show->handler_list = params[0];
+		if(make_message)
+			return new os::Message(window_show->next_msg_code++);
+	}
+	return NULL;
+}
+
+void add_widget_shared(vis_window_shown * window_show, datum * widget_datum, char * name, double xpos, double ypos, queue_entry * worker_entry, os::View * parent_view = NULL)
+{
+	datum * index;
+	os::View * widget_view;
+	os::TextView * text_view;
+	os::DropdownMenu * drop_view;
+	os::Message * msg;
+	vis_widget * widget;
+	datum * params[3];
+	params[0] = window_show->widget_types;
+	params[1] = make_string(name, -1, worker_entry->instance->def->prog);
+	params[2] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->prog);
+	params[2]->c.integers.num_a = widget_datum->company->type_id;
+	vis_dict_set(params, worker_entry);
+	window_show->widget_types = params[0];
+	widget = (vis_widget *)(widget_datum->c.generic.data);
+		DEBUGPUTS("Instantiating OS native widget object\n");
+		switch(widget_datum->company->type_id)
+		{
+			case BUILTIN_TYPE_BUTTON:
+				DEBUGPUTS("new os::Button()\n");
+				widget_view = new os::Button(
+					os::Rect(
+						xpos, ypos, 
+						xpos+widget->width, ypos+widget->height
+					), 
+					name, 
+					(char *)(widget->label->c.generic.data), 
+					new os::Message(window_show->next_msg_code++)
+				);
+				/*params[0] = add_ref(widget->handler_dict);
+				params[1] = new_datum(BUILTIN_TYPE_STRING, 1, 6, worker_entry->instance->def->prog);//click
+				strcpy((char *)(params[1]->c.generic.data), "click");
+				DEBUGPUTS("Looking up click handler\n");
+				vis_dict_index(params, worker_entry);
+				if(params[1])
+					release_ref(params[1]);
+				DEBUGPRINTF("Appending %X to handler list\n", params[0]);
+				params[1] = params[0];
+				params[0] = window_show->handler_list;
+				vis_list_append(params, worker_entry);
+				window_show->handler_list = params[0];*/
+				handler_widget_to_window(widget, window_show, "click", worker_entry, false);
+				break;
+			case BUILTIN_TYPE_INPUTBOX:
+				text_view = new os::TextView(
+					os::Rect(
+						xpos, ypos, 
+						xpos+widget->width, ypos+widget->height
+					),
+					name, 
+					(char *)(widget->value->c.generic.data)
+				);
+				switch(widget->flags)
+				{
+				case 1:
+					text_view->SetMultiLine();
+					break;
+				case 2:
+					text_view->SetNumeric(true);
+					break;
+				case 3:
+					text_view->SetPasswordMode();
+					break;
+				case 4:
+					text_view->SetReadOnly();
+					break;
+				default:
+					break;
+				}
+				widget_view = text_view;
+				break;
+			case BUILTIN_TYPE_CUSTOM_WIDGET:
+				DEBUGPUTS("Creating custom widget\n");
+				widget_view = new GenericView(
+					os::Rect(
+						xpos, ypos, 
+						xpos+widget->width, ypos+widget->height
+					),
+					name,
+					add_ref(widget_datum),
+					&(window_show->instance));
+				DEBUGPRINTF("Widget view: %X\n", widget_view);
+				break;
+			case BUILTIN_TYPE_CHECKBOX:
+				widget_view = new os::CheckBox(
+					os::Rect(
+						xpos, ypos,
+						xpos+widget->width, ypos+widget->height
+					),
+					name,
+					(char *)(widget->label->c.generic.data),
+					new os::Message(window_show->next_msg_code++)
+				);
+				handler_widget_to_window(widget, window_show, "click", worker_entry, false);
+				break;
+			case BUILTIN_TYPE_DROPDOWN:
+				drop_view = new os::DropdownMenu(
+					os::Rect(
+						xpos, ypos,
+						xpos+widget->width, ypos+widget->height
+					),
+					name
+				);
+				params[0] = add_ref(widget->label);
+				vis_list_first(params, worker_entry);
+				index = params[0];
+				while(index)
+				{
+					params[1] = add_ref(index);
+					params[0] = add_ref(widget->label);
+					vis_list_index(params, worker_entry);
+					if(params[0] && params[0]->company->type_id == BUILTIN_TYPE_STRING)
+						drop_view->AppendItem((char *)(params[0]->c.generic.data));
+					params[1] = index;
+					params[0] = add_ref(widget->label);
+					vis_list_next(params, worker_entry);
+					index = params[0];
+				}
+				release_ref(params[1]);
+				if(widget->selected_index >= 0)
+					drop_view->SetSelection(widget->selected_index, false);
+				else if(widget->value && widget->value->company->type_id == BUILTIN_TYPE_STRING)
+					drop_view->SetCurrentString((char *)(widget->value->c.generic.data));
+				drop_view->SetSendIntermediateMsg(true);
+				msg = handler_widget_to_window(widget, window_show, "change", worker_entry, true);
+				if(msg)
+					drop_view->SetEditMessage(msg);
+				msg = handler_widget_to_window(widget, window_show, "select", worker_entry, true);
+				if(msg)
+					drop_view->SetSelectionMessage(msg);
+				drop_view->SetTarget(window_show->wind);
+				widget_view = drop_view;
+				break;
+			default:
+				//Do error crap here
+				break;
+		}
+		if(parent_view) {
+			//widget_view->SetFlags(widget_view->GetFlags() | os::WID_TRANSPARENT);
+			parent_view->AddChild(widget_view);
+		} else {
+			DEBUGPUTS("Adding OS native object to window\n");
+			window_show->wind->AddChild(widget_view);
+		}
+	
+}
+
+int vis_window_shown_addwidget(datum ** inputlist, queue_entry * worker_entry)
+{
+	vis_window_shown * window = (vis_window_shown *)(inputlist[0]->c.generic.data);
+	window->wind->Lock();
+	add_widget_shared(window, inputlist[2], (char *)(inputlist[1]->c.generic.data), inputlist[3]->c.real, inputlist[4]->c.real, worker_entry, NULL);
+	window->wind->Unlock();
+	release_ref(inputlist[1]);
+	release_ref(inputlist[2]);
+	release_ref(inputlist[3]);
+	release_ref(inputlist[4]);
+	return 0;
+}
+
+int vis_window_show(datum ** inputlist, queue_entry * worker_entry)
+{
+	vis_window * window = (vis_window *)(inputlist[0]->c.generic.data);
+	vis_window_shown * window_show;
+	list_data * list;
+	int i;
+	datum * params[2];
+	double xpos, ypos;
+	datum * widget_datum;
+	vis_widget * widget;
+	datum * show_datum = new_datum(BUILTIN_TYPE_WINDOW_SHOWN, 1, sizeof(vis_window_shown), worker_entry->instance->def->prog);
+	window_show = (vis_window_shown *)(show_datum->c.generic.data);
+	window_show->title = add_ref(window->title);
+	window_show->width = window->width;
+	window_show->height = window->height;
+	window_show->xpos = inputlist[1]->c.real;
+	release_ref(inputlist[1]);
+	window_show->ypos = inputlist[2]->c.real;
+	release_ref(inputlist[2]);
+	window_show->is_open = TRUE;
+	window_show->wait_entry = NULL;
+	window_show->next_msg_code = 0;
+	window_show->instance.def = worker_entry->instance->def;
+	window_show->widget_types = create_dict(worker_entry->instance->def->prog);
+	
+	check_create_app();
+	VIS_InitializeCriticalSection(window_show->lock);
+	window_show->wind = new os_window(add_ref(show_datum));
+	
+	window_show->handler_list = create_list(worker_entry->instance->def->prog);
+	list = (list_data *)(window->id_list->c.generic.data);
+	for(i = 0; i < list->num_entries; ++i)
+	{
+		DEBUGPRINTF("Retrieving widget %d\n", i);
+		params[0] = add_ref(window->widget_dict);
+		params[1] = add_ref(list->entries[i]);
+		vis_dict_index(params, NULL);
+		widget_datum = params[0];
+		DEBUGPRINTF("Retrieving xpos for widget: %d\n", i);
+		params[0] = add_ref(window->widget_xpos);
+		params[1] = add_ref(list->entries[i]);
+		DEBUGPUTS("Calling vis_dict_index(params, NULL) for xpos\n");
+		vis_dict_index(params, NULL);
+		DEBUGPUTS("After vis_dict_index\n");
+		xpos = params[0]->c.real;
+		DEBUGPUTS("Releasing xpos datum\n");
+		release_ref(params[0]);
+		DEBUGPRINTF("Retrieving ypos for widget: %d\n", i);
+		params[0] = add_ref(window->widget_ypos);
+		params[1] = add_ref(list->entries[i]);
+		DEBUGPUTS("Calling vis_dict_index(params, NULL) for ypos\n");
+		vis_dict_index(params, NULL);
+		DEBUGPUTS("After vis_dict_index\n");
+		ypos = params[0]->c.real;
+		DEBUGPUTS("Releasing ypos datum\n");
+		release_ref(params[0]);
+		add_widget_shared(window_show, widget_datum, (char *)(list->entries[i]->c.generic.data), xpos, ypos, worker_entry, NULL);
+	}
+
+	DEBUGPUTS("Showing window\n");
+	window_show->wind->MakeFocus();
+	window_show->wind->Show();
+	//resume_thread(spawn_thread("vis_mem_check", (void *)vis_mem_check, 1, 0, (void *)window_show));
+	//sleep(5);
+	release_ref(inputlist[0]);
+	inputlist[0] = show_datum;
+	return 0;
+}
+
+
+}
+
+os_window::os_window(datum * vis_wind) : os::Window(
+											os::Rect(
+												((vis_window_shown *)(vis_wind->c.generic.data))->xpos, 
+												((vis_window_shown *)(vis_wind->c.generic.data))->ypos, 
+												((vis_window_shown *)(vis_wind->c.generic.data))->xpos+((vis_window_shown *)(vis_wind->c.generic.data))->width,
+												((vis_window_shown *)(vis_wind->c.generic.data))->ypos+((vis_window_shown *)(vis_wind->c.generic.data))->height), 
+											"vis_wnd", 
+											(char *)(((vis_window_shown *)(vis_wind->c.generic.data))->title->c.generic.data))
+{
+	//DEBUGPRINTF("vis_wind lock: %d\n", ((vis_window_shown *)(vis_wind->c.generic.data))->lock);
+	this->vis_wind = vis_wind;
+//	this->current_focus = NULL;
+}
+os_window::~os_window()
+{
+	vis_window_closed(this->vis_wind);
+}
+
+void empty_callback(worker_instance * caller_instance, int caller_workernum, worker_instance * done_instance, void * data)
+{
+}
+
+void os_window::HandleMessage(os::Message * msg)
+{
+	int returnval;
+	queue_entry entry;
+	datum * params[32];
+	datum * io_list;
+	datum * worker;
+	worker_datum * work;
+	int code = msg->GetCode();
+	DEBUGPRINTF("Message Code: %d\n", code);
+	DEBUGPRINTF("window->wind: %X\n", ((vis_window_shown *)(this->vis_wind->c.generic.data))->wind);
+	DEBUGPRINTF("vis_wind->ref_count: %X\n", this->vis_wind->ref_count);
+	params[0] = add_ref(((vis_window_shown *)(this->vis_wind->c.generic.data))->handler_list);
+	params[1] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, ((vis_window_shown *)(this->vis_wind->c.generic.data))->instance.def->prog);
+	params[1]->c.integers.num_a = code;
+	entry.worker_num = 0;
+		entry.instance = &(((vis_window_shown *)(this->vis_wind->c.generic.data))->instance);
+	vis_list_index(params, &entry);
+	if(params[0] && params[0]->company->type_id == BUILTIN_TYPE_WORKER)
+	{
+		worker = params[0];
+		work = (worker_datum *)(worker->c.generic.data);
+		params[0] = create_list(entry.instance->def->prog);
+		params[1] = add_ref(this->vis_wind);
+		vis_list_append(params, &entry);
+		io_list = params[0];
+		returnval = worker_populate_inputs(worker, io_list, params);
+		if(!returnval)
+			execute_def(work->def, entry, params, empty_callback);
+	}
+	DEBUGPRINTF("window->wind: %X\n", ((vis_window_shown *)(this->vis_wind->c.generic.data))->wind);
+	DEBUGPUTS("End: HandleMessage\n");
+}
+/*
+void os_window::DispatchMessage(os::Message * pcMsg, os::Handler * pcHandler)
+{
+	os::View * view;
+	os::View * handler_view;
+	//int code = pcMsg->GetCode();
+	pcMsg->FindPointer("_widget", (void **)&view);
+	if(view) {
+		handler_view = _FindHandler(view->m_nToken);
+		if(handler_view != view)
+			printf("DispatchMessage, message view: %X, handler view: %X\n", view, handler_view);
+		
+	}
+	os::Window::DispatchMessage(pcMsg, pcHandler);
+}
+
+os::View *os_window::SetFocusNoHandler(os::View * new_focus )
+{
+	ifthis->current_focus)
+		this->current_focus->Activated(false);
+	if(new_focus)
+		new_focus->Activated(true);
+	this->current_focus = new_focus;
+	return new_focus;
+}*/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/syl_window.h	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,66 @@
+#ifndef SYL_WINDOW_H_
+#define SYL_WINDOW_H_
+
+#include "datum.h"
+#include "interp.h"
+#include "vis_threading.h"
+
+#ifdef CPLUSPLUS
+
+#include <gui/window.h>
+
+
+class os_window : public os::Window
+{
+public:
+	os_window(datum * vis_wind);
+	~os_window();
+	void HandleMessage(os::Message * msg);
+//	void DispatchMessage(os::Message * pcMsg, os::Handler * pcHandler);
+//	os::View *SetFocusNoHandler(os::View * new_focus );
+//private:
+//	os::View * current_focus;
+	datum * vis_wind;
+};
+
+
+struct vis_window_shown
+{
+	os_window * wind;
+#else
+typedef struct
+{
+	void * wind;
+#endif
+	VIS_CRITICAL_SECTION(lock)
+	datum * title;
+	double width;
+	double height;
+	double xpos;
+	double ypos;
+	queue_entry * wait_entry;
+	int next_msg_code;
+	datum * handler_list;
+	worker_instance instance;
+	datum * widget_types;
+	BOOL is_open;
+#ifdef CPLUSPLUS
+};
+#else
+} vis_window_shown;
+#endif
+
+#ifdef CPLUSPLUS
+extern "C" {
+void add_widget_shared(vis_window_shown * window_show, datum * widget_datum, char * name, double xpos, double ypos, queue_entry * worker_entry, os::View * parent_view);
+}
+#endif
+
+#endif //SYL_WINDOW_H_
+
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vis_threading.c	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,63 @@
+#ifdef WIN32
+#include "windows.h"
+void VIS_EnterCriticalSectionImpl(short * cs)
+{
+	int tmp = (int)cs;
+	__asm
+	{
+		mov	ebx, tmp
+	CriticalLoop:
+		bts	[ebx], 0
+		jnc	End
+	}
+	Sleep(0);
+	__asm
+	{
+		jmp	CriticalLoop
+	}
+	
+End:
+	return;
+}
+
+#else
+
+#include <unistd.h>
+
+volatile /*inline*/ void VIS_EnterCriticalSectionImpl(short * cs)
+{
+	int code;
+VIS_EnterStart:
+	asm(
+	"movw $1, %%ax\n\t"
+	"xchg %%ax, (%1)\n\t"
+	"test %%ax, %%ax\n\t"
+	"jz VIS_EnterEnd\n\t"
+	"movl $1, %0\n\t"
+	"jmp VIS_EnterCont\n"
+"VIS_EnterEnd:\n\t"
+	"movl $0, %0\n"
+"VIS_EnterCont:":
+	"=r"(code):
+	"r"(cs):
+	"%ax");
+	if(!code)
+		return;
+	sleep(0);
+	goto VIS_EnterStart;
+}
+
+volatile /*inline*/ void VIS_LeaveCriticalSectionImpl(short * cs)
+{
+	asm(
+	"movw $0, %%ax\n\t"
+	"mfence\n\t"
+	"xchg %%ax, (%0)"::
+	"r"(cs):
+	"%ax");
+}
+
+#endif
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vis_threading.h	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,242 @@
+#ifndef	_VIS_THREADING_H_
+#define	_VIS_THREADING_H_
+
+#ifndef COMPILE_THREADS
+#ifdef	NO_THREADS
+#define	COMPILE_THREADS	1
+#else
+#define	COMPILE_THREADS	4
+#endif
+#endif
+
+#if	COMPILE_THREADS > 1
+
+#ifdef WIN32
+
+#include "windows.h"
+/*
+__inline void VIS_EnterCriticalSectionImpl(short * cs)
+{
+	int tmp = (int)cs;
+	__asm
+	{
+		mov	ebx, tmp
+	CriticalLoop:
+		bts	[ebx], 0
+		jnc	End
+	}
+	Sleep(0);
+	__asm
+	{
+		jmp	CriticalLoop
+	}
+	
+End:
+	return;
+}*/
+
+extern int lock_fail_counter;
+extern int lock_counter;
+extern int spin_counter;
+
+volatile __inline void VIS_EnterCriticalSectionImpl(short * cs)
+{
+	int tmp = (int)cs;
+	//int spins = 0;
+	__asm
+	{
+		mov	ebx, tmp
+	CriticalLoop:
+		mov ax, 1
+		xchg ax, [ebx]
+		test ax, ax
+		
+		
+		jz	End
+	}
+	//++spins;
+	Sleep(0);
+	__asm
+	{
+		jmp	CriticalLoop
+	}
+	
+End:
+/*	if(spins > 0)
+	{
+		tmp = (int)(&lock_fail_counter);
+		__asm
+		{
+			mov ebx, tmp
+			lock inc dword ptr [ebx]
+		}
+		tmp = (int)(&spin_counter);
+		__asm
+		{
+			mov ebx, tmp
+			mov eax, spins
+			lock xadd dword ptr [ebx], eax
+		}
+	}
+	tmp = (int)(&lock_counter);
+	__asm
+	{
+		mov ebx, tmp
+		lock inc dword ptr [ebx]
+	}*/
+	return;
+}
+
+volatile __inline void VIS_LeaveCriticalSectionImpl(short * cs)
+{
+	int tmp = (int)cs;
+	__asm
+	{
+		mov	ebx, tmp
+		mov ax, 0
+		xchg ax, [ebx]
+	}
+}
+#else
+/*
+#include <unistd.h>
+
+volatile inline void VIS_EnterCriticalSectionImpl(short * cs)
+{
+	int code;
+VIS_EnterStart:
+	asm(
+	"movw $1, %%ax\n\t"
+	"xchg %%ax, (%1)\n\t"
+	"test %%ax, %%ax\n\t"
+	"jz VIS_EnterEnd\n\t"
+	"movl $1, %0\n\t"
+	"jmp VIS_EnterCont\n"
+"VIS_EnterEnd:\n\t"
+	"movl $0, %0\n"
+"VIS_EnterCont:":
+	"=r"(code):
+	"r"(cs):
+	"%ax");
+	if(!code)
+		return;
+	sleep(0);
+	goto VIS_EnterStart;
+}
+
+volatile inline void VIS_LeaveCriticalSectionImpl(short * cs)
+{
+	asm(
+	"movw $0, %%ax\n\t"
+	"mfence\n\t"
+	"xchg %%ax, (%0)"::
+	"r"(cs):
+	"%ax");
+}*/
+#ifdef CPLUSPLUS
+extern "C" {
+#endif
+volatile void VIS_EnterCriticalSectionImpl(short * cs);
+volatile void VIS_LeaveCriticalSectionImpl(short * cs);
+
+#ifdef CPLUSPLUS
+}
+#endif
+
+#endif //Win32
+
+#ifdef USE_OS_PRIMITIVES
+#ifdef WIN32
+//TODO fill this in
+#else
+#ifdef SYLLABLE
+//TODO fill this in
+#else
+#include <pthread.h>
+#define	VIS_CRITICAL_SECTION(cs)	pthread_mutex_t cs;
+#define VIS_EXTERN_CRITICAL_SECTION(cs)	extern pthread_mutex_t cs;
+#define	VIS_InitializeCriticalSection(cs)	pthread_mutex_init(&(cs), NULL)
+#define VIS_EnterCriticalSection(cs)		pthread_mutex_lock(&(cs))
+#define VIS_LeaveCriticalSection(cs)		pthread_mutex_unlock(&(cs))
+#define	VIS_DeleteCriticalSection(cs)		pthread_mutex_destroy(&(cs))
+#endif //SYLLABLE
+#endif //WIN32
+#else
+#define	VIS_CRITICAL_SECTION(cs)	short cs;//CRITICAL_SECTION cs;//
+#define VIS_EXTERN_CRITICAL_SECTION(cs)	extern short cs;
+#define	VIS_InitializeCriticalSection(cs)	cs = 0
+#define VIS_EnterCriticalSection(cs)		VIS_EnterCriticalSectionImpl(&(cs))
+#define VIS_LeaveCriticalSection(cs)		cs = 0//VIS_LeaveCriticalSectionImpl(&(cs))
+#define	VIS_DeleteCriticalSection(cs)
+#endif/*
+#define	VIS_InitializeCriticalSection(cs)	InitializeCriticalSectionAndSpinCount(&(cs),0x400);
+#define VIS_EnterCriticalSection(cs)		EnterCriticalSection(&(cs))
+#define VIS_LeaveCriticalSection(cs)		LeaveCriticalSection(&(cs))
+#define	VIS_DeleteCriticalSection(cs)		DeleteCriticalSection(&(cs))*/
+
+#ifdef WIN32
+
+#define	VIS_Event(evt)			HANDLE evt;
+#define	VIS_CreateEvent(evt)	evt = CreateEvent(NULL, TRUE, FALSE, NULL)
+#define VIS_DestroyEvent(evt)	CloseHandle(evt)
+#define	VIS_SetEvent(evt)		SetEvent(evt)
+#define	VIS_ResetEvent(evt)		ResetEvent(evt)
+#define	VIS_WaitEvent(evt)		WaitForSingleObject(evt, INFINITE)
+
+#else
+#ifdef SYLLABLE
+//TODO fill this in
+#define	VIS_Event(evt)
+#define	VIS_CreateEvent(evt)
+#define VIS_DestroyEvent(evt)
+#define	VIS_SetEvent(evt)
+#define	VIS_ResetEvent(evt)
+#define	VIS_WaitEvent(evt)	sleep(0)
+#else
+#define	VIS_Event(evt)			pthread_cond_t evt; pthread_mutex_t evt##_mutex;
+#define	VIS_CreateEvent(evt)	pthread_cond_init(&(evt), NULL); pthread_mutex_init(&(evt##_mutex),NULL)
+#define VIS_DestroyEvent(evt)	pthread_cond_destroy(&(evt)); pthread_mutex_destroy(&(evt##_mutex))
+#define	VIS_SetEvent(evt)		pthread_mutex_lock(&(evt##_mutex)); pthread_cond_signal(&(evt)); pthread_mutex_unlock(&evt##_mutex);
+#define VIS_ResetEvent(evt)
+#define	VIS_WaitEvent(evt)		pthread_mutex_lock(&(evt##_mutex)); pthread_cond_wait(&(evt), &(evt##_mutex)); pthread_mutex_unlock(&evt##_mutex)
+#endif //SYLLABLE
+#endif //WIN32
+
+#ifdef WIN32
+	#define VIS_NewThread(func, data)	CreateThread(NULL, 0, func, data, 0, NULL)
+#else
+#ifdef SYLLABLE
+	#define VIS_NewThread(func, data)	resume_thread(spawn_thread("vis_worker", func, 1, 0, data));
+#else
+	#include <pthread.h>
+	pthread_t pid;
+	#define VIS_NewThread(func, data)	pthread_create(&pid, NULL, func, data); 
+#endif
+#endif
+
+#else
+
+#define	VIS_CRITICAL_SECTION(cs)
+#define VIS_EXTERN_CRITICAL_SECTION(cs)
+#define	VIS_InitializeCriticalSection(cs)
+#define VIS_EnterCriticalSection(cs)
+#define VIS_LeaveCriticalSection(cs)
+#define	VIS_DeleteCriticalSection(cs)
+
+#define	VIS_Event(evt)
+#define	VIS_CreateEvent(evt)
+#define VIS_DestroyEvent(evt)
+#define	VIS_SetEvent(evt)
+#define	VIS_WaitEvent(evt)
+#define VIS_ResetEvent(evt)
+#define VIS_NewThread(func, data)
+
+#endif //COMPILE_THREADS > 1
+
+
+#endif //_VIS_THREADING_H_
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visuality.c	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,1302 @@
+
+
+#include <stdio.h>
+#include <math.h>
+
+#include "structs.h"
+#include "visuality.h"
+#include "interp.h"
+#include "parser.h"
+#include "saveload.h"
+
+
+#define	NUM_SPRITES	5
+
+
+FILE * outfile;
+
+
+HGLRC		hRC = NULL;
+HDC			hDC = NULL;
+HWND		hWnd = NULL;
+HINSTANCE	hInstance;
+GLuint	glyph_base;
+
+BOOL mouse_left_down=FALSE;
+BOOL mouse_leftstart_down=FALSE;
+int mouse_lastx;
+int mouse_lasty;
+int mouse_curx;
+int mouse_cury;
+int start_wire_worker=-1;
+int start_wire_ionum=-2;
+BOOL start_wire_isinput;
+BOOL checked_mouse_pos=FALSE;
+
+char new_name_buf[256];
+int buf_size=0;
+
+extern char text_buf[256];
+extern int text_buf_size=0;
+
+extern BOOL execute_active;
+
+worker * view_workerlist;
+wire * view_wirelist;
+
+int current_def=0;
+/*
+void save_program(char * filename)
+{
+	worker * aworkerlist;
+	wire * awirelist;
+	FILE * savefile;
+	int def_num, version = 1;
+	savefile = fopen(filename, "wb");
+	if(!savefile)
+		return;
+	deflist[current_def].num_workers = num_workers;
+	deflist[current_def].num_wires = num_wires;
+	fwrite(&version, 4, 1, savefile);
+	fwrite(&num_defs, 4, 1, savefile);
+	fwrite(deflist, sizeof(worker_def), num_defs, savefile);
+	for(def_num = 0; def_num < num_defs; ++def_num)
+	{
+		if(deflist[def_num].workerlist)
+		{
+			fwrite(&def_num, 4, 1, savefile);
+			//fwrite(&(deflist[def_num].num_workers), 4, 1, savefile);
+			fwrite(deflist[def_num].workerlist, sizeof(worker), deflist[def_num].num_workers, savefile);
+			//fwrite(&(deflist[def_num].num_wires), 4, 1, savefile);
+			fwrite(deflist[def_num].wirelist, sizeof(wire), deflist[def_num].num_wires, savefile);
+		}
+	}
+	def_num = -1;
+	fwrite(&def_num, 4, 1, savefile);
+	fclose(savefile);
+}
+
+void load_program(char * filename)
+{
+	char msg[256];
+	worker * aworkerlist;
+	wire * awirelist;
+	FILE * loadfile;
+	int def_num, version;
+	loadfile = fopen(filename, "rb");
+	if(!loadfile)
+	{
+		MessageBox(NULL, "Could not open file","Error",MB_OK);
+		return;
+	}
+	fread(&version, 4, 1, loadfile);
+	if(version != 1)
+	{
+		MessageBox(NULL, "Can't read files of this version.","Error",MB_OK);
+		return;
+	}
+	fread(&num_defs, 4, 1, loadfile);
+	fread(deflist, sizeof(worker_def), num_defs, loadfile);
+	fread(&def_num, 4, 1, loadfile);
+	while(def_num >= 0 && !feof(loadfile))
+	{
+		sprintf(msg, "Reading def %X at %X", def_num, ftell(loadfile));
+		MessageBox(NULL, msg, "debug",MB_OK);
+		deflist[def_num].workerlist = malloc((deflist[def_num].num_workers+512)*sizeof(worker));
+		fread(deflist[def_num].workerlist, sizeof(worker), deflist[def_num].num_workers, loadfile);
+		deflist[def_num].wirelist = malloc((deflist[def_num].num_wires+1024)*sizeof(wire));
+		fread(deflist[def_num].wirelist, sizeof(wire), deflist[def_num].num_wires, loadfile);
+		deflist[def_num].workers_to_wires_up = malloc((deflist[def_num].num_wires+1024)*sizeof(int));
+		deflist[def_num].workers_to_wires_down = malloc((deflist[def_num].num_wires+1024)*sizeof(int));
+		fread(&def_num, 4, 1, loadfile);
+	}
+	fclose(loadfile);
+	view_workerlist = deflist[0].workerlist;
+	view_wirelist = deflist[0].wirelist;
+	num_workers = deflist[0].num_workers;
+	num_wires = deflist[0].num_wires;
+	initpredefworkers();
+	//sprintf(msg,"%d workers, %d wires in %s",deflist[0].num_workers,deflist[0].num_wires,deflist[0].name);
+	//MessageBox(NULL,msg,"visdbg",MB_OK);
+}*/
+
+
+
+BOOL	keys[256];
+BOOL	active = TRUE;
+BOOL	fullscreen=TRUE;
+BOOL	gameover = FALSE;
+
+GLfloat		xrot;								// X Rotation ( NEW )
+GLfloat		yrot;								// Y Rotation ( NEW )
+GLfloat		zrot;								// Z Rotation ( NEW )
+
+GLuint		texture[NUM_SPRITES];							// Storage For One Texture ( NEW )
+float		xsizes[NUM_SPRITES] = {0.75f, 1.0f, 0.25f, 0.25f, 2.0f};
+float		ysizes[NUM_SPRITES] = {1.0f, 0.5f, 0.25f, 0.25f, 2.0f};
+float		xtexturefit[NUM_SPRITES] = {0.75f, 1.0f, 1.0f, 1.0f, 1.0f};
+float		ytexturefit[NUM_SPRITES] = {1.0f, 1.0f, 1.0f, 1.0f, 1.0f};
+float		gunxpos = 5.0f;
+char	spritenames[NUM_SPRITES][32] = {"rini.bmp", "zapper.bmp", "heart.bmp", "fireball.bmp", "kiss.bmp"};
+
+#define SCREEN_WIDTH_REL	8.8f
+#define SCREEN_HEIGHT_REL	6.6f
+#define PI 3.14159265
+
+int selected_worker = -1;
+int selected_wire = -1;
+
+
+int killed = 0;
+
+
+LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
+	
+
+AUX_RGBImageRec *LoadBMP(char *Filename)					// Loads A Bitmap Image
+{
+	FILE *File=NULL;							// File Handle
+	if (!Filename)								// Make Sure A Filename Was Given
+	{
+		return NULL;							// If Not Return NULL
+	}
+	File=fopen(Filename,"r");						// Check To See If The File Exists
+	if (File)								// Does The File Exist?
+	{
+		fclose(File);							// Close The Handle
+		return auxDIBImageLoad(Filename);				// Load The Bitmap And Return A Pointer
+	}
+	return NULL;								// If Load Failed Return NULL
+}
+/*
+int LoadGLTextures()								// Load Bitmaps And Convert To Textures
+{
+	int Status=FALSE;							// Status Indicator
+	AUX_RGBImageRec *TextureImage[NUM_SPRITES];					// Create Storage Space For The Texture
+	int i;
+	
+
+	for(i = 0; i < NUM_SPRITES; ++i)
+	{
+		
+		TextureImage[i] = NULL;				// Set The Pointer To NULL
+		// Load The Bitmap, Check For Errors, If Bitmap's Not Found Quit
+		if (TextureImage[i]=LoadBMP(spritenames[i]))
+		{
+			Status=TRUE;							// Set The Status To TRUE
+			glGenTextures(1, &texture[i]);					// Create The Texture
+	
+			// Typical Texture Generation Using Data From The Bitmap
+			glBindTexture(GL_TEXTURE_2D, texture[i]);
+			// Generate The Texture
+			glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[i]->sizeX, TextureImage[i]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[i]->data);
+			glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);	// Linear Filtering
+			glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);	// Linear Filtering
+		}
+		if (TextureImage[i])							// If Texture Exists
+		{
+			if (TextureImage[i]->data)					// If Texture Image Exists
+			{
+				free(TextureImage[i]->data);				// Free The Texture Image Memory
+			}
+	
+			free(TextureImage[i]);						// Free The Image Structure
+		}
+		//xsizes[i] = 0.5f;
+		//ysizes[i] = 1.0f;
+	}
+	
+	return Status;								// Return The Status
+}
+
+*/
+
+GLvoid ReSizeGLScene(GLsizei width, GLsizei height)
+{
+	if(height ==0)
+		height = 1;
+	glViewport(0,0,width,height);
+
+	glMatrixMode(GL_PROJECTION);	//Reset projection matrix
+	glLoadIdentity();
+	
+	//Calculate aspect ratio
+	gluPerspective(45.0f, (GLfloat)width/ (GLfloat)height, 0.1f, 100.0f);
+	
+	glMatrixMode(GL_MODELVIEW);
+	glLoadIdentity();				//reset modelview matrix
+}
+
+int InitGL(GLvoid)
+{
+	//if (!LoadGLTextures())							// Jump To Texture Loading Routine ( NEW )
+	//{
+	//	return FALSE;							// If Texture Didn't Load Return FALSE ( NEW )
+	//}
+	HFONT font;
+	glEnable(GL_TEXTURE_2D);
+	glShadeModel(GL_SMOOTH);
+	
+	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);	//blackness
+	
+	glClearDepth(1.0f);
+	glEnable(GL_DEPTH_TEST);
+	glDepthFunc(GL_LEQUAL);
+	
+	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
+
+	glEnable(GL_COLOR_MATERIAL);
+
+
+	
+	font = CreateFont(-24, 0, 0, 0, FW_BOLD, 0, 0, 0, ANSI_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, 
+		ANTIALIASED_QUALITY, FF_SWISS || VARIABLE_PITCH, "Arial");
+	SelectObject(hDC, font);
+
+	glyph_base = glGenLists(224);
+	wglUseFontOutlines(hDC, 32, 224, glyph_base, 0.0, 0.0, WGL_FONT_POLYGONS, NULL);
+	DeleteObject(font);
+	
+	return TRUE;
+}
+
+void drawtriangle(double xpos, double ypos, double width, double height, double angle)
+{
+	if(xpos != 0.0 || ypos != 0.0)
+		glTranslatef(xpos, ypos, 0.0);
+	
+	if(angle != 0.0)
+		glRotatef(angle, 0.0,0.0,1.0);
+		
+	glBegin(GL_TRIANGLES);
+		glVertex2f(0.0, height/2); //Top
+		glVertex2f(0.0 - width/2, 0.0 - height/2); //Left
+		glVertex2f(width/2, 0.0 - height/2); //Right
+	glEnd();		
+		
+	if(angle != 0.0)
+		glRotatef(0.0-angle, 0.0,0.0,1.0);//restore rotation without loading identity
+	if(xpos != 0.0 || ypos != 0.0)
+		glTranslatef(0.0-xpos, 0.0-ypos, 0.0);
+}
+
+void drawrect(double xpos, double ypos, double width, double height, double angle)
+{
+	if(xpos != 0.0 || ypos != 0.0)
+		glTranslatef(xpos, ypos, 0.0);
+	
+	if(angle != 0.0)
+		glRotatef(angle, 0.0,0.0,1.0);
+		
+	glBegin(GL_QUADS);
+		glVertex2f(0.0 - width/2,  height/2.0); //Top Left
+		glVertex2f(width/2, height/2.0); //Top Right
+		glVertex2f(width/2, 0.0 - height/2.0); //Bottom Right
+		glVertex2f(0.0 - width/2, 0.0 - height/2.0); //Bottom Left
+		
+	glEnd();
+		
+	if(angle != 0.0)
+		glRotatef(0.0-angle, 0.0,0.0,1.0);//restore rotation without loading identity
+	if(xpos != 0.0 || ypos != 0.0)
+		glTranslatef(0.0-xpos, 0.0-ypos, 0.0);
+}
+void drawshapestrip(int shape_type, double length, double ypos, double width, double height, int num)
+{
+	double currentpos, spacing;
+	int i;
+	
+	spacing = length/(double)num;
+	currentpos = 0.0 - length/2.0 + spacing/2.0;
+	for(i = 0; i < num; ++i)
+	{
+		if(shape_type == 0)
+			drawtriangle(currentpos, ypos, width, height, 0.0);
+		else
+			drawrect(currentpos, ypos, width, height, 0.0);
+		currentpos += spacing;
+	}
+}
+
+double get_io_xpos(worker * some_worker, int output_num, BOOL is_input)
+{
+	double length, currentpos, spacing;
+	if(is_input && output_num == -1)
+		return some_worker->xpos + some_worker->width/2.0 + INPUT_SIZE/2.0;
+	if(some_worker->type == 2 && is_input) //Trapezoid
+		length = 2.0*(some_worker->width)/3.0;
+	else
+		length = some_worker->width;
+	fprintf(outfile, "Worker length: %f, worker width: %f\n");
+	if(is_input)
+		spacing = length/(some_worker->num_inputs);
+	else
+		spacing = length/(some_worker->num_outputs);
+	currentpos = some_worker->xpos - length/2.0 + spacing/2.0;
+	return currentpos + spacing * (double)output_num;
+}
+
+double get_io_ypos(worker * some_worker, int output_num, BOOL is_input)
+{
+	if(is_input && output_num != -1)
+		return some_worker->ypos + (some_worker->height)/2.0;
+	else
+		return some_worker->ypos - ((some_worker->height)/2.0);
+}
+
+void drawshape(int shape_type, double xpos, double ypos, double width, double height, double angle, int inputs, int outputs, char *text, BOOL selected)
+{
+	double x, y,temp, currentpos, spacing;
+	double *inputx, *inputy, *outputx, *outputy;
+	double ioangle, hypot;
+	int i;
+	glLoadIdentity();
+	glTranslatef(SCREEN_WIDTH_REL / (-2.0f) + xpos, SCREEN_HEIGHT_REL / (-2.0f) + ypos,-8.0f);
+	xpos = 0.0; ypos = 0.0;
+	glRotatef(angle, 0.0,0.0,1.0);
+	if(selected)
+		glColor3f(SELECT_RED, SELECT_GREEN, SELECT_BLUE);
+	else
+		glColor3f(BODY_RED, BODY_GREEN, BODY_BLUE);
+	switch(shape_type)
+	{
+	case 0: //Triangle
+		drawtriangle(0.0, 0.0, width, height, 0.0);
+		glTranslatef(0.0-width/4.0, 0.0-height/4.0,0);
+		
+		break;
+	case 1: //Rectangle
+		drawrect(0.0, 0.0, width, height, angle);
+		glColor3f(INPUT_RED, INPUT_GREEN, INPUT_BLUE);
+		if(inputs)
+			drawshapestrip(0, width, height/2.0 + INPUT_SIZE/2.0,INPUT_SIZE, INPUT_SIZE, inputs);
+		drawtriangle(xpos + width/2.0 + INPUT_SIZE/2.0, ypos-height/2.0+INPUT_SIZE/2.0, INPUT_SIZE, INPUT_SIZE, 0.0);
+		glColor3f(OUTPUT_RED, OUTPUT_GREEN, OUTPUT_BLUE);
+		if(outputs)
+			drawshapestrip(1, width, 0.0-(height/2.0 + OUTPUT_SIZE/2.0),OUTPUT_SIZE, OUTPUT_SIZE, outputs);
+		glTranslatef(0.0-width/2.0 + width/16.0, 0.0-height/3.0, 0.0);
+		
+		break;
+	case 2: //Trapezoid
+		glBegin(GL_QUADS);
+			glVertex2f(xpos - width/3.0 , ypos + height/2.0); //Top Left
+			glVertex2f(xpos + width/3.0, ypos + height/2.0); //Top Right
+			glVertex2f(xpos + width/2.0, ypos - height/2.0); //Bottom Right
+			glVertex2f(xpos - width/2.0, ypos - height/2.0); //Bottom Left
+		glEnd();
+		glColor3f(INPUT_RED, INPUT_GREEN, INPUT_BLUE);
+		if(inputs)
+			drawshapestrip(0, 2.0*(width/3.0), height/2.0 + INPUT_SIZE/2.0,INPUT_SIZE, INPUT_SIZE, inputs);
+		drawtriangle(xpos + width/2.0 + INPUT_SIZE/2.0, ypos-height/2.0+INPUT_SIZE/2.0, INPUT_SIZE, INPUT_SIZE, 0.0);
+		glColor3f(OUTPUT_RED, OUTPUT_GREEN, OUTPUT_BLUE);
+		if(outputs)
+			drawshapestrip(1, width, 0.0-(height/2.0 + OUTPUT_SIZE/2.0),OUTPUT_SIZE, OUTPUT_SIZE, outputs);
+		glTranslatef(0.0-width/3.0, 0.0-height/3.0, 0.0);
+		break;
+		
+	case 3: //Ellipse
+	
+		x = 3.4587;
+		y = 2293.784;
+		
+		glBegin(GL_TRIANGLE_FAN);
+			glVertex2f(0.0, 0.0);
+			
+			if(inputs)
+			{
+				spacing = width/(double)inputs;
+				currentpos = 0.0-width/2.0 + spacing/2.0;
+				inputx = (double *)malloc(inputs*sizeof(double));
+				inputy = (double *)malloc(inputs*sizeof(double));
+				i = 0;
+			}
+			for(x = 0.0-width/2 ; x <= width/2.0+CIRCLE_STEP; x += CIRCLE_STEP)
+			{
+				y = sqrt(fabs(pow(height/2.0,2) - (pow(height/2.0,2)*pow(x, 2))/pow(width/2.0, 2)));
+				glVertex2f(x, y);
+				if(inputs && x >= currentpos)
+				{
+					inputx[i] = x;
+					inputy[i] = y;
+					++i;
+					currentpos += spacing;
+				}
+			}
+			x -= CIRCLE_STEP;
+			while(x >= 0.0-width/2)
+			{
+				y = 0.0-sqrt(fabs(pow(height/2.0,2) - (pow(height/2.0,2)*pow(x, 2))/pow(width/2.0, 2)));
+				glVertex2f(x+xpos, y+ypos);
+				x -= CIRCLE_STEP;
+			}
+				
+		glEnd();
+			
+		glColor3f(INPUT_RED, INPUT_GREEN, INPUT_BLUE);
+		for(i = 0; i < inputs; ++i)
+		{
+			ioangle = atan2(inputy[i], inputx[i]);
+			hypot = sqrt(pow(inputx[i],2) + pow(inputy[i], 2)) + INPUT_SIZE/2;
+			x = hypot * cos(ioangle);
+			y = hypot * sin(ioangle);
+			ioangle *= (180/PI);
+			fprintf(outfile, "oldx: %f, oldy: %f, newx: %f, newy %f, hypot %f, angle %f\n",inputx[i],inputy[i],x,y,hypot, ioangle);
+			drawtriangle(x,y,INPUT_SIZE,INPUT_SIZE, 90-ioangle);
+		}
+		glTranslatef(0.0-width/8.0, 0.0, 0.0);
+		break;
+	default:
+		break;
+	}
+	if(text)
+	{
+		glColor3f(TEXT_RED, TEXT_GREEN, TEXT_BLUE);
+		glPushAttrib(GL_LIST_BIT);
+			glListBase(glyph_base-32);
+		glScalef(0.25,0.25,0.25);
+		
+		glCallLists(strlen(text),GL_UNSIGNED_BYTE, text);
+	
+		glPopAttrib();
+		
+	}
+}
+
+#define INTX_TO_FLOAT_REL(val)	(((double)val)*SCREEN_WIDTH_REL/640.0)
+#define INTY_TO_FLOAT_REL(val)	(((double)val)*SCREEN_HEIGHT_REL/480.0)
+
+//void drawshape(int shape_type, double xpos, double ypos, double width, double height, double angle, int inputs, int outputs)
+int DrawGLScene(GLvoid)
+{
+	double line_startx;
+	double line_starty;
+	double line_endx;
+	double line_endy;
+	double m,b,x,y,mousey;
+	int i,j;
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+	
+	for(i = 0; i < num_workers; ++i)
+	{
+		if(mouse_leftstart_down 
+			&& INTX_TO_FLOAT_REL(mouse_curx) > (view_workerlist[i].xpos - view_workerlist[i].width/2.0) 
+			&& INTX_TO_FLOAT_REL(mouse_curx) < (view_workerlist[i].xpos + view_workerlist[i].width/2.0)
+			&& INTY_TO_FLOAT_REL(mouse_cury) > (view_workerlist[i].ypos - view_workerlist[i].height/2.0) 
+			&& INTY_TO_FLOAT_REL(mouse_cury) < (view_workerlist[i].ypos + view_workerlist[i].height/2.0))
+		{
+			view_workerlist[i].grabbed = TRUE;
+			selected_worker = i;
+			selected_wire = -1;
+			mouse_leftstart_down = FALSE;
+		}
+		else if(mouse_leftstart_down
+			&& INTX_TO_FLOAT_REL(mouse_curx) > (view_workerlist[i].xpos - view_workerlist[i].width/2.0) //Check for mouse in input or output area
+			&& INTX_TO_FLOAT_REL(mouse_curx) < (view_workerlist[i].xpos + view_workerlist[i].width/2.0)
+			&& (INTY_TO_FLOAT_REL(mouse_cury) > (view_workerlist[i].ypos - view_workerlist[i].height/2.0 - OUTPUT_SIZE))
+			&& (INTY_TO_FLOAT_REL(mouse_cury) < (view_workerlist[i].ypos + view_workerlist[i].height/2.0 + INPUT_SIZE)))
+		{
+			if(INTY_TO_FLOAT_REL(mouse_cury) > view_workerlist[i].ypos && view_workerlist[i].num_inputs > 0)//is mouse above or below worker (inputs are above, outputs below)?
+			{
+				fputs("Hit on input region.\n", outfile);
+				for(j = 0; j < view_workerlist[i].num_inputs; ++j)
+				{
+					if(INTX_TO_FLOAT_REL(mouse_curx) > (get_io_xpos(&view_workerlist[i], j, TRUE)-INPUT_SIZE/2.0) && INTX_TO_FLOAT_REL(mouse_curx) < (get_io_xpos(&view_workerlist[i], j, TRUE)+INPUT_SIZE/2.0))
+					{
+						fprintf(outfile, "Hit on input number %d on worker %d.\n", j, i);
+						mouse_leftstart_down = FALSE;
+						if(start_wire_worker >= 0)
+						{
+							fprintf(outfile, "Adding wire %d. output_num: %d, input_num: %d", num_wires,start_wire_ionum, j);
+							//Add wire
+							view_wirelist[num_wires].start_worker = start_wire_worker;
+							view_wirelist[num_wires].end_worker = i;
+							view_wirelist[num_wires].output_num = start_wire_ionum;;
+							view_wirelist[num_wires].input_num = j;
+							++num_wires;
+							start_wire_worker = start_wire_ionum = -1;
+							
+						}
+						else
+						{
+							fputs("Saving information for later wire creation.\n", outfile);
+							start_wire_worker = i;
+							start_wire_ionum = j;
+							start_wire_isinput=TRUE;
+						}
+						break;
+					}
+				}
+			}
+			else if(view_workerlist[i].num_outputs > 0)
+			{
+				fputs("Hit on output region.\n", outfile);
+				for(j = 0; j < view_workerlist[i].num_outputs; ++j)
+				{
+					fprintf(outfile, "Checking mouse x(%f) for hit on output number %d with position %f\n", INTX_TO_FLOAT_REL(mouse_curx), j, get_io_xpos(&view_workerlist[i], j, FALSE));
+					if(INTX_TO_FLOAT_REL(mouse_curx) > (get_io_xpos(&view_workerlist[i], j, FALSE)-OUTPUT_SIZE/2.0) && INTX_TO_FLOAT_REL(mouse_curx) < (get_io_xpos(&view_workerlist[i], j, FALSE)+OUTPUT_SIZE/2.0))
+					{
+						fprintf(outfile, "Hit on output number %d on worker %d.\n", j, i);
+						mouse_leftstart_down = FALSE;
+						if(start_wire_worker >= 0)
+						{
+							fprintf(outfile, "Adding wire %d. output_num: %d, input_num: %d", num_wires, j, start_wire_ionum);
+							//Add wire
+							view_wirelist[num_wires].start_worker = i;
+							view_wirelist[num_wires].end_worker = start_wire_worker;
+							view_wirelist[num_wires].output_num = j;
+							view_wirelist[num_wires].input_num = start_wire_ionum;
+							if(start_wire_ionum == -1)
+								view_workerlist[start_wire_worker].null_input = TRUE;
+							++num_wires;
+							start_wire_worker = start_wire_ionum = -1;
+						}
+						else
+						{
+							fputs("Saving information for later wire creation.\n", outfile);
+							start_wire_worker = i;
+							start_wire_ionum = j;
+							start_wire_isinput=FALSE;
+						}
+						break;
+					}
+				}
+			}
+			
+		}
+		else if(mouse_leftstart_down
+			&& INTX_TO_FLOAT_REL(mouse_curx) > (view_workerlist[i].xpos + view_workerlist[i].width/2.0) //Check for mouse in input or output area
+			&& INTX_TO_FLOAT_REL(mouse_curx) < (view_workerlist[i].xpos + view_workerlist[i].width/2.0+INPUT_SIZE)
+			&& (INTY_TO_FLOAT_REL(mouse_cury) > (view_workerlist[i].ypos - view_workerlist[i].height/2.0))
+			&& (INTY_TO_FLOAT_REL(mouse_cury) < (view_workerlist[i].ypos - view_workerlist[i].height/2.0 + INPUT_SIZE)))
+		{
+			fprintf(outfile, "Click on NULL input at %f,%f\n", INTX_TO_FLOAT_REL(mouse_curx), INTY_TO_FLOAT_REL(mouse_cury));
+			mouse_leftstart_down = FALSE;
+			if(start_wire_worker >= 0)
+			{
+				fprintf(outfile, "Adding wire %d. output_num: %d, input_num: %d", num_wires,start_wire_ionum, -1);
+				//Add wire
+				view_wirelist[num_wires].start_worker = start_wire_worker;
+				view_wirelist[num_wires].end_worker = i;
+				view_wirelist[num_wires].output_num = start_wire_ionum;;
+				view_wirelist[num_wires].input_num = -1;
+				view_workerlist[i].null_input = TRUE;
+				++num_wires;
+				start_wire_worker = start_wire_ionum = -1;
+				
+			}
+			else
+			{
+				fputs("Saving information for later wire creation.\n", outfile);
+				start_wire_worker = i;
+				start_wire_ionum = -1;
+				start_wire_isinput=TRUE;
+			}
+		}
+		else if(mouse_leftstart_down)
+		{
+			fprintf(outfile, "Click at %f,%f, worker at %f,%f with size %f,%f\n", INTX_TO_FLOAT_REL(mouse_curx), INTY_TO_FLOAT_REL(mouse_cury), view_workerlist[i].xpos, view_workerlist[i].ypos, view_workerlist[i].width, view_workerlist[i].height);
+		}
+				
+		if(!mouse_left_down)
+			view_workerlist[i].grabbed= FALSE;
+		if(mouse_left_down && view_workerlist[i].grabbed && (mouse_curx != mouse_lastx || mouse_cury != mouse_lasty))
+		{
+			view_workerlist[i].xpos += INTX_TO_FLOAT_REL(mouse_curx-mouse_lastx);
+			view_workerlist[i].ypos += INTY_TO_FLOAT_REL(mouse_cury-mouse_lasty);
+		}
+		drawshape(view_workerlist[i].display_type, view_workerlist[i].xpos, view_workerlist[i].ypos, view_workerlist[i].width, view_workerlist[i].height, 
+			view_workerlist[i].angle, view_workerlist[i].num_inputs, view_workerlist[i].num_outputs, view_workerlist[i].name, selected_worker==i);
+	}
+	
+
+	glLoadIdentity();
+	glTranslatef(SCREEN_WIDTH_REL / (-2.0f), SCREEN_HEIGHT_REL / (-2.0f),-8.0f);
+
+	glColor3f(WIRE_RED, WIRE_GREEN, WIRE_BLUE);
+	for(i = 0; i < num_wires; ++i)
+	{
+		fprintf(outfile, "Wire %d starts in worker %d at output %d of %d and ends in worker %d at input %d of %d\n", i, view_wirelist[i].start_worker,
+			view_wirelist[i].output_num, view_workerlist[view_wirelist[i].start_worker].num_outputs, view_wirelist[i].end_worker, view_wirelist[i].input_num, view_workerlist[view_wirelist[i].end_worker].num_inputs);
+		line_startx = get_io_xpos(&view_workerlist[view_wirelist[i].start_worker], view_wirelist[i].output_num, FALSE);
+		line_starty = get_io_ypos(&view_workerlist[view_wirelist[i].start_worker], view_wirelist[i].output_num, FALSE)-OUTPUT_SIZE;
+		line_endx = get_io_xpos(&view_workerlist[view_wirelist[i].end_worker], view_wirelist[i].input_num, TRUE);
+		line_endy = get_io_ypos(&view_workerlist[view_wirelist[i].end_worker], view_wirelist[i].input_num, TRUE)+OUTPUT_SIZE;
+		
+		x = INTX_TO_FLOAT_REL(mouse_curx);
+		mousey = INTY_TO_FLOAT_REL(mouse_cury);
+		if(mouse_leftstart_down)
+		{
+			//y = mx=b
+			
+			if(line_startx < line_endx)
+			{
+				if(x >= line_startx && x <= line_endx)
+				{
+					m = (line_endy-line_starty)/(line_endx-line_starty);
+					b = line_starty;
+					x -= line_startx;
+					y = m*x + b;
+					fprintf(outfile, "y: %f, m: %f, x: %f, b: %f, mousey: %f\n", y,m,x,b,mousey);
+					if(mousey >= (y-0.05) && mousey <= (y+0.05))
+					{
+						selected_wire = i;
+						selected_worker = -1;
+					}
+				}
+			} 
+			else if(line_endx > line_startx)
+			{
+				if(x <= line_startx && x >= line_endx)
+				{
+					m = (line_starty-line_endy)/(line_startx-line_endy);
+					b = line_endy;
+					y = m*x + b;
+					x -= line_endx;
+					if(mousey >= (y-0.05) && mousey <= (y+0.05))
+					{
+						selected_wire = i;
+						selected_worker = -1;
+					}
+				}
+			}
+			else	//avoid divide by zero error
+			{
+				if(x >= (line_startx-0.05) && x <= (line_startx+0.05))
+				{
+					if(line_starty > line_endy)
+					{
+						if(mousey >= line_endy && mousey <= line_starty)
+						{
+							selected_wire = i;
+							selected_worker = -1;
+						}
+					}
+					else
+					{
+						if(mousey <= line_endy && mousey >= line_starty)
+						{
+							selected_wire = i;
+							selected_worker = -1;
+						}
+					}
+				}
+			}
+		}
+		if(i == selected_wire)
+			glColor3f(SELECT_RED, SELECT_GREEN, SELECT_BLUE);
+
+		fprintf(outfile, "Start (%f,%f), End (%f, %f), Mouse(%f, %f)\n", line_startx, line_starty, line_endx, line_endy, x, mousey);
+
+		glBegin(GL_QUADS);
+			glVertex2f(line_startx, line_starty);
+			glVertex2f(line_startx+0.1, line_starty);
+			glVertex2f(line_endx+0.1, line_endy);
+			glVertex2f(line_endx, line_endy);
+		glEnd();
+		
+		if(i == selected_wire)
+			glColor3f(WIRE_RED, WIRE_GREEN, WIRE_BLUE);
+	}
+	mouse_leftstart_down = FALSE;
+	//view_workerlist[3].angle += 1.0;
+	checked_mouse_pos=TRUE;
+
+	if(buf_size)
+	{
+		glColor3f(1.0, 1.0, 1.0);
+		glPushAttrib(GL_LIST_BIT);
+		glListBase(glyph_base-32);
+
+		glScalef(0.25,0.25,0.25);
+		
+		glCallLists(buf_size,GL_UNSIGNED_BYTE, new_name_buf);
+	
+		glPopAttrib();
+	}
+/*
+	if(execute_active)
+	{
+		for(i = 0; i < num_workers; ++i)
+			process_worker(i);
+		if(!execute_active)
+		{
+			for(i = 0; i < num_datum; ++i)
+			{
+				if(data[i].type & 0x80)
+					free(data[i].contents);
+			}
+		}
+	}
+*/
+
+	mouse_lastx = mouse_curx;
+	mouse_lasty = mouse_cury;
+
+	return TRUE;
+}
+
+GLvoid KillGLWindow(GLvoid)
+{
+	if(fullscreen)
+	{
+		ChangeDisplaySettings(NULL, 0);
+		ShowCursor(TRUE);
+	}
+	if(hRC)
+	{
+		glDeleteLists(glyph_base, 224);
+		if(!wglMakeCurrent(NULL,NULL))
+			MessageBox(NULL, "Release of DC and RC failed.","SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
+
+		if(!wglDeleteContext(hRC))
+			MessageBox(NULL, "Release Rendering Context Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
+		hRC = NULL;
+		if(hDC && !ReleaseDC(hWnd,hDC))
+		{
+			MessageBox(NULL,"Release Device Context Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
+			hDC = NULL;
+		}
+	}
+		
+	if(hWnd && !DestroyWindow(hWnd))
+	{
+		MessageBox(NULL, "Could not Release hWnd", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
+		hWnd = NULL;
+	}
+	
+	if(!UnregisterClass("OpenGL", hInstance))
+	{
+		MessageBox(NULL, "Could Not Unregister Class.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
+		hInstance=NULL;
+	}
+}
+
+BOOL CreateGLWindow(char * title, int width, int height, int bits, BOOL fullscreenflag)
+{
+	GLuint	PixelFormat;
+	WNDCLASS	wc;
+	DWORD		dwExStyle;
+	DWORD		dwStyle;
+	
+	static	PIXELFORMATDESCRIPTOR pfd=					// pfd Tells Windows How We Want Things To Be
+	{
+		sizeof(PIXELFORMATDESCRIPTOR),					// Size Of This Pixel Format Descriptor
+		1,								// Version Number
+		PFD_DRAW_TO_WINDOW |						// Format Must Support Window
+		PFD_SUPPORT_OPENGL |						// Format Must Support OpenGL
+		PFD_DOUBLEBUFFER,						// Must Support Double Buffering
+		PFD_TYPE_RGBA,							// Request An RGBA Format
+		0,								// Select Our Color Depth
+		0, 0, 0, 0, 0, 0,						// Color Bits Ignored
+		0,								// No Alpha Buffer
+		0,								// Shift Bit Ignored
+		0,								// No Accumulation Buffer
+		0, 0, 0, 0,							// Accumulation Bits Ignored
+		16,								// 16Bit Z-Buffer (Depth Buffer)
+		0,								// No Stencil Buffer
+		0,								// No Auxiliary Buffer
+		PFD_MAIN_PLANE,							// Main Drawing Layer
+		0,								// Reserved
+		0, 0, 0								// Layer Masks Ignored
+	};
+	
+	RECT	WindowRect;
+	WindowRect.left = (long)0;
+	WindowRect.right = (long)width;
+	WindowRect.top = (long)0;
+	WindowRect.bottom=(long)height;
+	
+	fullscreen = fullscreenflag;
+
+	hInstance		= GetModuleHandle(NULL);			// Grab An Instance For Our Window
+	wc.style		= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;		// Redraw On Move, And Own DC For Window
+	wc.lpfnWndProc		= (WNDPROC) WndProc;				// WndProc Handles Messages
+	wc.cbClsExtra		= 0;						// No Extra Window Data
+	wc.cbWndExtra		= 0;						// No Extra Window Data
+	wc.hInstance		= hInstance;					// Set The Instance
+	wc.hIcon		= LoadIcon(NULL, IDI_WINLOGO);			// Load The Default Icon
+	wc.hCursor		= LoadCursor(NULL, IDC_ARROW);			// Load The Arrow Pointer
+	wc.hbrBackground	= NULL;						// No Background Required For GL
+	wc.lpszMenuName		= NULL;						// We Don't Want A Menu
+	wc.lpszClassName	= "OpenGL";					// Set The Class Name
+
+	if (!RegisterClass(&wc))						// Attempt To Register The Window Class
+	{
+		MessageBox(NULL,"Failed To Register The Window Class.","ERROR",MB_OK|MB_ICONEXCLAMATION);
+		return FALSE;							// Exit And Return FALSE
+	}
+
+	if (fullscreen)								// Attempt Fullscreen Mode?
+	{
+		DEVMODE dmScreenSettings;					// Device Mode
+		memset(&dmScreenSettings,0,sizeof(dmScreenSettings));		// Makes Sure Memory's Cleared
+		dmScreenSettings.dmSize=sizeof(dmScreenSettings);		// Size Of The Devmode Structure
+		dmScreenSettings.dmPelsWidth	= width;			// Selected Screen Width
+		dmScreenSettings.dmPelsHeight	= height;			// Selected Screen Height
+		dmScreenSettings.dmBitsPerPel	= bits;				// Selected Bits Per Pixel
+		dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
+		// Try To Set Selected Mode And Get Results.  NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar.
+		if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
+		{
+
+			// If The Mode Fails, Offer Two Options.  Quit Or Run In A Window.
+			if (MessageBox(NULL,"The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?","NeHe GL",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
+			{
+				fullscreen=FALSE;				// Select Windowed Mode (Fullscreen=FALSE)
+			}
+			else
+			{
+
+				// Pop Up A Message Box Letting User Know The Program Is Closing.
+				MessageBox(NULL,"Program Will Now Close.","ERROR",MB_OK|MB_ICONSTOP);
+				return FALSE;					// Exit And Return FALSE
+			}
+		}
+	}
+	if (fullscreen)								// Are We Still In Fullscreen Mode?
+	{
+		dwExStyle=WS_EX_APPWINDOW;					// Window Extended Style
+		dwStyle=WS_POPUP;						// Windows Style
+		ShowCursor(FALSE);						// Hide Mouse Pointer
+	}
+	else
+	{
+
+		dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;			// Window Extended Style
+		dwStyle=WS_OVERLAPPEDWINDOW;					// Windows Style
+	}
+	AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);		// Adjust Window To True Requested Size
+	if (!(hWnd=CreateWindowEx(	dwExStyle,				// Extended Style For The Window
+					"OpenGL",				// Class Name
+					title,					// Window Title
+					WS_CLIPSIBLINGS |			// Required Window Style
+					WS_CLIPCHILDREN |			// Required Window Style
+					dwStyle,				// Selected Window Style
+					0, 0,					// Window Position
+					WindowRect.right-WindowRect.left,	// Calculate Adjusted Window Width
+					WindowRect.bottom-WindowRect.top,	// Calculate Adjusted Window Height
+					NULL,					// No Parent Window
+					NULL,					// No Menu
+					hInstance,				// Instance
+					NULL)))					// Don't Pass Anything To WM_CREATE
+	{
+		KillGLWindow();							// Reset The Display
+		MessageBox(NULL,"Window Creation Error.","ERROR",MB_OK|MB_ICONEXCLAMATION);
+		return FALSE;							// Return FALSE
+	}
+	
+	pfd.cColorBits = bits;
+	
+	if (!(hDC=GetDC(hWnd)))							// Did We Get A Device Context?
+	{
+		KillGLWindow();							// Reset The Display
+		MessageBox(NULL,"Can't Create A GL Device Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
+		return FALSE;							// Return FALSE
+	}
+	if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd)))				// Did Windows Find A Matching Pixel Format?
+	{
+		KillGLWindow();							// Reset The Display
+		MessageBox(NULL,"Can't Find A Suitable PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
+		return FALSE;							// Return FALSE
+	}
+	if(!SetPixelFormat(hDC,PixelFormat,&pfd))				// Are We Able To Set The Pixel Format?
+	{
+		KillGLWindow();							// Reset The Display
+		MessageBox(NULL,"Can't Set The PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
+		return FALSE;							// Return FALSE
+	}
+	if (!(hRC=wglCreateContext(hDC)))					// Are We Able To Get A Rendering Context?
+	{
+		KillGLWindow();							// Reset The Display
+		MessageBox(NULL,"Can't Create A GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
+		return FALSE;							// Return FALSE
+	}
+	if(!wglMakeCurrent(hDC,hRC))						// Try To Activate The Rendering Context
+	{
+		KillGLWindow();							// Reset The Display
+		MessageBox(NULL,"Can't Activate The GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
+		return FALSE;							// Return FALSE
+	}
+	ShowWindow(hWnd,SW_SHOW);						// Show The Window
+	SetForegroundWindow(hWnd);						// Slightly Higher Priority
+	SetFocus(hWnd);								// Sets Keyboard Focus To The Window
+	ReSizeGLScene(width, height);						// Set Up Our Perspective GL Screen
+	if (!InitGL())								// Initialize Our Newly Created GL Window
+	{
+		KillGLWindow();							// Reset The Display
+		MessageBox(NULL,"Initialization Failed.","ERROR",MB_OK|MB_ICONEXCLAMATION);
+		return FALSE;							// Return FALSE
+	}
+	return TRUE;								// Success
+}
+
+LRESULT CALLBACK WndProc(	HWND	hWnd,					// Handle For This Window
+				UINT	uMsg,					// Message For This Window
+				WPARAM	wParam,					// Additional Message Information
+				LPARAM	lParam)					// Additional Message Information
+{
+	int i;
+	worker_def * def;
+	FILE * loadfile;
+	char * code;
+	int size;
+	switch (uMsg)								// Check For Windows Messages
+	{
+
+		case WM_ACTIVATE:						// Watch For Window Activate Message
+		{
+			if (!HIWORD(wParam))					// Check Minimization State
+			{
+				active=TRUE;					// Program Is Active
+			}
+			else
+			{
+				active=FALSE;					// Program Is No Longer Active
+			}
+
+			return 0;						// Return To The Message Loop
+		}
+		case WM_SYSCOMMAND:						// Intercept System Commands
+		{
+			switch (wParam)						// Check System Calls
+			{
+				case SC_SCREENSAVE:				// Screensaver Trying To Start?
+				case SC_MONITORPOWER:				// Monitor Trying To Enter Powersave?
+				return 0;					// Prevent From Happening
+			}
+			break;							// Exit
+		}
+		case WM_CLOSE:							// Did We Receive A Close Message?
+		{
+			PostQuitMessage(0);					// Send A Quit Message
+			return 0;						// Jump Back
+		}
+		case WM_KEYDOWN:						// Is A Key Being Held Down?
+		{
+			if(wParam == VK_BACK && buf_size > 0)
+				--buf_size;
+			else if(wParam == VK_F5 && !execute_active)
+			{
+				deflist[current_def].implement_func->num_workers = num_workers;
+				deflist[current_def].implement_func->num_wires = num_wires;
+				fprintf(outfile, "Starting execution.\n");
+				interp_start(-1,FALSE,0,NULL);
+			}
+			else if(wParam == VK_RETURN && buf_size > 0)
+			{
+				text_buf_size = buf_size;
+				memcpy(text_buf, new_name_buf, buf_size);
+				buf_size = 0;
+				if(memcmp(text_buf, "Save:", strlen("Save:")) == 0)
+				{
+					text_buf[text_buf_size]='\0';
+					deflist[current_def].implement_func->num_workers = num_workers;
+					deflist[current_def].implement_func->num_wires = num_wires;
+					save_program(text_buf + strlen("Save:"));
+					text_buf_size = 0;
+				}
+				else if(memcmp(text_buf, "Load:", strlen("Load:")) == 0)
+				{
+					text_buf[text_buf_size]='\0';
+					load_program(text_buf + strlen("Load:"));
+					view_workerlist = deflist[0].implement_func->workerlist;
+					view_wirelist = deflist[0].implement_func->wirelist;
+					num_workers = deflist[0].implement_func->num_workers;
+					num_wires = deflist[0].implement_func->num_wires;
+					text_buf_size = 0;
+				}
+				else if (memcmp(text_buf, "View:", strlen("View:")) == 0)
+				{
+					text_buf[text_buf_size]='\0';
+					deflist[current_def].implement_func->num_workers = num_workers;
+					deflist[current_def].implement_func->num_wires = num_wires;
+					i = find_worker(text_buf+strlen("View:"), NULL, NULL);
+					if(i < 0)
+						current_def = create_worker(text_buf+strlen("View:"), 0, 0, USER_FLAG | WORKER_TYPE) - deflist;
+					else
+						current_def = i;
+					num_workers = deflist[current_def].implement_func->num_workers;
+					num_wires = deflist[current_def].implement_func->num_wires;
+					view_workerlist = deflist[current_def].implement_func->workerlist;
+					view_wirelist = deflist[current_def].implement_func->wirelist;
+					text_buf_size = 0;
+					selected_worker = -1;
+				}
+				else if(memcmp(text_buf, "Import:", strlen("Import:")) == 0)
+				{
+					deflist[current_def].implement_func->num_workers = num_workers;
+					deflist[current_def].implement_func->num_wires = num_wires;
+					text_buf[text_buf_size]='\0';
+					loadfile = fopen(text_buf+strlen("Import:"), "rb");
+					fseek(loadfile, 0, SEEK_END);
+					size = ftell(loadfile);
+					fseek(loadfile, 0, SEEK_SET);
+					code = malloc(size+1);
+					fread(code, 1, size, loadfile);
+					parse(code, size);
+				}
+			}
+			else if(wParam == VK_DELETE)
+			{
+				if(selected_worker != -1)
+				{
+					for(i = 0; i < num_wires; ++i)
+					{
+						if(view_wirelist[i].start_worker == selected_worker || view_wirelist[i].end_worker == selected_worker)
+						{
+							view_wirelist[i] = view_wirelist[num_wires-1];
+							--num_wires;
+							--i;
+						}
+						
+					}
+					view_workerlist[selected_worker] = view_workerlist[num_workers-1];
+					for(i = 0; i < num_wires; ++i)
+					{
+						if(view_wirelist[i].start_worker == num_workers-1)
+							view_wirelist[i].start_worker = selected_worker;
+						if(view_wirelist[i].end_worker == num_workers-1)
+							view_wirelist[i].end_worker = selected_worker;
+					}
+					--num_workers;
+					selected_worker = -1;
+						
+				}
+			}
+
+
+			keys[wParam] = TRUE;					// If So, Mark It As TRUE
+			return 0;						// Jump Back
+		}
+		case WM_KEYUP:							// Has A Key Been Released?
+		{
+			keys[wParam] = FALSE;					// If So, Mark It As FALSE
+			return 0;						// Jump Back
+		}
+		case WM_SIZE:							// Resize The OpenGL Window
+		{
+			ReSizeGLScene(LOWORD(lParam),HIWORD(lParam));		// LoWord=Width, HiWord=Height
+			return 0;						// Jump Back
+		}
+		case WM_RBUTTONDOWN:
+		{
+			view_workerlist[num_workers].xpos = INTX_TO_FLOAT_REL(GET_X_LPARAM(lParam));
+			view_workerlist[num_workers].ypos = INTY_TO_FLOAT_REL(480-GET_Y_LPARAM(lParam));
+			
+			view_workerlist[num_workers].height = 0.25;
+			view_workerlist[num_workers].grabbed=FALSE;
+			if(buf_size > strlen("Data:") && memcmp("Data:", new_name_buf, strlen("Data:")) == 0)
+			{
+				
+				view_workerlist[num_workers].display_type=1;//Rectangle
+				view_workerlist[num_workers].type=0;//Constant
+				view_workerlist[num_workers].num_inputs=0;//Constants don't have inputs
+				view_workerlist[num_workers].num_outputs=1;//Constants have one output
+				view_workerlist[num_workers].null_input = FALSE;
+				memcpy(view_workerlist[num_workers].name, new_name_buf+strlen("Data:"), buf_size-strlen("Data:"));
+				view_workerlist[num_workers].name[buf_size-strlen("Data:")]='\0';
+				view_workerlist[num_workers].width = ((double)(buf_size-strlen("Data:"))+0.5) * INPUT_SIZE;
+				++num_workers;
+				buf_size = 0;
+			}
+			else if(buf_size > strlen("Room:") && memcmp("Room:", new_name_buf, strlen("Room:")) == 0)
+			{
+				view_workerlist[num_workers].type=1;//Room
+				view_workerlist[num_workers].display_type=1;//Rectangle
+				view_workerlist[num_workers].num_inputs=1;
+				view_workerlist[num_workers].num_outputs=1;
+				view_workerlist[num_workers].null_input = FALSE;
+				memcpy(view_workerlist[num_workers].name, new_name_buf+strlen("Room:"), buf_size-strlen("Room:"));
+				view_workerlist[num_workers].name[buf_size-strlen("Room:")]='\0';
+				view_workerlist[num_workers].width = ((double)(buf_size-strlen("Room:"))+0.5) * INPUT_SIZE;
+				++num_workers;
+				buf_size = 0;
+			}
+			else if(buf_size > strlen("Input:") && memcmp("Input:", new_name_buf, strlen("Input:")) == 0)
+			{
+				deflist[current_def].implement_func->num_workers = num_workers;
+				new_name_buf[buf_size] = '\0';
+				MessageBox(NULL, new_name_buf,"Error",MB_OK);
+				add_input(deflist+current_def, new_name_buf + strlen("Input:"), INTX_TO_FLOAT_REL(GET_X_LPARAM(lParam)), INTY_TO_FLOAT_REL(480-GET_Y_LPARAM(lParam)));
+				num_workers = deflist[current_def].implement_func->num_workers;
+			}
+			else if(buf_size > strlen("Output:") && memcmp("Output:", new_name_buf, strlen("Output:")) == 0)
+			{
+				deflist[current_def].implement_func->num_workers = num_workers;
+				new_name_buf[buf_size] = '\0';
+				add_output(deflist+current_def, new_name_buf + strlen("Output:"), INTX_TO_FLOAT_REL(GET_X_LPARAM(lParam)), INTY_TO_FLOAT_REL(480-GET_Y_LPARAM(lParam)));
+				num_workers = deflist[current_def].implement_func->num_workers;
+			}
+			else if(buf_size > strlen("Express:") && memcmp("Express:", new_name_buf, strlen("Express:")) == 0)
+			{
+				deflist[current_def].implement_func->num_workers = num_workers;
+				new_name_buf[buf_size] = '\0';
+				def = create_worker(new_name_buf+strlen("Express:"), 0, 0, USER_FLAG | WORKER_TYPE);
+				parse_body(def, new_name_buf+strlen("Express:"), buf_size-strlen("Express:"));
+				add_worker_to_def(deflist+current_def, def-deflist, INTX_TO_FLOAT_REL(GET_X_LPARAM(lParam)), INTY_TO_FLOAT_REL(480-GET_Y_LPARAM(lParam)));
+				num_workers = deflist[current_def].implement_func->num_workers;
+				buf_size = 0;
+			}
+			else
+			{
+				memcpy(view_workerlist[num_workers].name, new_name_buf, buf_size);
+				view_workerlist[num_workers].name[buf_size] = '\0';
+				for(i = 0; i < num_defs; ++i)
+				{
+					fprintf(outfile, "Comparing %s with %s(%d)\n", view_workerlist[num_workers].name, deflist[i].name, i);
+					if(strcmp(view_workerlist[num_workers].name, deflist[i].name)==0)
+					{
+						view_workerlist[num_workers].display_type=2;//Trapezoid
+						view_workerlist[num_workers].type=2;//Worker
+						view_workerlist[num_workers].num_inputs=deflist[i].num_inputs;
+						view_workerlist[num_workers].num_outputs=deflist[i].num_outputs;
+						view_workerlist[num_workers].null_input = FALSE;
+						view_workerlist[num_workers].value_index = i;
+						view_workerlist[num_workers].width = ((double)buf_size+0.5) * INPUT_SIZE;
+						
+						++num_workers;
+						buf_size = 0;
+						break;
+					}
+				}
+				if(i >= num_defs)
+				{
+					strcpy(new_name_buf, "I don't know a worker with that name.");
+					buf_size = strlen(new_name_buf);
+				}
+			}
+			if(view_workerlist[num_workers-1].width <= (double)view_workerlist[num_workers-1].num_outputs * OUTPUT_SIZE)
+				view_workerlist[num_workers-1].width = (double)view_workerlist[num_workers-1].num_outputs * (OUTPUT_SIZE*1.1);
+			if(view_workerlist[num_workers-1].width <= (double)view_workerlist[num_workers-1].num_inputs * INPUT_SIZE)
+				view_workerlist[num_workers-1].width = (double)view_workerlist[num_workers-1].num_inputs * (INPUT_SIZE*1.1);
+			
+			
+			break;
+		}
+
+		case WM_LBUTTONDOWN:
+		{
+			mouse_leftstart_down=mouse_left_down=TRUE;
+			mouse_lastx = mouse_curx = GET_X_LPARAM(lParam);
+			mouse_lasty = mouse_cury = 480-GET_Y_LPARAM(lParam);
+			checked_mouse_pos=FALSE;
+			return 0;
+		}
+		case WM_LBUTTONUP:
+		{
+			mouse_leftstart_down=mouse_left_down=FALSE;
+			return 0;
+		}
+		case WM_MOUSEMOVE:
+		{
+			//If no one has checked the mouse position vars, this could cause bugs
+			if(checked_mouse_pos)
+			{
+				mouse_lastx = mouse_curx;
+				mouse_lasty = mouse_cury;
+			}
+			mouse_curx = GET_X_LPARAM(lParam);
+			mouse_cury = 480-GET_Y_LPARAM(lParam);
+			checked_mouse_pos=FALSE;
+			return 0;
+		}
+		case WM_CHAR:
+		{
+			if(wParam >= 0x20)
+			{
+				new_name_buf[buf_size++]=wParam&0xFF;
+			}
+			return 0;
+		}
+			
+	}
+	// Pass All Unhandled Messages To DefWindowProc
+	return DefWindowProc(hWnd,uMsg,wParam,lParam);
+}
+
+VOID CALLBACK DoFrame(HWND myhWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
+{
+	if(active)
+	{
+		DrawGLScene();				// Draw The Scene
+		SwapBuffers(hDC);			// Swap Buffers (Double Buffering)
+	}
+}
+
+int WINAPI WinMain(	HINSTANCE	hInstance,				// Instance
+			HINSTANCE	hPrevInstance,				// Previous Instance
+			LPSTR		lpCmdLine,				// Command Line Parameters
+			int		nCmdShow)				// Window Show State
+{
+	MSG	msg;								// Windows Message Structure
+	BOOL	done=FALSE;							// Bool Variable To Exit Loop
+	// Ask The User Which Screen Mode They Prefer
+	if (MessageBox(NULL,"Would You Like To Run In Fullscreen Mode?", "Start FullScreen?",MB_YESNO|MB_ICONQUESTION)==IDNO)
+	{
+		fullscreen=FALSE;						// Windowed Mode
+	}
+	// Create Our OpenGL Window
+	if (!CreateGLWindow("Visuality",640,480,16,fullscreen))
+	{
+		return 0;							// Quit If Window Was Not Created
+	}
+
+	initworkers();
+	view_workerlist = deflist[0].implement_func->workerlist;
+	view_wirelist = deflist[0].implement_func->wirelist;
+	
+	
+	outfile = fopen("output.txt", "w");
+	
+	SetTimer(hWnd, 1, 17, DoFrame);
+
+	
+	while(!done)								// Loop That Runs Until done=TRUE
+	{
+		if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))			// Is There A Message Waiting?
+		{
+			if (msg.message==WM_QUIT)				// Have We Received A Quit Message?
+			{
+				done=TRUE;					// If So done=TRUE
+			}
+			else							// If Not, Deal With Window Messages
+			{
+				TranslateMessage(&msg);				// Translate The Message
+				DispatchMessage(&msg);				// Dispatch The Message
+			}
+		}
+		// Draw The Scene.  Watch For ESC Key And Quit Messages From DrawGLScene()
+		if (active)						// Program Active?
+		{
+			if (keys[VK_ESCAPE])				// Was ESC Pressed?
+			{
+				done=TRUE;				// ESC Signalled A Quit
+			}
+			else						// Not Time To Quit, Update Screen
+			{
+
+				
+			}
+			
+			if (keys[VK_F1])					// Is F1 Being Pressed?
+			{
+				keys[VK_F1]=FALSE;				// If So Make Key FALSE
+				KillTimer(hWnd, 1);
+				KillGLWindow();					// Kill Our Current Window
+				fullscreen=!fullscreen;				// Toggle Fullscreen / Windowed Mode
+				// Recreate Our OpenGL Window
+				if (!CreateGLWindow("Rini's Love Quest",640,480,16,fullscreen))
+				{
+					return 0;				// Quit If Window Was Not Created
+				}
+				SetTimer(hWnd, 1, 17, DoFrame);
+			}
+		}
+		Sleep(0);
+	}
+	KillTimer(hWnd, 1);
+
+	// Shutdown
+	KillGLWindow();								// Kill The Window
+	return (msg.wParam);							// Exit The Program
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visuality.h	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,47 @@
+#ifndef _VISUALITY_H_
+#define _VISUALITY_H_
+
+#ifdef WIN32
+#include <windows.h>
+#include <Windowsx.h>
+
+//#include <gl\gl.h>
+//#include <gl\glu.h>
+//#include <gl\glaux.h>
+
+#endif
+
+#define CIRCLE_STEP 0.05
+#define INPUT_SIZE 0.20
+#define OUTPUT_SIZE INPUT_SIZE
+
+#define TEXT_RED	0.0
+#define TEXT_BLUE	0.0
+#define TEXT_GREEN	0.0
+
+#define BODY_RED	1.0
+#define BODY_BLUE	1.0
+#define	BODY_GREEN	1.0
+
+#define SELECT_RED	0.7
+#define SELECT_BLUE	0.7
+#define	SELECT_GREEN	0.7
+
+#define	INPUT_RED	0.0
+#define INPUT_BLUE	0.0
+#define	INPUT_GREEN	1.0
+
+#define OUTPUT_RED	1.0
+#define	OUTPUT_BLUE	0.0
+#define	OUTPUT_GREEN 0.0
+
+#define	WIRE_RED	1.0
+#define WIRE_BLUE	1.0
+#define	WIRE_GREEN	1.0
+
+
+
+
+
+#endif //_VISUALITY_H_
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visuality_cmd.c	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,116 @@
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "structs.h"
+#include "visuality.h"
+#include "interp.h"
+#include <time.h>
+#include "parser.h"
+#include "saveload.h"
+
+#ifdef WIN32
+#ifdef GUI_LIB
+#define WIN32_GUI
+#endif
+#endif
+
+extern BOOL execute_active;
+
+extern int num_workers;
+extern int num_wires;
+#ifdef WIN32_GUI
+#include "ms_window.h"
+HINSTANCE glob_instance;
+int glob_cmd_show;
+char prog_name[] = "visuality_cmd";
+int WINAPI WinMain (HINSTANCE instance_handle, HINSTANCE prev_instance, LPSTR cmd_str, int cmd_show)
+{
+	int argc = 1;
+	char * argv[10];
+#else
+int main(int argc, char ** argv)
+{
+#endif //WIN32_GUI
+	int i;
+	char newfile[512];
+	time_t start_time;
+	char * offset;
+	int min_args = 2;
+	int num_threads = -1;
+	BOOL save_flag = FALSE;
+	program * prog;
+#ifdef WIN32_GUI
+	argv[0] = prog_name;
+	argv[1] = cmd_str;
+
+	for(i = 1; cmd_str[i-1] != '\0' && argc < 10; ++i)
+	{
+		if(cmd_str[i] == ' ' || cmd_str[i] == '\0')
+		{
+			cmd_str[i] = '\0';
+			++argc;
+			if(argc < 10)
+				argv[argc] = cmd_str + i+1;
+		}
+	}
+	glob_instance = instance_handle;
+	glob_cmd_show = cmd_show;
+#endif
+	if(argc >= 2)
+		if(strcmp(argv[1],"-t") == 0)
+			min_args += 2;
+		else if(strcmp(argv[1], "-v") == 0)
+		{
+#ifdef TEXT_FILE_DEBUG
+			debugfile = fopen("interp_debug.txt", "w");
+#endif
+			start_time = time(NULL);
+			test_virtual();
+			printf("Execution took %d seconds.\n", (time(NULL)-start_time));
+			return 0;
+		}
+	if(argc >= min_args && !strcmp(argv[min_args-1],"-c"))
+	{
+		min_args+=2;
+		save_flag = TRUE;
+	}
+	
+#ifdef TEXT_FILE_DEBUG
+	debugfile = fopen("interp_debug.txt", "w");
+#endif
+	if(argc < min_args)
+	{
+		min_args = argc;
+		prog = load_program("parser.vistxt");
+	}
+	else
+	{
+		if(min_args > 2)
+			num_threads = atoi(argv[2]);
+		//printf("Loading %s\n", argv[min_args-1]);
+		DEBUGPUTS("load_program\n");
+		if(!strcmp(strrchr(argv[min_args-1],'.')+1, "rhope"))
+		{
+			--min_args;
+			prog = load_program("parser.vistxt");
+		}
+		else
+			prog = load_program(argv[min_args-1]);
+	}
+	start_time = time(NULL);
+	if(save_flag)
+	{
+		save_program(prog, argv[min_args-2]);
+	} 
+	/*#ifdef WIN32
+		interp_start(num_threads,FALSE, argc-(min_args-1), argv + (min_args-1), prog);
+		message_loop();
+	#else*/
+		interp_start(num_threads,TRUE, argc-(min_args-1), argv + (min_args-1), prog);
+	//#endif
+	printf("Execution took %d seconds.\n", (time(NULL)-start_time));
+	return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webserver.rhope	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,116 @@
+Import extendlib.rhope
+
+Get Content Type[path:out]
+{
+	parts <- [path]Split["."]
+	ext <- [parts]Index[ [[parts]Length] - [1] ]
+	If[ [ext] = ["html"] ]
+	{
+		out <- "text/html; charset=ISO-8859-1"
+	}{ 
+		If[ [ext] = ["jpg"] ]
+		{
+			out <- "image/jpeg"
+		}{ 
+			If[ [ext] = ["gif"] ]
+			{
+				out <- "image/gif"
+			}{
+				If[ [ext] = ["css"] ]
+				{
+					out <- "text/css"
+				}{
+					out <- "application/octet-stream"
+				}
+			}
+		}
+	}
+}
+
+HTTP OK[client,type,content length,headers:out]
+{
+	out <- HTTP Response[client, type, content length, headers, "200 OK"]
+}
+
+HTTP Response[client,type,content length,headers,code:out]
+{
+	start headers <- [New@Dictionary[]]Set["Content-Type", type]
+	If[[content length] < [0]]
+	{
+		default headers <- [start headers]Set["Transfer-Encoding", "Chunked"]
+	}{
+		default headers <- [start headers]Set["Content-Length", content length]
+	}
+	
+	out <- [client]Put String@Net Client[
+				[
+					[
+						[
+							["HTTP/1.1 "]Append[code]
+						]Append["\r\n"]
+					]Append[
+						[
+							Combine[headers, default headers]
+						]Key Value Join[": ", "\r\n"]
+					]
+				]Append["\r\n\r\n"]]
+}
+
+HTTP Not Found[client]
+{
+	string <- "<html><head><title>Document Not Found</title></head><body>The document you requested is not available on this server.</body></html>"
+	HTTP Response[client, Get Content Type[".html"], [string]Length, New@Dictionary[], "404 Not Found"]
+	{
+		[~]Put String[string]
+	}
+}
+
+Handle Request[client,type,query,headers,handler]
+{
+	parts <- [query]Split["?"]
+	path <- [parts]Index[0]
+	[[path]Split["/"]]Index[1]
+	{
+		handlerpath <- ["/"]Append[~]
+	}{
+		handlerpath <- "/"
+	}
+	[handler]Index[handlerpath]
+	{
+		If[[[parts]Length] > [1]]
+		{
+			queryvars <- Dict Split[[parts]Index[1], "=", "&"]
+		}{
+			queryvars <- New@Dictionary[]
+		}
+		[~]Do@Worker[ [[[[[New@List[]]Append[client]]Append[path]]Append[type]]Append[queryvars]]Append[headers] ]
+	}{
+
+		,newpath <- [path]Slice[1]
+		file <- <String@File[newpath]
+		content length <- Length[file]
+		If[[content length] > [0]]
+		{
+			junk,data <- [file]Get FString[content length]
+			[HTTP OK[client, Get Content Type[path], content length, New@Dictionary[]]
+			]Put String@Net Client[data]
+		}{
+			HTTP Not Found[client]
+		}
+	}
+	
+}
+
+Connection Start[con,handlers]
+{
+	client, request <- [con]Get DString@Net Client["\r\n"]
+	parts <- [request]Split@String[" "]
+	Print[request]
+	[client]Get DString@Net Client["\r\n\r\n"]
+	{
+		Handle Request[~, [parts]Index@List[0], [parts]Index@List[1], headers, handlers]
+	}{
+		headers <- Map[Dict Split[~, ":", "\r\n"], ["Trim"]Set Input[1, " \t"]]
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webserver.vistxt	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,116 @@
+Import extendlib.vistxt
+
+Get Content Type(1,1)
+|:
+	parts <- [path(0)]Split["."]
+	ext <- [parts]Index[ [[parts]Length] - [1] ]
+	If[ [ext] = ["html"] ]
+	|:
+		out(0) <- "text/html; charset=ISO-8859-1"
+	:||: 
+		If[ [ext] = ["jpg"] ]
+		|:
+			out(0) <- "image/jpeg"
+		:||: 
+			If[ [ext] = ["gif"] ]
+			|:
+				out(0) <- "image/gif"
+			:||:
+				If[ [ext] = ["css"] ]
+				|:
+					out(0) <- "text/css"
+				:||:
+					out(0) <- "application/octet-stream"
+				:|
+			:|
+		:|
+	:|
+:|
+
+HTTP OK(4,1)
+|:
+	out(0) <- HTTP Response[client(0), type(1), content length(2), headers(3), "200 OK"]
+:|
+
+HTTP Response(5,1)
+|:
+	start headers <- [New@Dictionary[]]Set["Content-Type", type(1)]
+	If[[content length(2)] < [0]]
+	|:
+		default headers <- [start headers]Set["Transfer-Encoding", "Chunked"]
+	:||:
+		default headers <- [start headers]Set["Content-Length", content length(2)]
+	:|
+	
+	out(0) <- [client(0)]Put String@Net Client[
+				[
+					[
+						[
+							["HTTP/1.1 "]Append[code(4)]
+						]Append["\r\n"]
+					]Append[
+						[
+							Combine[headers(3), default headers]
+						]Key Value Join[": ", "\r\n"]
+					]
+				]Append["\r\n\r\n"]]
+:|
+
+HTTP Not Found(1,0)
+|:
+	string <- "<html><head><title>Document Not Found</title></head><body>The document you requested is not available on this server.</body></html>"
+	HTTP Response[client(0), Get Content Type[".html"], [string]Length, New@Dictionary[], "404 Not Found"]
+	|:
+		[~]Put String[string]
+	:|
+:|
+
+Handle Request(5,0)
+|:
+	parts <- [query(2)]Split["?"]
+	path <- [parts]Index[0]
+	[[path]Split["/"]]Index[1]
+	|:
+		handlerpath <- ["/"]Append[~]
+	:||:
+		handlerpath <- "/"
+	:|
+	[handler(4)]Index[handlerpath]
+	|:
+		If[[[parts]Length] > [1]]
+		|:
+			queryvars <- Dict Split[[parts]Index[1], "=", "&"]
+		:||:
+			queryvars <- New@Dictionary[]
+		:|
+		[~]Do@Worker[ [[[[[New@List[]]Append[client(0)]]Append[path]]Append[type(1)]]Append[queryvars]]Append[headers(3)] ]
+	:||:
+
+		,newpath <- [path]Slice@String[1]
+		file <- <String@File[newpath]
+		content length <- Length[file]
+		If[[content length] > [0]]
+		|:
+			junk,data <- [file]Get FString[content length]
+			[HTTP OK[client(0), Get Content Type[path], content length, New@Dictionary[]]
+			]Put String@Net Client[data]
+		:||:
+			HTTP Not Found[client(0)]
+		:|
+	:|
+	
+:|
+
+Connection Start(2,0)
+|:
+	client, request <- [con(0)]Get DString@Net Client["\r\n"]
+	parts <- [request]Split@String[" "]
+	Print[request]
+	[client]Get DString@Net Client["\r\n\r\n"]
+	|:
+		Handle Request[~, [parts]Index@List[0], [parts]Index@List[1], headers, handlers(1)]
+	:||:
+		headers <- Map[Dict Split[~, ":", "\r\n"], ["Trim"]Set Input[1, " \t"]]
+	:|
+:|
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/window.c	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,291 @@
+#include <stdlib.h>
+#include <string.h>
+#include "structs.h"
+#include "datum.h"
+#include "interp.h"
+#include "vis_threading.h"
+#include "debugmacros.h"
+
+#ifdef SYLLABLE
+#include "syl_window.h"
+VIS_CRITICAL_SECTION(app_lock);
+#else
+	#ifdef WIN32
+#include "ms_window.h"
+VIS_CRITICAL_SECTION(hwnd_lock);
+	#endif
+#endif
+
+/*
+typedef struct
+{
+	os::Window * wind;
+	int refcount;
+	VIS_CRITICAL_SECTION(lock)
+} os_window;
+
+typedef struct
+{
+	os_window * os_wind;
+	datum * title;
+	double width;
+	double height;
+	double xpos;
+	double ypos;
+} vis_window_shown;*/
+
+void vis_window_init()
+{
+	#ifdef SYLLABLE
+		DEBUGPUTS("Initializing app_lock");
+		
+		VIS_InitializeCriticalSection(app_lock);
+	#else
+		#ifdef WIN32
+			VIS_InitializeCriticalSection(hwnd_lock);
+		#endif
+	#endif
+}
+
+int vis_window_new(datum ** inputlist, queue_entry * worker_entry)
+{
+	vis_window * window;
+	datum * window_datum = new_datum(BUILTIN_TYPE_WINDOW, 1, sizeof(vis_window), worker_entry->instance->def->program);
+	window = (vis_window *)(window_datum->c.generic.data);
+	window->title = inputlist[0];
+	DEBUGPRINTF("Type: %d\n", window->title->company->type_id);
+	DEBUGPRINTF("Length: %d\n", window->title->c.generic.len);
+	window->width = inputlist[1]->c.real;
+	window->height = inputlist[2]->c.real;
+
+	window->widget_dict = create_dict(worker_entry->instance->def->program);
+	window->widget_xpos = create_dict(worker_entry->instance->def->program);
+	window->widget_ypos = create_dict(worker_entry->instance->def->program);
+	window->id_list = create_list(worker_entry->instance->def->program);
+	release_ref(inputlist[1]);
+	release_ref(inputlist[2]);
+	inputlist[0] = window_datum;
+	return 0;
+}
+
+int vis_window_add_widget(datum ** inputlist, queue_entry * worker_entry)
+{
+	datum * params[3];
+	vis_window * window;
+	inputlist[0] = copy_datum(inputlist[0], 0);
+	window = (vis_window *)(inputlist[0]->c.generic.data);
+	DEBUGPRINTF("xpos nodes: %d\n", ((dict_data *)window->widget_xpos->c.generic.data)->num_nodes);
+	params[0] = window->widget_dict;
+	params[1] = add_ref(inputlist[1]);
+	params[2] = inputlist[2];
+	DEBUGPUTS("Adding widget to widget_dict\n");
+	DEBUGPRINTF("xpos nodes: %d\n", ((dict_data *)window->widget_xpos->c.generic.data)->num_nodes);
+	DEBUGPRINTF("widget_dict->datas: %X, xpos->datas: %X\n", window->widget_dict->c.generic.data, window->widget_xpos->c.generic.data);
+	DEBUGPRINTF("sizeof(dict_data): %d, sizeof(ternary_node), %d\n", sizeof(dict_data), sizeof(ternary_node));
+	vis_dict_set(params, NULL);
+	DEBUGPRINTF("xpos nodes: %d\n", ((dict_data *)window->widget_xpos->c.generic.data)->num_nodes);
+	window->widget_dict = params[0];
+	params[0] = window->widget_xpos;
+	params[1] = add_ref(inputlist[1]);
+	params[2] = inputlist[3];
+	DEBUGPUTS("Adding xpos to xpos_dict\n");
+	vis_dict_set(params, NULL);
+	window->widget_xpos = params[0];
+	params[0] = window->widget_ypos;
+	params[1] = add_ref(inputlist[1]);
+	params[2] = inputlist[4];
+	DEBUGPUTS("Adding ypos to ypos_dict\n");
+	vis_dict_set(params, NULL);
+	window->widget_ypos = params[0];
+	params[0] = window->id_list;
+	params[1] = inputlist[1];
+	DEBUGPUTS("Adding id to id list\n");
+	DEBUGPRINTF("xpos nodes: %d\n", ((dict_data *)window->widget_xpos->c.generic.data)->num_nodes);
+	vis_list_append(params, NULL);
+	window->id_list = params[0];
+	return 0;
+}
+
+int vis_window_wait_close(datum ** inputlist, queue_entry * worker_entry)
+{
+	vis_window_shown * window = (vis_window_shown *)(inputlist[0]->c.generic.data);
+	VIS_EnterCriticalSection(window->lock);
+		if(window->is_open && !window->wait_entry)
+		{
+			window->wait_entry = (queue_entry *)malloc(sizeof(queue_entry));
+			memcpy(window->wait_entry, worker_entry, sizeof(queue_entry));
+	VIS_LeaveCriticalSection(window->lock);
+			release_ref(inputlist[0]);
+			return 1;
+		}
+		else
+		{
+	VIS_LeaveCriticalSection(window->lock);
+			release_ref(inputlist[0]);
+			inputlist[0] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, worker_entry->instance->def->program);
+			datum_set_yesno(inputlist[0], DATUM_NO);
+			return 0;
+		}
+}
+
+
+
+void vis_window_closed(datum * window_datum)
+{
+	datum * params[1];
+	queue_entry * temp;
+	vis_window_shown * window = (vis_window_shown *)(window_datum->c.generic.data);
+
+	VIS_EnterCriticalSection(window->lock);
+		window->is_open = FALSE;
+		//window->wind = NULL;
+		temp = window->wait_entry;
+		window->wait_entry = NULL;
+	VIS_LeaveCriticalSection(window->lock);
+	release_ref(window_datum);
+	if(temp)
+	{
+		//TODO send YESNO output
+		params[0] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, temp->instance->def->program);
+		datum_set_yesno(params[0], DATUM_YES);
+		process_outputs(params, temp->worker_num, temp->instance);
+		//worker_complete(*temp);
+		cleanup_check(*temp);
+		free(temp);
+	}
+	
+}
+
+void widget_new(datum ** inputlist, int type, program * prog)
+{
+	vis_widget * widget;
+	datum * output = new_datum(type, 1, sizeof(vis_widget), prog);
+	widget = (vis_widget *)(output->c.generic.data);
+	widget->label = inputlist[0];
+	widget->width = inputlist[1]->c.real;
+	release_ref(inputlist[1]);
+	widget->height = inputlist[2]->c.real;
+	release_ref(inputlist[2]);
+	widget->handler_dict = create_dict(prog);
+	widget->value = NULL;
+	DEBUGPRINTF("widget_new: type = %d, handler_dict = %X\n", type, widget->handler_dict);
+	inputlist[0] = output;
+}
+
+int vis_button_new(datum ** inputlist, queue_entry * worker_entry)
+{
+	widget_new(inputlist, BUILTIN_TYPE_BUTTON, worker_entry->instance->def->program);
+	return 0;
+}
+
+int vis_button_set_handler(datum ** inputlist, queue_entry * workere_entry)
+{
+	vis_widget * widget;
+	datum * params[3];
+	inputlist[0] = copy_datum(inputlist[0], 0);
+	widget = (vis_widget *)(inputlist[0]->c.generic.data);
+	params[0] = widget->handler_dict;
+	params[1] = inputlist[1];
+	params[2] = inputlist[2];
+	//DEBUGPUTS("\n\nvis_button_set_handler vis_dict_set\n");
+	vis_dict_set(params, NULL);
+	DEBUGPUTS("after vis_dict_set\n\n\n");
+	widget->handler_dict = params[0];
+	return 0;
+}
+
+int vis_inputbox_new(datum ** inputlist, queue_entry * worker_entry)
+{
+	vis_widget * widget;
+	datum * output = new_datum(BUILTIN_TYPE_INPUTBOX, 1, sizeof(vis_widget), worker_entry->instance->def->program);
+	widget = (vis_widget *)(output->c.generic.data);
+	widget->value = inputlist[0];
+	widget->width = inputlist[1]->c.real;
+	release_ref(inputlist[1]);
+	widget->height = inputlist[2]->c.real;
+	release_ref(inputlist[2]);
+	widget->label = NULL;
+	widget->handler_dict = NULL;
+	widget->flags = 0;
+	inputlist[0] = output;
+	return 0;
+}
+
+int vis_inputbox_settype(datum ** inputlist, queue_entry * worker_entry)
+{
+	vis_widget * widget;
+	inputlist[0] = copy_datum(inputlist[0], 0);
+	widget = (vis_widget *)(inputlist[0]->c.generic.data);
+	if(!strcmp((char *)(inputlist[1]->c.generic.data), "multiline"))
+		widget->flags = 1;
+	else if(!strcmp((char *)(inputlist[1]->c.generic.data), "numeric"))
+		widget->flags = 2;
+	else if(!strcmp((char *)(inputlist[1]->c.generic.data), "password"))
+		widget->flags = 3;
+	else if(!strcmp((char *)(inputlist[1]->c.generic.data), "read only"))
+		widget->flags = 4;
+	else
+		widget->flags = 0;
+	return 0;
+}
+
+int vis_customwidget_new(datum ** inputlist, queue_entry * worker_entry)
+{
+	widget_new(inputlist, BUILTIN_TYPE_CUSTOM_WIDGET, worker_entry->instance->def->program);
+	return 0;
+}
+
+
+int vis_checkbox_new(datum ** params, queue_entry * entry)
+{
+	vis_widget * widget;
+	widget_new(params, BUILTIN_TYPE_CHECKBOX, entry->instance->def->program);
+	widget = params[0]->c.generic.data;
+	widget->value = params[3];
+	return 0;
+}
+
+int vis_dropdown_new(datum ** params, queue_entry * entry)
+{
+	vis_widget * widget;
+	widget_new(params, BUILTIN_TYPE_DROPDOWN, entry->instance->def->program);
+	widget = params[0]->c.generic.data;
+	widget->selected_index = -1;
+	return 0;
+}
+
+int vis_dropdown_settext(datum ** params, queue_entry * entry)
+{
+	vis_widget * widget;
+	params[0] = copy_datum(params[0], 0);
+	widget = params[0]->c.generic.data;
+	widget->selected_index = -1;
+	release_ref(widget->value);
+	widget->value = params[1];
+	return 0;
+}
+
+int vis_dropdown_select(datum ** params, queue_entry * entry)
+{
+	vis_widget * widget;
+	params[0] = copy_datum(params[0], 0);
+	widget = params[0]->c.generic.data;
+	release_ref(widget->value);
+	widget->value = NULL;
+	widget->selected_index = params[1]->c.integers.num_a;
+	release_ref(params[1]);
+	return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/window_test.c	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,113 @@
+#include <windows.h>
+
+LRESULT CALLBACK WindowProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+	switch (message)
+	{
+	/*	case WM_CREATE:
+			CreateChildControls(hwnd);
+			break;
+
+		case WM_COMMAND:
+			if( HIWORD( wParam ) == BN_CLICKED )
+			{
+				ProcessButtonClick( (char)LOWORD( wParam ) );
+			}
+			break;*/
+
+		case WM_DESTROY:
+			PostQuitMessage (0); 
+			break;
+	}
+	return DefWindowProc (hwnd, message, wParam, lParam);
+}
+char g_szClassName[ ] = "WindowsApp";
+HINSTANCE glob_instance;
+int glob_cmdshow;
+BOOL wind_created=FALSE;
+
+DWORD WINAPI message_thread(void * param)
+{
+	WSADATA wsa_data;
+	/* Define the Window Class and try to register it */
+	WNDCLASSEX wc;
+	HWND hwnd;
+	MSG messages; 
+	wc.cbSize        = sizeof (WNDCLASSEX);
+	wc.style         = 0; 
+	wc.lpfnWndProc   = WindowProc;
+	wc.cbClsExtra    = 0;
+    wc.cbWndExtra    = 0;
+    wc.hInstance     = glob_instance;
+    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
+    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
+	wc.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
+    wc.lpszMenuName  = NULL;
+    wc.lpszClassName = g_szClassName;
+    wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);
+	if (!RegisterClassEx (&wc)) return 0;
+
+	/* Create and Show the Window */
+	hwnd = CreateWindowEx (
+		0, g_szClassName, "The OMGWTF Calculator",
+		WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 
+		220, 270, 
+		HWND_DESKTOP, NULL, glob_instance, NULL);
+	
+	CreateWindow("STATIC", "test", SS_BLACKFRAME | SS_WHITERECT | SS_LEFT,
+		10, 10, 100, 20, hwnd, NULL, GetModuleHandle(NULL), NULL);
+		
+	ShowWindow (hwnd, glob_cmdshow);
+	
+	while (GetMessage (&messages, NULL, 0, 0))
+	{
+		TranslateMessage(&messages);
+		DispatchMessage(&messages);
+	}
+	MessageBox(NULL, "No More messages!", "Blah", MB_OK);
+	wind_created = TRUE;
+	return 0;
+}
+
+int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
+{
+	WSADATA wsa_data;
+	/* Define the Window Class and try to register it */
+	WNDCLASSEX wc;
+	HWND hwnd;
+	MSG messages; 
+	/*wc.cbSize        = sizeof (WNDCLASSEX);
+	wc.style         = 0; 
+	wc.lpfnWndProc   = WindowProc;
+	wc.cbClsExtra    = 0;
+    wc.cbWndExtra    = 0;
+    wc.hInstance     = hInstance;
+    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
+    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
+	wc.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
+    wc.lpszMenuName  = NULL;
+    wc.lpszClassName = g_szClassName;
+    wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);
+	if (!RegisterClassEx (&wc)) return 0;
+
+
+	hwnd = CreateWindowEx (
+		0, g_szClassName, "The OMGWTF Calculator",
+		WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 
+		220, 270, 
+		HWND_DESKTOP, NULL, hInstance, NULL);
+	ShowWindow (hwnd, nCmdShow);*/
+	glob_instance = hInstance;
+	glob_cmdshow = nCmdShow;
+	CreateThread(NULL, 0, message_thread, NULL, 0, NULL);
+	/* Process the Message Loop  */
+	while(!wind_created)
+		Sleep(0);
+	/*while (GetMessage (&messages, NULL, 0, 0))
+	{
+		TranslateMessage(&messages);
+		DispatchMessage(&messages);
+	}*/
+
+	return (int)messages.wParam;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/worker.c	Tue Apr 28 23:06:07 2009 +0000
@@ -0,0 +1,567 @@
+#include "structs.h"
+#include "interp.h"
+#include "datum.h"
+#include "parser.h"
+#include "saveload.h"
+#include <stdlib.h>
+#include <string.h>
+
+int vis_worker_from_string(datum ** inputlist, queue_entry * worker_entry)
+{
+	int i;
+	worker_datum * work;
+	datum * output = new_datum(BUILTIN_TYPE_WORKER, 1, sizeof(worker_datum), worker_entry->instance->def->program);
+	work = output->c.generic.data;
+	find_worker(inputlist[0]->c.generic.data, NULL, NULL, worker_entry->instance->def->program, &work->def);
+	if(work->def)
+		add_program_ref(work->def->program);
+	for(i = 0; i < 32; ++i)
+		work->params[i] = NULL;
+	release_ref(inputlist[0]);
+	inputlist[0] = output;
+	return 0;
+}
+
+BOOL list_to_array(datum * list_dat, datum ** out_params, int num)
+{
+	int i;
+	datum * params[2];
+	list_data * list = list_dat->c.generic.data;
+	if(num > list->num_entries) {
+		return FALSE;
+	}
+	for(i = 0; i < num; ++i)
+		out_params[i] = add_ref(list->entries[i]);
+	release_ref(list_dat);
+	return TRUE;
+}
+
+datum * array_to_list(datum ** in_params, int num, program * prog)
+{
+	int i;
+	datum * params[2];
+	params[0] = create_list(prog);
+	for(i = 0; i < num; ++i)
+	{
+		params[1] = in_params[i];
+		vis_list_append(params, NULL);
+	}
+	return params[0];
+}
+
+int worker_populate_inputs(datum * inputWorker, datum * ioList, datum ** inputlist)
+{
+	int i,j=0;
+	worker_datum * work = inputWorker->c.generic.data;
+	list_data * list = ioList->c.generic.data;
+	for(i = 0; i < work->def->num_inputs; ++i)
+		if(work->params[i])
+		{
+			DEBUGPRINTF("Setting input %d to %X from worker object\n", i, work->params[i]);
+			inputlist[i] = add_ref(work->params[i]);
+		}
+		else
+		{
+			if(j < list->num_entries)
+			{
+				DEBUGPRINTF("Setting input %d to %X from input %d\n", i, list->entries[j], j);
+				inputlist[i] = add_ref(list->entries[j]);
+				++j;
+			}
+			else
+			{
+				ERRORPRINTF("Error: List passed to Do@Worker doesn't have enough entries for worker %s\n", work->def->name);
+				return -1;
+			}
+		}
+	return 0;
+}
+
+int vis_worker_do(datum ** inputlist, queue_entry * worker_entry)
+{
+	//int i,j;
+	worker_datum * work;
+	//worker_def * def;
+	//list_data * list;
+	datum * inputWorker = inputlist[0];
+	datum * ioList = inputlist[1];
+	int returnval;
+	//release_ref(inputlist[0]);
+	work = inputlist[0]->c.generic.data;
+	//list_to_array(inputlist[1], inputlist, work->def->num_inputs);
+	/*list = inputlist[1]->c.generic.data;
+	j = 0;
+	DEBUGPRINTF("vis_worker_do: def_name: %s, num_inputs = %d, list length = %d\n", work->def->name, work->def->num_inputs, list->num_entries);
+	for(i = 0; i < work->def->num_inputs; ++i)
+		if(work->params[i])
+		{
+			DEBUGPRINTF("Setting input %d to %X from worker object\n", i, work->params[i]);
+			inputlist[i] = add_ref(work->params[i]);
+		}
+		else
+		{
+			DEBUGPRINTF("Setting input %d to %X from input %d, company name: %s\n", i, list->entries[j], j, list->entries[j]->company->name);
+			inputlist[i] = add_ref(list->entries[j]);
+			++j;
+		}*/
+	returnval = worker_populate_inputs(inputWorker, ioList, inputlist);
+	release_ref(ioList);
+	if(returnval)
+		return returnval;
+	if(work->def->program != worker_entry->instance->def->program) {
+		prep_program(work->def->program );
+	}
+	returnval = execute_def(work->def, *worker_entry, inputlist, pack_list_sub_callback);
+	if(returnval == 0)
+	{
+		inputlist[0] = array_to_list(inputlist, work->def->num_outputs, worker_entry->instance->def->program);
+		/*vis_list_new(params, NULL);
+		DEBUGPRINTF("params[0] after vis_list_new: %X\n", params[0]);
+		for(i = 0; i < work->def->num_outputs; ++i)
+		{
+			params[1] = inputlist[i];
+			vis_list_append(params, NULL);
+			DEBUGPRINTF("params[0] after vis_list_append: %X\n", params[0]);
+		}
+		inputlist[0] = params[0];*/
+	}
+	release_ref(inputWorker);
+	return returnval;
+}
+
+int vis_worker_setinput(datum ** inputlist, queue_entry * worker_entry)
+{
+	worker_datum * work;
+	inputlist[0] = copy_datum(inputlist[0], 0);
+	work = inputlist[0]->c.generic.data;
+	if(inputlist[1]->c.integers.num_a < 32)
+		work->params[inputlist[1]->c.integers.num_a] = inputlist[2];
+	else
+	{
+		puts("Error: Visuality currently only supports 32 inputs\n");
+		execute_active = FALSE;
+		return -1;
+	}
+	release_ref(inputlist[1]);
+	inputlist[1] = inputlist[2] = NULL;
+	return 0;
+}
+
+int vis_worker_add_worker_call(datum ** inputlist, queue_entry * worker_entry)
+{
+	worker_datum * add_work;
+	worker_datum * work = inputlist[0]->c.generic.data;
+	int index;
+	add_work = inputlist[1]->c.generic.data;
+	/*index = add_work->def - work->def->program->deflist;
+	DEBUGPRINTF("work->def: %X, deflist: %X\n", work->def, worker_entry->instance->def->program->deflist);
+	DEBUGPRINTF("work->def->name: %X\n", work->def->name);*/
+	index = add_worker_to_def(work->def, add_work->def, 1.0, 1.0);
+	release_ref(inputlist[1]);
+	inputlist[1] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program);
+	inputlist[1]->c.integers.num_a = index;
+	return 0;
+}
+
+int vis_worker_add_wire(datum ** inputlist, queue_entry * worker_entry)
+{
+	worker_datum * work = inputlist[0]->c.generic.data;
+	add_wire(work->def, inputlist[1]->c.integers.num_a, inputlist[2]->c.integers.num_a, inputlist[3]->c.integers.num_a, inputlist[4]->c.integers.num_a);
+	release_ref(inputlist[1]);
+	release_ref(inputlist[2]);
+	release_ref(inputlist[3]);
+	release_ref(inputlist[4]);
+	return 0;
+}
+
+void list_change_program(list_data * list, program * new_prog)
+{
+	int i;
+	for(i = 0; i < list->num_entries; ++i)
+	{
+		if(list->entries[i] && list->entries[i]->company->type_id < USER_DEFINED_TYPES)
+		{
+			list->entries[i] = copy_datum(list->entries[i], 0);
+			list->entries[i]->company = new_prog->companylist + list->entries[i]->company->type_id;
+			if(list->entries[i]->company->type_id == BUILTIN_TYPE_LIST)
+				list_change_program(list->entries[i]->c.generic.data, new_prog);
+		}
+	}
+}
+
+int vis_worker_add_constant(datum ** inputlist, queue_entry * worker_entry)
+{
+	datum * constant = inputlist[1];
+	worker_datum * work = inputlist[0]->c.generic.data;
+	int index = add_constant(work->def, "code generated", 1.0, 1.0);
+	if(worker_entry->instance->def->program != work->def->program && constant->company->type_id < USER_DEFINED_TYPES)
+	{
+		constant = copy_datum(constant, 0);
+		constant->company = work->def->program->companylist + constant->company->type_id;
+		if(constant->company->type_id == BUILTIN_TYPE_LIST)
+		{
+			list_change_program(constant->c.generic.data, work->def->program);
+		}
+	}
+	work->def->implement_func->workerlist[index].value_index = constant;
+	inputlist[1] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program);
+	inputlist[1]->c.integers.num_a = index;
+	return 0;
+}
+
+int vis_worker_add_input(datum ** inputlist, queue_entry * worker_entry)
+{
+	worker_datum * work = inputlist[0]->c.generic.data;
+	int index = add_input_num(work->def, inputlist[1]->c.generic.data, inputlist[2]->c.integers.num_a, 1.0, 1.0);
+	release_ref(inputlist[1]);
+	release_ref(inputlist[2]);
+	inputlist[1] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program);
+	inputlist[1]->c.integers.num_a = index;
+	return 0;
+}
+
+int vis_worker_add_output(datum ** inputlist, queue_entry * worker_entry)
+{
+	worker_datum * work = inputlist[0]->c.generic.data;
+	int index = add_output_num(work->def, inputlist[1]->c.generic.data, inputlist[2]->c.integers.num_a, 1.0, 1.0);
+	release_ref(inputlist[1]);
+	release_ref(inputlist[2]);
+	inputlist[1] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program);
+	inputlist[1]->c.integers.num_a = index;
+	return 0;
+}
+
+int vis_worker_add_objectget(datum ** inputlist, queue_entry * worker_entry)
+{
+	worker_datum * work = inputlist[0]->c.generic.data;
+	int index = add_get_comp_room(work->def, inputlist[1]->c.generic.data, 1.0,1.0);
+	release_ref(inputlist[1]);
+	inputlist[1] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program);
+	inputlist[1]->c.integers.num_a = index;
+	return 0;
+}
+
+int vis_worker_add_objectset(datum ** inputlist, queue_entry * worker_entry)
+{
+	worker_datum * work = inputlist[0]->c.generic.data;
+	int index = add_set_comp_room(work->def, inputlist[1]->c.generic.data, 1.0,1.0);
+	release_ref(inputlist[1]);
+	inputlist[1] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program);
+	inputlist[1]->c.integers.num_a = index;
+	return 0;
+}
+
+int vis_worker_add_globalget(datum ** inputlist, queue_entry * worker_entry)
+{
+	worker_datum * work = inputlist[0]->c.generic.data;
+	int index;
+	char * name = malloc(inputlist[1]->c.generic.len + inputlist[2]->c.generic.len + 1);
+	memcpy(name, inputlist[1]->c.generic.data, inputlist[1]->c.generic.len);
+	release_ref(inputlist[1]);
+	strcat(name, "::");
+	strcat(name, inputlist[2]->c.generic.data);
+	release_ref(inputlist[2]);
+	index = add_global_get(work->def, name, 1.0,1.0);
+	free(name);
+	inputlist[1] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program);
+	inputlist[1]->c.integers.num_a = index;
+	return 0;
+}
+
+int vis_worker_add_globalset(datum ** inputlist, queue_entry * worker_entry)
+{
+	worker_datum * work = inputlist[0]->c.generic.data;
+	int index;
+	char * name = malloc(inputlist[1]->c.generic.len + inputlist[2]->c.generic.len + 1);
+	memcpy(name, inputlist[1]->c.generic.data, inputlist[1]->c.generic.len);
+	release_ref(inputlist[1]);
+	strcat(name, "::");
+	strcat(name, inputlist[2]->c.generic.data);
+	release_ref(inputlist[2]);
+	index = add_global_set(work->def, name, 1.0,1.0);
+	free(name);
+	inputlist[1] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program);
+	inputlist[1]->c.integers.num_a = index;
+	return 0;
+}
+
+int vis_worker_new(datum ** inputlist, queue_entry * worker_entry)
+{
+	int i;
+	datum * output = new_datum(BUILTIN_TYPE_WORKER, 1, sizeof(worker_datum), worker_entry->instance->def->program);
+	worker_datum * work = output->c.generic.data;
+	work->def = create_worker(worker_entry->instance->def->program, inputlist[0]->c.generic.data, 0, 0, USER_FLAG | WORKER_TYPE);
+	add_program_ref(work->def->program);
+	for(i = 0; i < 32; ++i)
+		work->params[i] = NULL;
+	release_ref(inputlist[0]);
+	inputlist[0] = output;
+	return 0;
+}
+
+int vis_worker_clear(datum ** inputlist, queue_entry * worker_entry)
+{
+	int i;
+	worker_datum * work = inputlist[0]->c.generic.data;
+	VIS_EnterCriticalSection(work->def->implement_func->lock);
+		for(i = 0; i < work->def->implement_func->num_workers; ++i) {
+			if(work->def->implement_func->workerlist[i].type == CONSTANT) {
+				release_ref(work->def->implement_func->workerlist[i].value_index);
+			}
+		}
+		work->def->num_inputs = 0;
+		work->def->num_outputs = 0;
+		work->def->implement_func->num_workers = 0;
+		work->def->implement_func->num_wires = 0;
+		work->def->implement_func->dirty = TRUE;
+	VIS_LeaveCriticalSection(work->def->implement_func->lock);
+	return 0;
+}
+
+int vis_worker_uses(datum ** inputlist, queue_entry * worker_entry)
+{
+	int i;
+	worker_datum * work = inputlist[0]->c.generic.data;
+	list_data * list = inputlist[1]->c.generic.data;
+	char ** new_uses;
+	if(list->num_entries)
+	{
+		new_uses = malloc(sizeof(char *) * list->num_entries);
+		for(i = 0; i < list->num_entries; ++i) {
+			if(list->entries[i]->company->type_id != BUILTIN_TYPE_STRING) {
+				ERRORPUTS("List passed to Uses@Worker contains non-string value(s)\n");
+				execute_active = FALSE;
+				return -1;
+			}
+			new_uses[i] = malloc(sizeof(char) * list->entries[i]->c.generic.len);
+			memcpy(new_uses[i], list->entries[i]->c.generic.data, list->entries[i]->c.generic.len);
+		}
+	} else
+		new_uses = NULL;
+	if(work->def->uses_stores)
+		free(work->def->uses_stores);
+	work->def->uses_stores = new_uses;
+	work->def->num_stores = list->num_entries;
+	release_ref(inputlist[1]);
+	return 0;
+}
+
+int vis_worker_setio_counts(datum ** inputlist, queue_entry * worker_entry)
+{
+	int i;
+	int new_inputs = inputlist[1]->c.integers.num_a;
+	worker_datum * work = inputlist[0]->c.generic.data;
+	release_ref(inputlist[1]);
+	if(work->def->num_inputs < new_inputs)
+	{
+		work->def->input_types = realloc(work->def->input_types, sizeof(short)*new_inputs);
+		for(i = work->def->num_inputs; i < new_inputs; ++i)
+			work->def->input_types[i] = ANY_TYPE;
+	}
+	work->def->num_inputs = new_inputs;
+	work->def->num_outputs = inputlist[2]->c.integers.num_a;
+	release_ref(inputlist[2]);
+	return 0;
+}
+
+int vis_program_new(datum ** inputlist, queue_entry * worker_entry)
+{
+	program * prog = new_program(START_DEF_STORAGE, START_COMP_STORAGE);
+	inputlist[0] = new_datum(BUILTIN_TYPE_PROGRAM, 2, 0, worker_entry->instance->def->program);
+	inputlist[0]->c.generic.data = prog;
+	inputlist[0]->c.generic.len = sizeof(program);
+	//inputlist[0]->union_type = 1;
+	return 0;
+}
+
+int vis_program_new_worker(datum ** inputlist, queue_entry * worker_entry)
+{
+	int i;
+	datum * output = new_datum(BUILTIN_TYPE_WORKER, 1, sizeof(worker_datum), worker_entry->instance->def->program);
+	worker_datum * work = output->c.generic.data;
+	add_program_ref(inputlist[0]->c.generic.data);
+	work->def = create_worker(inputlist[0]->c.generic.data, inputlist[1]->c.generic.data, 0, 0, USER_FLAG | WORKER_TYPE);
+	for(i = 0; i < 32; ++i)
+		work->params[i] = NULL;
+	release_ref(inputlist[1]);
+	inputlist[1] = output;
+	return 0;
+}
+
+int vis_program_add_worker(datum ** inputlist, queue_entry * worker_entry)
+{
+	int i;
+	worker_datum * work = inputlist[1]->c.generic.data;
+	program * prog = inputlist[0]->c.generic.data;
+	datum * output = new_datum(BUILTIN_TYPE_WORKER, 1, sizeof(worker_datum), worker_entry->instance->def->program);
+	worker_datum * out_work = output->c.generic.data;
+	add_program_ref(inputlist[0]->c.generic.data);
+	out_work->def = create_worker(prog, work->def->name, work->def->num_inputs, work->def->num_outputs, WORKER_TYPE);
+	out_work->def->implement_func = work->def->implement_func;
+	out_work->def->type = work->def->type;
+	if(work->def->type & USER_FLAG)
+		out_work->def->program = work->def->program;
+	for(i = 0; i < work->def->num_inputs; ++i)
+		out_work->def->input_types[i] = out_work->def->input_types[i];
+	release_ref(inputlist[1]);
+	inputlist[1] = output;
+	return 0;
+}
+
+int vis_program_add_builtins(datum ** inputlist, queue_entry * worker_entry)
+{
+	initpredefworkers((program *)inputlist[0]->c.generic.data);
+	return 0;
+}
+
+int vis_program_run(datum ** inputlist, queue_entry * worker_entry)
+{
+	datum * params[32];
+	defchunk * current;
+	int i;
+	program * prog = inputlist[0]->c.generic.data;
+	params[0] = inputlist[1];
+	VIS_EnterCriticalSection(program_count_lock);
+		++program_count;
+	VIS_LeaveCriticalSection(program_count_lock);
+	prep_program(prog);
+	add_program_ref(prog);
+	init_custom_worker(-1, NULL, prog->defs->deflist, main_callback, add_ref(inputlist[0]), params);
+	return 0;
+}
+
+int vis_program_find_worker(datum ** inputlist, queue_entry * worker_entry)
+{
+	int i,returnval;
+	worker_datum * work;
+	worker_def * def;
+	program * prog = inputlist[0]->c.generic.data;
+	returnval = find_worker(inputlist[1]->c.generic.data, NULL, NULL, prog, &def);
+	release_ref(inputlist[0]);
+	if(returnval >= 0)
+	{
+		add_program_ref(prog);
+		release_ref(inputlist[1]);
+		inputlist[0] = new_datum(BUILTIN_TYPE_WORKER, 1, sizeof(worker_datum), worker_entry->instance->def->program);
+		inputlist[1] = NULL;
+		work = inputlist[0]->c.generic.data;
+		work->def = def;
+		for(i = 0; i < 32; ++i)
+			work->params[i] = NULL;
+	} else {
+		inputlist[0] = NULL;
+	}
+	return 0;
+}
+
+void free_worker(worker_def * def)
+{
+	int i;
+	if(def->type & USER_FLAG && (def->type & TYPE_MASK) == WORKER_TYPE)
+	{
+		for(i = 0; i < def->implement_func->num_workers; ++i)
+			if(def->implement_func->workerlist[i].type == CONSTANT)
+				release_ref(def->implement_func->workerlist[i].value_index);
+		free(def->implement_func->workerlist);
+		free(def->implement_func->wirelist);
+		free(def->implement_func->workers_to_wires_up);
+		free(def->implement_func->workers_to_wires_down);
+		free(def->implement_func);
+	}
+	free(def->name);
+	free(def->input_types);
+	free(def->output_types);
+}
+
+void free_company(company * comp)
+{
+	free(comp->methodlist);
+	free(comp->room_list);
+}
+
+void add_program_ref(program * prog)
+{
+	VIS_EnterCriticalSection(prog->lock);
+		++prog->refcount;
+	VIS_LeaveCriticalSection(prog->lock);
+}
+
+void release_program_ref(program * prog)
+{
+	int i;
+	defchunk * current, *temp;
+	VIS_EnterCriticalSection(prog->lock);
+		--prog->refcount;
+	if(!prog->refcount) {
+		VIS_LeaveCriticalSection(prog->lock);
+		VIS_DeleteCriticalSection(prog->lock);
+		current = prog->defs;
+		while(current)
+		{
+			for(i = 0; i < current->num_defs; ++i)
+			{
+				free_worker(current->deflist + i);
+			}
+			current = current->next;
+		}
+		current = prog->defs;
+		while(current)
+		{
+			temp = current;
+			current = current->next;
+			free(temp);
+		}
+		//FIXME: We can't currently free the object definitions because of issues related to global stores
+		//for(i = 0; i < prog->num_companies; ++i)
+		//	free_company(prog->companylist + i);
+		//free(prog->companylist);
+		free(prog);
+	} else {
+		VIS_LeaveCriticalSection(prog->lock);
+	}
+}
+
+/*
+int vis_worker_begin_transaction(datum ** inputlist, queue_entry * worker_entry)
+{
+	worker_def * def;
+	int returnval;
+	datum * params[2];
+	int i;
+	global_store * store;
+	list_data * list = inputist[0]->c.generic.data;
+	transaction * trans = malloc(sizeof(transaction) + list->num_entries - 1);
+	trans->num_stores = list->num_entries;
+	VIS_EnterCriticalSection(global_store_lock);
+		for(i = 0; i < list->num_entries; ++i)
+		{
+			params[0] = global_store_dict;
+			params[1] = add_ref(list->entries[i]);
+			vis_dict_index(params, NULL);
+			store = params[0]->c.generic.data;
+			while(store->inuse)
+			{
+				VIS_LeaveCriticalSection(global_store_lock);
+					#ifdef WIN32
+						Sleep(0);
+					#else
+						sleep(0);
+					#endif
+				VIS_EnterCriticalSection(global_store_lock);
+			}
+			store->inuse;
+			trans->stores[i] = params[0];
+		}
+	VIS_LeaveCriticalSection(global_store_lock;
+	release_ref(inputlist[0]);
+	def = deflist+inputlist[1]->c.integers.num_a;
+	release_ref(inputlist[1]);
+	list_to_array(inputlist[2], inputlist, def->num_inputs);
+	returnval = execute_def_data(def, *worker_entry, inputlist, trasnaction_sub_callback, transaction);
+	if(returnval == 0)
+		inputlist[0] = array_to_list(inputlist, def->num_outputs);
+	return returnval;
+}
+
+*/
+