diff --git a/README.md b/README.md
index f7a5a120cf336de384ecf2e19475a39ebf46f95c..e4788a14578dc58922d956702926b814c5b881d2 100644
--- a/README.md
+++ b/README.md
@@ -16,7 +16,12 @@ This project serves the developement environment / api we use to write and repre
 ## For MW
 
  - fundament
+  - the basic unit is a .js file having inputs, outputs, and state objects 
+  - we can compose programs of these modules, being collections of them with connections 
+  - we can represent these programs heirarchically, or in a flat manner ... heirarchy just requires an extra wrap, we do it later
+  
   - load / save programs (req. prgmem representation) 
+  - rewrite ui & transfers to use this rep. 
  - UI 
   - title bar descr. how to operate
   - 'L' for load, 'M' for new module, type for module search ?
@@ -39,7 +44,7 @@ Also
 
 Modules-that-represent-remote-computing also have
  Ports
- that connect to 
+ that connect to a
  Link 
 
 To assemble a representation of these, we want to have a kind of 'netlist' that, for convenience, we'll treat like a JSON object. We want heirarchy, so consider the representation having 'top-level' outputs / inputs / state as well ? 
diff --git a/lib/inout.js b/lib/inout.js
deleted file mode 100644
index f994d9e13e162ab0353ce458a469359d0df9970e..0000000000000000000000000000000000000000
--- a/lib/inout.js
+++ /dev/null
@@ -1,141 +0,0 @@
-// event system to include type-checking etc
-
-function Input(type, fn){
-	var input = {
-		accepts: type,
-		fn: fn
-	}
-
-	return input
-}
-
-function Output(type){
-	var output = {
-		emits: type
-	}
-
-	output.calls = new Array()
-
-	output.attach = function(input){
-		this.calls.push(input)
-	}
-
-	output.isLinked = function(input){
-		// return true if already hooked up 
-		if(this.calls.includes(input)){
-			return true 
-		} else {
-			return false 
-		}
-	}
-
-	output.remove = function(input){
-		if(!this.isLinked(input)){
-			console.log('attempt to rm input that is not attached')
-			return false 
-		} else {
-			this.calls.splice(this.calls.indexOf(input), 1)
-		}
-	}
-
-	output.emit = function(data){
-		if(this.calls.length == 0){
-			console.log('no inputs bound to this output')
-		} else {
-			for(index in this.calls){
-				this.calls[index].fn(JSON.parse(JSON.stringify(data)))
-			}
-		}
-	}
-
-	return output
-}
-
-function State(){
-	var state = {
-	}
-
-	state.emitters = {}
-
-	state.onChange = function(item, fn){
-		this.emitters[item] = fn
-		//console.log('ADD STATE CHANGE EMITTER', this.emitters)
-	}
-
-	state.emitChange = function(item){
-		//console.log('EMIT CHANGE FOR', item)
-		if(this.emitters[item] != null){
-			this.emitters[item]()
-		}
-	}
-
-	return state
-}
-
-// within state ... or not ? 
-function Button(label){
-	var button = {
-		isButton: true,
-		isPressed: false,
-		label: label
-	}
-
-	return button 
-}
-
-// now we're definitely writing a UI class 
-function MultiLine(label, rows){
-	var ml = {
-		isMultiLine: true,
-		label: label,
-		rows: rows,
-		value: ' - '
-	}
-
-	return ml
-}
-
-module.exports = {
-	Input: Input,
-	Output: Output,
-	State: State,
-	Button: Button,
-	MultiLine: MultiLine
-}
-
-/*
-prjRep = {
-	connectivity: [
-			{id: 1, thisOutput: ['2:thisInput', '4:thatInput'], thatOutput: [etc]},
-			{id: 2, thatOutput: ['2:thisInput', '4:thatInput']}
-	], 
-	states: [
-		{id: 1, state: {
-			//
-		}}
-	},
-	positions: [
-		{id: 1, posX: 12, posY: 15}
-	]
-}
-*/
-
-
-/*
-more like
-
-modules = [
-	Class {
-		state: object,
-		inputs: object,
-		outputs: object, // walk this for connectivity - how to set that up?
-	} 
-]
-
-reps = [
-	object {
-		posX: num,
-		posY: num
-	}
-]
-*/
\ No newline at end of file
diff --git a/lib/jsunit.js b/lib/jsunit.js
new file mode 100644
index 0000000000000000000000000000000000000000..324ff7c5bb12702d084a7bb6bb07748ee2538956
--- /dev/null
+++ b/lib/jsunit.js
@@ -0,0 +1,104 @@
+// event system to include type-checking etc
+// dataflow types for javascript objects ... 
+
+function Input(type, fn) {
+    var input = {
+        accepts: type,
+        fn: fn
+    }
+
+    return input
+}
+
+function Output(type) {
+    var output = {
+        emits: type
+    }
+
+    output.calls = new Array()
+
+    output.attach = function(input) {
+        this.calls.push(input)
+    }
+
+    output.isLinked = function(input) {
+        // return true if already hooked up 
+        if (this.calls.includes(input)) {
+            return true
+        } else {
+            return false
+        }
+    }
+
+    output.remove = function(input) {
+        if (!this.isLinked(input)) {
+            console.log('attempt to rm input that is not attached')
+            return false
+        } else {
+            this.calls.splice(this.calls.indexOf(input), 1)
+        }
+    }
+
+    output.emit = function(data) {
+        if (this.calls.length == 0) {
+            console.log('no inputs bound to this output')
+        } else {
+            for (index in this.calls) {
+                this.calls[index].fn(JSON.parse(JSON.stringify(data)))
+            }
+        }
+    }
+
+    return output
+}
+
+function State() {
+    var state = {}
+
+    state.emitters = {}
+
+    state.onChange = function(item, fn) {
+        this.emitters[item] = fn
+        //console.log('ADD STATE CHANGE EMITTER', this.emitters)
+    }
+
+    state.emitChange = function(item) {
+        //console.log('EMIT CHANGE FOR', item)
+        if (this.emitters[item] != null) {
+            this.emitters[item]()
+        }
+    }
+
+    return state
+}
+
+// within state ... or not ? 
+function Button(label) {
+    var button = {
+        isButton: true,
+        isPressed: false,
+        label: label
+    }
+
+    return button
+}
+
+// now we're definitely writing a UI class 
+function MultiLine(label, rows) {
+    var ml = {
+        isMultiLine: true,
+        label: label,
+        rows: rows,
+        value: ' - '
+    }
+
+    return ml
+}
+
+module.exports = {
+    Input: Input,
+    Output: Output,
+    State: State,
+    Button: Button,
+    MultiLine: MultiLine
+}
\ No newline at end of file
diff --git a/server.js b/nnc.js
similarity index 62%
rename from server.js
rename to nnc.js
index e5f901747a9f19482a7e29c089321e0fdb6ece00..9f25315978801c7002ed71f3b68107d6bda51261 100644
--- a/server.js
+++ b/nnc.js
@@ -1,5 +1,6 @@
 //
-// server.js
+// nnc.js
+//
 //
 // Jake Read at the Center for Bits and Atoms
 // (c) Massachusetts Institute of Technology 2018
@@ -134,129 +135,216 @@ PROGRAM AS API
 ------------------------------------------------------
 */
 
-var modules = new Array()
+// nodes are objects having inputs, outputs, and state
+// nodes can be made up of other nodes 
+// a node originates somewhere, 
 
-// a program is a list of modules, 
-// modules have internal lists of modules that they call 
+// is it a JSON, or a txt .js file ? loadProgram and loadModule ...
+// it wants to be an object that gets 'read' in ... 
 
-var prgmem = {
-    // we want to describe all of the nodes first,
-    // then we can add connections once we have hooks 
-    // to each of them 
-    modules: {
-        gate: {
-            path: './src/util/gate.js',
-            conn: {
-                
-            }
-            ui:{
-                pos: [100, 100]
-            }
-        },
-        delay: {
-            path: './src/util/delay.js',
-            state: {
-                ms: 500
-            }
-        },
-        log: {
-            path: './src/util.log.js'
-        }
+var program = {
+    description: {
+        name: 'tstprgmem',
     },
-    connections: ['gate.outputs.out', 'delay.inputs.thru']
+    modules: new Array()
 }
 
-function loadPrgmem(desc) {
-    console.log(desc)
-}
+// add things
 
-loadPrgmem(prgmem)
+var gate = addModuleToProgram(program, './src/util/gate.js')
+var delay = addModuleToProgram(program, './src/util/delay.js')
+var log = addModuleToProgram(program, './src/util/log.js')
 
-/*
-------------------------------------------------------
-LOST FUNCTION
-------------------------------------------------------
-*/
+// hookup as usual 
+
+gate.outputs.out.attach(delay.inputs.thru)
+delay.outputs.out.attach(log.inputs.thru)
+gate.outputs.out.attach(log.inputs.thru)
+
+saveProgram(program, 'save/onesave.json')
+
+program = null 
+delete gate 
+delete delay
+delete log 
+
+console.log('PROGRAM', program)
+
+var prgmem = openProgram('save/onesave.json')
+
+saveProgram(prgmem, 'save/twosave.json')
 
-function setUiPos(module, left, top) {
-    if (module.ui == null) {
-        module.ui = {}
-    }
-    module.ui.left = left
-    module.ui.top = top
-}
 
 /*
 ------------------------------------------------------
-PROGRAM WRITING 
+PROGRAM ASSEMBLY 
 ------------------------------------------------------
 */
 
-function addModule(path) {
-    // get and add to server system
+function addModuleToProgram(program, path) {
+    // program is an object seeking heirarchy, has program.modules 
     if (fs.existsSync(path)) {
-        var src = require(path) // get and return 
-        var mod = new src() // make a new one
-        modules.push(mod) // add to the system
-
-        // assign and id and remember from whence it came
-        mod.id = modules.length - 1
-        mod.path = path
-
-        // we need to add some top-level info to the inputs so that we can draw them 
-        for (item in mod.inputs) {
-            mod.inputs[item].parentId = mod.id
-            mod.inputs[item].key = item
+        var src = require(path)
+        var mod = new src()
+
+        // add to list
+        program.modules.push(mod)
+        // make unique name 
+        mod.description.id = mod.description.name + '-' + program.modules.length
+        mod.description.path = path
+
+        // input need references for later hookup
+        for (key in mod.inputs) {
+            mod.inputs[key].parentId = mod.description.id
+            mod.inputs[key].key = key
         }
 
-        for (item in mod.state) {
-            if (item == 'onChange' | item == 'emitChange' | item == 'emitters') {
+        // state updating, begs for update 
+        for (key in mod.state) {
+            if (key == 'onChange' | key == 'emitChange' | key == 'emitters') {
                 //console.log('rolling past change fn')
             } else {
-                mod.state['_' + item] = mod.state[item]
-                mod.state[item] = {}
-                writeStateObject(mod, item)
+                mod.state['_' + key] = mod.state[key]
+                mod.state[key] = {}
+                writeStateObject(mod, key)
             }
         }
 
-        console.log('ADDING MODULE', mod.description.name)
+        if (program.description.id == null) {
+            if (program.description.name == null) {
+                if (program.description == null) {
+                    program.description = {}
+                }
+                program.description.name = 'unnamed program'
+            }
+            program.description.id = program.description.name + '-' + 0
+        }
 
-        // now roll and return representable object 
-        // first to UI
-        putRep(mod)
-        // also to fn call, in case writing program ? 
+        console.log('ADDING', mod.description.id, 'to', program.description.id)
+        // also return it so that we can write programs without the UI 
         return mod
     } else {
-        console.log('ERR no module found at', path)
+        console.log('ERR no module found at ', path)
     }
 }
 
-function writeStateObject(mod, item) {
-    Object.defineProperty(mod.state, item, {
+function writeStateObject(mod, key) {
+    Object.defineProperty(mod.state, key, {
         set: function(x) {
             // update internal value 
-            this['_' + item] = x
-            //console.log('SET', item, this['_' + item])
+            this['_' + key] = x
+            //console.log('SET', key, this['_' + key])
             // push to internal state change handler
-            this.emitChange(item)
+            this.emitChange(key)
             // update server (or in some cases, a confirmation)
             putState(mod)
         }
     })
-    Object.defineProperty(mod.state, item, {
+    Object.defineProperty(mod.state, key, {
         get: function() {
-            //console.log('GET', item, this['_' + item])
-            return this['_' + item]
+            //console.log('GET', key, this['_' + key])
+            return this['_' + key]
         }
     })
 }
 
+function makeRepFromModule(mdl) {
+    var rep = {
+        description: {
+            id: mdl.description.id,
+            name: mdl.description.name,
+            alt: mdl.description.alt,
+            path: mdl.description.path
+        }
+    }
+
+    // TODO: making rep. of input / output should be a f'n of that object ...
+    // input, outputs, state objs should be known /sysobjects 
+    // everything else is free play 
+    rep.inputs = {}
+    for (key in mdl.inputs) {
+        rep.inputs[key] = {}
+        rep.inputs[key].accepts = mdl.inputs[key].accepts
+    }
+
+    rep.outputs = {}
+    for (key in mdl.outputs) {
+        rep.outputs[key] = {}
+        rep.outputs[key].emits = mdl.outputs[key].emits
+        rep.outputs[key].calls = new Array()
+        mdl.outputs[key].calls.forEach(function(inp) {
+            var input = {
+                parentId: inp.parentId,
+                key: inp.key
+            }
+            rep.outputs[key].calls.push(input)
+        })
+    }
+
+    rep.state = {}
+    for(key in mdl.state){
+        if(isStateKey(key)){
+            rep.state[key] = mdl.state[key]
+        }
+    }
+
+    return rep
+}
+
+function saveProgram(prgmem, path) {
+    // ok, and we're interested in just copying the relevant things ... 
+    var svprgmem = {
+        description: {
+            name: prgmem.description.name
+        },
+        modules: new Array()
+    }
+
+    var mdls = prgmem.modules
+
+    mdls.forEach(function(mdl) {
+        // basically, going to run a diff on this
+        console.log('mdl unit', mdl)
+        // and 
+        var og = makeRepFromModule(mdl)
+        console.log('rep uniiiit', og)
+        svprgmem.modules.push(og)
+    })
+
+    fs.writeFileSync(path, JSON.stringify(svprgmem, null, 2), 'utf8')
+}
+
+function openProgram(path){
+    var program = {}
+
+    // get the .json file as an object 
+    var prgRep = JSON.parse(fs.readFileSync(path, 'utf8'))
+    console.log('OPENING THIS REP', prgRep)
+
+    program.description = {
+        name: prgRep.description.name,
+        id: prgRep.description.name + 1,
+        path: path
+    }
+
+    program.modules = new Array()
+
+    prgRep.modules.forEach(function(rep){
+        addModuleToProgram(program, rep.description.path)
+    })
+
+    // once modules exist, link inputs / outputs / copy state ? 
+
+    return program
+}
+
 /*
 
-PROGRAM UPDATING 
+PROGRAM REPRESENT 
 
 */
 
+
 //console.log('modules at prgmem start', modules)
 function putReps() {
     var reps = new Array()
@@ -341,6 +429,15 @@ function changeUi(data) {
     console.log('CHANGE UI', mod.id, mod.ui)
 }
 
+function setUiPos(module, left, top) {
+    if (module.ui == null) {
+        module.ui = {}
+    }
+    module.ui.left = left
+    module.ui.top = top
+}
+
+
 function isStateKey(key) {
     if (key.indexOf('_') == 0 || key == 'emitters' || key == 'onChange' || key == 'emitChange') {
         return false
diff --git a/programs/instron.js b/programs/instron.js
index 68dba0f823db30cfba9dce6728d957a14ff30de4..bf65736d862a1be3f33a7feb6bb0abbc86d33603 100644
--- a/programs/instron.js
+++ b/programs/instron.js
@@ -1,4 +1,5 @@
 
+
 var gate = addModule('./src/util/gate.js')
 var delay = addModule('./src/util/delay.js')
 var log = addModule('./src/util/log.js')
diff --git a/programs/tstprgmem.js b/programs/tstprgmem.js
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/save/mdls.json b/save/mdls.json
new file mode 100644
index 0000000000000000000000000000000000000000..167d4ffa273a3b01b6e3f6304b4f4952ac8872f2
--- /dev/null
+++ b/save/mdls.json
@@ -0,0 +1 @@
+[{"description":{"name":"gate","alt":"in ... out"},"state":{"emitters":{},"toggle":{"isButton":true,"isPressed":false,"label":"Open / Close"},"message":"closed","_toggle":{"isButton":true,"isPressed":false,"label":"Open / Close"},"_message":"closed"},"isOpen":false,"inputs":{"thru":{"accepts":"any","parentId":0,"key":"thru"}},"outputs":{"out":{"emits":"any","calls":[{"accepts":"any","parentId":1,"key":"thru"},{"accepts":"any","parentId":2,"key":"thru"},{"accepts":"any","parentId":3,"key":"reset"},{"accepts":"event","parentId":4,"key":"trigger"},{"accepts":"event","parentId":8,"key":"rmtrig"},{"accepts":"event","parentId":9,"key":"rmtrig"}]}},"id":0,"path":"./src/util/gate.js","ui":{"left":160,"top":130}},{"description":{"name":"delay!","alt":"in ... out"},"state":{"emitters":{},"ms":100,"_ms":100},"inputs":{"thru":{"accepts":"any","parentId":1,"key":"thru"}},"outputs":{"out":{"emits":"any","calls":[{"accepts":"any","parentId":3,"key":"A"}]}},"id":1,"path":"./src/util/delay.js","ui":{"left":160,"top":260}},{"description":{"name":"logger!","alt":"in ... out to console"},"state":{"emitters":{},"prefix":"LOGGER:","message":"---","_prefix":"LOGGER:","_message":"---"},"inputs":{"thru":{"accepts":"any","parentId":2,"key":"thru"}},"id":2,"path":"./src/util/log.js","ui":{"left":160,"top":400}},{"description":{"name":"andflow","alt":"in ... out"},"state":{"emitters":{},"toggle":{"isButton":true,"isPressed":false,"label":"Reset"},"A":0,"B":0,"_toggle":{"isButton":true,"isPressed":false,"label":"Reset"},"_A":0,"_B":0},"inputs":{"reset":{"accepts":"any","parentId":3,"key":"reset"},"A":{"accepts":"any","parentId":3,"key":"A"},"B":{"accepts":"any","parentId":3,"key":"B"}},"outputs":{"out":{"emits":"any","calls":[{"accepts":"any","parentId":0,"key":"thru"}]}},"id":3,"path":"./src/flowcontrol/and.js","ui":{"left":700,"top":300}},{"description":{"name":"CAMERA Request","alt":"webcam","isHardware":true},"state":{"emitters":{},"button":{"isButton":true,"isPressed":false,"label":"REQUEST IMAGE"},"counter":0,"_button":{"isButton":true,"isPressed":false,"label":"REQUEST IMAGE"},"_counter":0},"inputs":{"trigger":{"accepts":"event","parentId":4,"key":"trigger"}},"outputs":{"image":{"emits":"image","calls":[]},"callback":{"emits":"event","calls":[{"accepts":"any","parentId":3,"key":"B"}]}},"id":4,"path":"./src/hardware/webcam.js","ui":{"left":500,"top":700}},{"description":{"name":"Breadboard ADC Request","alt":"bbadc","isHardware":true},"state":{"emitters":{},"button":{"isButton":true,"isPressed":false,"label":"REQUEST CONVERSION"},"adcVal":0,"_button":{"isButton":true,"isPressed":false,"label":"REQUEST CONVERSION"},"_adcVal":0},"inputs":{"packet":{"accepts":"headless packet","parentId":5,"key":"packet"},"request":{"accepts":"event","parentId":5,"key":"request"}},"outputs":{"packet":{"emits":"number","calls":[{"accepts":"headless packet","parentId":7,"key":"B"}]}},"id":5,"path":"./src/hardware/adc.js","ui":{"left":1629,"top":180}},{"description":{"name":"Test Packet","alt":"net state","isHardware":true},"state":{"emitters":{},"button":{"isButton":true,"isPressed":false,"label":"TEST"},"message":"no test started","_button":{"isButton":true,"isPressed":false,"label":"TEST"},"_message":"no test started"},"inputs":{"packet":{"accepts":"headless packet","parentId":6,"key":"packet"},"trigger":{"accepts":"event","parentId":6,"key":"trigger"}},"outputs":{"packet":{"emits":"number","calls":[{"accepts":"headless packet","parentId":7,"key":"B"}]}},"id":6,"path":"./src/hardware/test.js","ui":{"left":1060,"top":918}},{"description":{"name":"ATK Hardware Bridge","alt":"talks over serialport","isHardware":true},"state":{"emitters":{},"rA":"0,0","rB":"0,1","rC":"0,2","rD":"0,3","rE":"0,4","rF":"0,5","rG":"0","findPort":{"isButton":true,"isPressed":false,"label":"click to find atk port"},"portName":"---","connect":{"isButton":true,"isPressed":false,"label":"click to connect"},"portStatus":"closed","terminal":"address | key:values","sendRawPacket":{"isButton":true,"isPressed":false,"label":"sendRaw"},"_rA":"0,0","_rB":"0,1","_rC":"0,2","_rD":"0,3","_rE":"0,4","_rF":"0,5","_rG":"0","_findPort":{"isButton":true,"isPressed":false,"label":"click to find atk port"},"_portName":"---","_connect":{"isButton":true,"isPressed":false,"label":"click to connect"},"_portStatus":"closed","_terminal":"address | key:values","_sendRawPacket":{"isButton":true,"isPressed":false,"label":"sendRaw"}},"inputs":{"A":{"accepts":"headless packet","parentId":7,"key":"A"},"B":{"accepts":"headless packet","parentId":7,"key":"B"},"C":{"accepts":"headless packet","parentId":7,"key":"C"},"D":{"accepts":"headless packet","parentId":7,"key":"D"},"E":{"accepts":"headless packet","parentId":7,"key":"E"},"F":{"accepts":"headless packet","parentId":7,"key":"F"},"G":{"accepts":"headless packet","parentId":7,"key":"G"}},"outputs":{"A":{"emits":"headless packet","calls":[{"accepts":"headless packet","parentId":8,"key":"packet"},{"accepts":"headless packet","parentId":10,"key":"packet"}]},"B":{"emits":"headless packet","calls":[{"accepts":"headless packet","parentId":5,"key":"packet"},{"accepts":"headless packet","parentId":6,"key":"packet"}]},"C":{"emits":"headless packet","calls":[]},"D":{"emits":"headless packet","calls":[]},"E":{"emits":"headless packet","calls":[]},"F":{"emits":"headless packet","calls":[{"accepts":"headless packet","parentId":9,"key":"packet"},{"accepts":"headless packet","parentId":11,"key":"packet"}]},"G":{"emits":"headless packet","calls":[]}},"pairs":{"A":{"route":"0,0","output":{"emits":"headless packet","calls":[{"accepts":"headless packet","parentId":8,"key":"packet"},{"accepts":"headless packet","parentId":10,"key":"packet"}]}},"B":{"route":"0,1","output":{"emits":"headless packet","calls":[{"accepts":"headless packet","parentId":5,"key":"packet"},{"accepts":"headless packet","parentId":6,"key":"packet"}]}},"C":{"route":"0,2","output":{"emits":"headless packet","calls":[]}},"D":{"route":"0,3","output":{"emits":"headless packet","calls":[]}},"E":{"route":"0,4","output":{"emits":"headless packet","calls":[]}}},"id":7,"path":"./src/hardware/bridge.js","ui":{"left":1629,"top":890}},{"description":{"name":"ATK Network Stepper Driver","alt":"software representation of stepper","isHardware":true},"state":{"emitters":{},"axis":"Y","spu":75,"rawMove":0.25,"makeMove":{"isButton":true,"isPressed":false,"label":"test move"},"lead":0,"position":0,"_axis":"Y","_spu":75,"_rawMove":0.25,"_makeMove":{"isButton":true,"isPressed":false,"label":"test move"},"_lead":0,"_position":0},"inputs":{"move":{"accepts":"move instruction","parentId":8,"key":"move"},"packet":{"accepts":"headless packet","parentId":8,"key":"packet"},"rmtrig":{"accepts":"event","parentId":8,"key":"rmtrig"}},"outputs":{"ack":{"emits":"move acknowledgement","calls":[]},"q":{"emits":"number","calls":[]},"packet":{"emits":"headless packet","calls":[{"accepts":"headless packet","parentId":7,"key":"A"}]}},"id":8,"path":"./src/hardware/stepper.js","ui":{"left":1629,"top":372}},{"description":{"name":"ATK Network Stepper Driver","alt":"software representation of stepper","isHardware":true},"state":{"emitters":{},"axis":"Y","spu":-75,"rawMove":0.25,"makeMove":{"isButton":true,"isPressed":false,"label":"test move"},"lead":0,"position":0,"_axis":"Y","_spu":-75,"_rawMove":0.25,"_makeMove":{"isButton":true,"isPressed":false,"label":"test move"},"_lead":0,"_position":0},"inputs":{"move":{"accepts":"move instruction","parentId":9,"key":"move"},"packet":{"accepts":"headless packet","parentId":9,"key":"packet"},"rmtrig":{"accepts":"event","parentId":9,"key":"rmtrig"}},"outputs":{"ack":{"emits":"move acknowledgement","calls":[]},"q":{"emits":"number","calls":[]},"packet":{"emits":"headless packet","calls":[{"accepts":"headless packet","parentId":7,"key":"F"}]}},"id":9,"path":"./src/hardware/stepper.js","ui":{"left":1629,"top":626}},{"description":{"name":"Test Packet","alt":"net state","isHardware":true},"state":{"emitters":{},"button":{"isButton":true,"isPressed":false,"label":"TEST"},"message":"no test started","_button":{"isButton":true,"isPressed":false,"label":"TEST"},"_message":"no test started"},"inputs":{"packet":{"accepts":"headless packet","parentId":10,"key":"packet"},"trigger":{"accepts":"event","parentId":10,"key":"trigger"}},"outputs":{"packet":{"emits":"number","calls":[{"accepts":"headless packet","parentId":7,"key":"A"}]}},"id":10,"path":"./src/hardware/test.js","ui":{"left":1060,"top":1050}},{"description":{"name":"Test Packet","alt":"net state","isHardware":true},"state":{"emitters":{},"button":{"isButton":true,"isPressed":false,"label":"TEST"},"message":"no test started","_button":{"isButton":true,"isPressed":false,"label":"TEST"},"_message":"no test started"},"inputs":{"packet":{"accepts":"headless packet","parentId":11,"key":"packet"},"trigger":{"accepts":"event","parentId":11,"key":"trigger"}},"outputs":{"packet":{"emits":"number","calls":[{"accepts":"headless packet","parentId":7,"key":"F"}]}},"id":11,"path":"./src/hardware/test.js","ui":{"left":1060,"top":1170}}]
\ No newline at end of file
diff --git a/save/onesave.json b/save/onesave.json
new file mode 100644
index 0000000000000000000000000000000000000000..aa0f88040398157147534212ba8a81523a4361cc
--- /dev/null
+++ b/save/onesave.json
@@ -0,0 +1,104 @@
+{
+    "description":
+    {
+        "name": "tstprgmem"
+    },
+    "modules": [
+    {
+        "description":
+        {
+            "id": "gate-1",
+            "name": "gate",
+            "alt": "in ... out",
+            "path": "./src/util/gate.js"
+        },
+        "inputs":
+        {
+            "thru":
+            {
+                "accepts": "any"
+            }
+        },
+        "outputs":
+        {
+            "out":
+            {
+                "emits": "any",
+                "calls": [
+                {
+                    "parentId": "delay-2",
+                    "key": "thru"
+                },
+                {
+                    "parentId": "logger-3",
+                    "key": "thru"
+                }]
+            }
+        },
+        "state":
+        {
+            "toggle":
+            {
+                "isButton": true,
+                "isPressed": false,
+                "label": "Open / Close"
+            },
+            "message": "closed"
+        }
+    },
+    {
+        "description":
+        {
+            "id": "delay-2",
+            "name": "delay",
+            "alt": "in ... out",
+            "path": "./src/util/delay.js"
+        },
+        "inputs":
+        {
+            "thru":
+            {
+                "accepts": "any"
+            }
+        },
+        "outputs":
+        {
+            "out":
+            {
+                "emits": "any",
+                "calls": [
+                {
+                    "parentId": "logger-3",
+                    "key": "thru"
+                }]
+            }
+        },
+        "state":
+        {
+            "ms": 100
+        }
+    },
+    {
+        "description":
+        {
+            "id": "logger-3",
+            "name": "logger",
+            "alt": "in ... out to console",
+            "path": "./src/util/log.js"
+        },
+        "inputs":
+        {
+            "thru":
+            {
+                "accepts": "any"
+            }
+        },
+        "outputs":
+        {},
+        "state":
+        {
+            "prefix": "LOGGER:",
+            "message": "---"
+        }
+    }]
+}
\ No newline at end of file
diff --git a/save/otms.json b/save/otms.json
new file mode 100644
index 0000000000000000000000000000000000000000..aa0f88040398157147534212ba8a81523a4361cc
--- /dev/null
+++ b/save/otms.json
@@ -0,0 +1,104 @@
+{
+    "description":
+    {
+        "name": "tstprgmem"
+    },
+    "modules": [
+    {
+        "description":
+        {
+            "id": "gate-1",
+            "name": "gate",
+            "alt": "in ... out",
+            "path": "./src/util/gate.js"
+        },
+        "inputs":
+        {
+            "thru":
+            {
+                "accepts": "any"
+            }
+        },
+        "outputs":
+        {
+            "out":
+            {
+                "emits": "any",
+                "calls": [
+                {
+                    "parentId": "delay-2",
+                    "key": "thru"
+                },
+                {
+                    "parentId": "logger-3",
+                    "key": "thru"
+                }]
+            }
+        },
+        "state":
+        {
+            "toggle":
+            {
+                "isButton": true,
+                "isPressed": false,
+                "label": "Open / Close"
+            },
+            "message": "closed"
+        }
+    },
+    {
+        "description":
+        {
+            "id": "delay-2",
+            "name": "delay",
+            "alt": "in ... out",
+            "path": "./src/util/delay.js"
+        },
+        "inputs":
+        {
+            "thru":
+            {
+                "accepts": "any"
+            }
+        },
+        "outputs":
+        {
+            "out":
+            {
+                "emits": "any",
+                "calls": [
+                {
+                    "parentId": "logger-3",
+                    "key": "thru"
+                }]
+            }
+        },
+        "state":
+        {
+            "ms": 100
+        }
+    },
+    {
+        "description":
+        {
+            "id": "logger-3",
+            "name": "logger",
+            "alt": "in ... out to console",
+            "path": "./src/util/log.js"
+        },
+        "inputs":
+        {
+            "thru":
+            {
+                "accepts": "any"
+            }
+        },
+        "outputs":
+        {},
+        "state":
+        {
+            "prefix": "LOGGER:",
+            "message": "---"
+        }
+    }]
+}
\ No newline at end of file
diff --git a/save/twosave.json b/save/twosave.json
new file mode 100644
index 0000000000000000000000000000000000000000..fd9d0a530ebdbe79afbaaaafd342eea264b0bbc7
--- /dev/null
+++ b/save/twosave.json
@@ -0,0 +1,92 @@
+{
+    "description":
+    {
+        "name": "tstprgmem"
+    },
+    "modules": [
+    {
+        "description":
+        {
+            "id": "gate-1",
+            "name": "gate",
+            "alt": "in ... out",
+            "path": "./src/util/gate.js"
+        },
+        "inputs":
+        {
+            "thru":
+            {
+                "accepts": "any"
+            }
+        },
+        "outputs":
+        {
+            "out":
+            {
+                "emits": "any",
+                "calls": []
+            }
+        },
+        "state":
+        {
+            "toggle":
+            {
+                "isButton": true,
+                "isPressed": false,
+                "label": "Open / Close"
+            },
+            "message": "closed"
+        }
+    },
+    {
+        "description":
+        {
+            "id": "delay-2",
+            "name": "delay",
+            "alt": "in ... out",
+            "path": "./src/util/delay.js"
+        },
+        "inputs":
+        {
+            "thru":
+            {
+                "accepts": "any"
+            }
+        },
+        "outputs":
+        {
+            "out":
+            {
+                "emits": "any",
+                "calls": []
+            }
+        },
+        "state":
+        {
+            "ms": 100
+        }
+    },
+    {
+        "description":
+        {
+            "id": "logger-3",
+            "name": "logger",
+            "alt": "in ... out to console",
+            "path": "./src/util/log.js"
+        },
+        "inputs":
+        {
+            "thru":
+            {
+                "accepts": "any"
+            }
+        },
+        "outputs":
+        {},
+        "state":
+        {
+            "prefix": "LOGGER:",
+            "message": "---"
+        }
+    }]
+}
\ No newline at end of file
diff --git a/scratch.js b/scratch.js
deleted file mode 100644
index 3c9a5440974baa48640194368f9d97fd844522c0..0000000000000000000000000000000000000000
--- a/scratch.js
+++ /dev/null
@@ -1,14 +0,0 @@
-
-function writeStateRep(rep, key){
-    // ui including different input types ... + button to fire?
-    var li = document.createElement('li')
-    li.appendChild(document.createTextNode(key + ':'))
-    var input = document.createElement('input')
-    input.type = 'text'
-    input.size = 20
-    li.appendChild(input)
-    input.addEventListener('change', function(){
-        console.log('update', rep.state, key)
-    })
-    return li
-}
\ No newline at end of file
diff --git a/atkterminal.js b/scratch/atkterminal.js
similarity index 100%
rename from atkterminal.js
rename to scratch/atkterminal.js
diff --git a/run.js b/scratch/run.js
similarity index 100%
rename from run.js
rename to scratch/run.js
diff --git a/scratch/scratch.js b/scratch/scratch.js
new file mode 100644
index 0000000000000000000000000000000000000000..5ba65416a7370c8de0d848539452ecd1f34d11ba
--- /dev/null
+++ b/scratch/scratch.js
@@ -0,0 +1,81 @@
+
+function writeStateRep(rep, key){
+    // ui including different input types ... + button to fire?
+    var li = document.createElement('li')
+    li.appendChild(document.createTextNode(key + ':'))
+    var input = document.createElement('input')
+    input.type = 'text'
+    input.size = 20
+    li.appendChild(input)
+    input.addEventListener('change', function(){
+        console.log('update', rep.state, key)
+    })
+    return li
+}
+
+
+function addModule(list, path) {
+    // get and add to server system
+    if (fs.existsSync(path)) {
+        var src = require(path) // get and return 
+        var mod = new src() // make a new one
+        list.push(mod)
+        // assign and id and remember from whence it came
+        mod.id = list.length - 1
+        mod.path = path
+
+        // we need to add some top-level info to the inputs so that we can draw them 
+        for (item in mod.inputs) {
+            mod.inputs[item].parentId = mod.id
+            mod.inputs[item].key = item
+        }
+
+        for (item in mod.state) {
+            if (item == 'onChange' | item == 'emitChange' | item == 'emitters') {
+                //console.log('rolling past change fn')
+            } else {
+                mod.state['_' + item] = mod.state[item]
+                mod.state[item] = {}
+                writeStateObject(mod, item)
+            }
+        }
+
+        console.log('ADDING MODULE', mod.description.name)
+
+        // now roll and return representable object 
+        // first to UI
+
+        // putRep(mod)
+
+        // also to fn call, in case writing program ? 
+        return mod
+    } else {
+        console.log('ERR no module found at', path)
+    }
+}
+
+
+/*
+
+fs.writeFile('save/mdls.json', JSON.stringify(modules), 'utf8', function(err){
+    if(err) throw err 
+    console.log('wrote file')
+})
+
+*/
+
+function loadPrgmem(desc) {
+    // a collection of modules 
+    var modules = new Array()
+
+    // go through once and load in memory 
+    for (obj in desc.nodes) {
+        console.log(desc.nodes[obj].path)
+        addModule(modules, desc.nodes[obj].path)
+    }
+    for (obj in desc.nodes) {
+        var lst = desc.nodes[obj].connects
+        // 1st item is output, all others are inputs 
+        console.log(lst)
+    }
+}
\ No newline at end of file
diff --git a/terminalMachine.js b/scratch/terminalMachine.js
similarity index 100%
rename from terminalMachine.js
rename to scratch/terminalMachine.js
diff --git a/src/util/delay.js b/src/util/delay.js
index 1d19c018da14a6ef4afc826762cada47838d74f4..21e43be4f5a3ef94edfa96e237b39262371ba469 100644
--- a/src/util/delay.js
+++ b/src/util/delay.js
@@ -1,8 +1,9 @@
 // boilerplate atkapi header
-const InOut = require('../../lib/inout.js')
-let Input = InOut.Input
-let Output = InOut.Output
-let State = InOut.State
+// boilerplate header
+const JSUnit = require('../../lib/jsunit.js')
+let Input = JSUnit.Input
+let Output = JSUnit.Output
+let State = JSUnit.State
 
 // a constructor, a fn, a javascript mess
 function Delay() {
@@ -10,7 +11,7 @@ function Delay() {
     var delay = {
         // descriptions are used in UI
         description: {
-            name: 'delay!',
+            name: 'delay',
             alt: 'in ... out'
         }
     }
diff --git a/src/util/gate.js b/src/util/gate.js
index 7a3b012916d541bb50b1753e0cdf0a9a7af41686..e9b8fdd93336ad51179ffc3b326e04793faa89b7 100644
--- a/src/util/gate.js
+++ b/src/util/gate.js
@@ -1,9 +1,9 @@
-// boilerplate atkapi header
-const InOut = require('../../lib/inout.js')
-let Input = InOut.Input
-let Output = InOut.Output
-let State = InOut.State
-let Button = InOut.Button
+// boilerplate header
+const JSUnit = require('../../lib/jsunit.js')
+let Input = JSUnit.Input
+let Output = JSUnit.Output
+let State = JSUnit.State
+let Button = JSUnit.Button 
 
 // a constructor, a fn, a javascript mess
 function Gate() {
diff --git a/src/util/log.js b/src/util/log.js
index 60403c42985f0d6494b391bbecb83c2f823050e6..3af0f622663b53a656ee95d79d7ec03974d4c93a 100644
--- a/src/util/log.js
+++ b/src/util/log.js
@@ -1,8 +1,8 @@
-// boilerplate atkapi header
-const InOut = require('../../lib/inout.js')
-let Input = InOut.Input
-let Output = InOut.Output
-let State = InOut.State
+// boilerplate header
+const JSUnit = require('../../lib/jsunit.js')
+let Input = JSUnit.Input
+let Output = JSUnit.Output
+let State = JSUnit.State
 
 // a constructor, a fn, a javascript mess
 function Logger() {
@@ -10,7 +10,7 @@ function Logger() {
     var logger = {
         // descriptions are used in UI
         description: {
-            name: 'logger!',
+            name: 'logger',
             alt: 'in ... out to console'
         }
     }