diff --git a/.gitignore b/.gitignore
index 42e6204b0ab36b01dd9511b4e93422a01aebb6d4..19ee4e98b8e1c4b3fe259ccf4ab9a1e8ec9dc94f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,4 +3,7 @@ jake/
 **.hex
 **.lss
 **.map
-**.srec
\ No newline at end of file
+**.srec
+
+sim/js_code.txt
+sim/TinyNets/nbproject/
\ No newline at end of file
diff --git a/document/worst-case-ethernet.xlsx b/document/worst-case-ethernet.xlsx
new file mode 100644
index 0000000000000000000000000000000000000000..4419950a1d69def0299447f5b96ec01efecd67b3
Binary files /dev/null and b/document/worst-case-ethernet.xlsx differ
diff --git a/sim/README.md b/sim/README.md
index 40d6ecccae3c4de27ef940e25e603ef3ff0ec34b..ce830c9827f334af30e380407660a48a9cedeb38 100644
--- a/sim/README.md
+++ b/sim/README.md
@@ -1,3 +1,5 @@
+EDIT: The important files are now located in sim/TinyNets/public_html/
+
 # TinyNets Simulator
 
 A modified version of [simbit](https://github.com/ebfull/simbit).
diff --git a/sim/TinyNets/.bowerrc b/sim/TinyNets/.bowerrc
new file mode 100644
index 0000000000000000000000000000000000000000..0ba26f2cf68ff39eaeb45ee56543cc08fb61acb0
--- /dev/null
+++ b/sim/TinyNets/.bowerrc
@@ -0,0 +1,3 @@
+{
+    "directory": "public_html/bower_components"
+}
diff --git a/sim/TinyNets/Gruntfile.js b/sim/TinyNets/Gruntfile.js
new file mode 100644
index 0000000000000000000000000000000000000000..37d6aa7627e3a6b75e1cc2c644f9032419539b07
--- /dev/null
+++ b/sim/TinyNets/Gruntfile.js
@@ -0,0 +1,10 @@
+/* 
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+module.exports = function (grunt) {
+    // Project configuration.
+    grunt.initConfig({
+    });
+};
diff --git a/sim/TinyNets/bower.json b/sim/TinyNets/bower.json
new file mode 100644
index 0000000000000000000000000000000000000000..cd4d9884bb1da95319ac12ab88ac253a314cb1f8
--- /dev/null
+++ b/sim/TinyNets/bower.json
@@ -0,0 +1,12 @@
+{
+    "name": "TinyNets",
+    "version": "1.0.0",
+    "main": "path/to/main.css",
+    "ignore": [
+        ".jshintrc", "**/*.txt"
+    ],
+    "dependencies": {
+    },
+    "devDependencies": {
+    }
+}
diff --git a/sim/TinyNets/gulpfile.js b/sim/TinyNets/gulpfile.js
new file mode 100644
index 0000000000000000000000000000000000000000..18b3733bfd1853fbfda3af9d4d2889c0af3fd005
--- /dev/null
+++ b/sim/TinyNets/gulpfile.js
@@ -0,0 +1,11 @@
+/* 
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+var gulp = require('gulp');
+
+gulp.task('default', function () {
+    // place code for your default task here
+});
diff --git a/sim/TinyNets/package.json b/sim/TinyNets/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..50a05b0c376ab6e3a41d9ab1b2779719f7c1634d
--- /dev/null
+++ b/sim/TinyNets/package.json
@@ -0,0 +1,8 @@
+{
+    "name": "TinyNets",
+    "version": "1.0.0",
+    "keywords": ["util", "functional", "server", "client", "browser"],
+    "author": "rupum",
+    "contributors": [],
+    "dependencies": {}
+}
diff --git a/sim/bit-array.js b/sim/TinyNets/public_html/bit-array.js
old mode 100755
new mode 100644
similarity index 96%
rename from sim/bit-array.js
rename to sim/TinyNets/public_html/bit-array.js
index b9498c365805b23cb6853509cb9da5ea8e7b08f8..ec85209a27d24808b9eb7db9cce2d72fa2eda6d2
--- a/sim/bit-array.js
+++ b/sim/TinyNets/public_html/bit-array.js
@@ -1,225 +1,225 @@
-/**
- * JavaScript BitArray - v0.2.0
- *
- * Licensed under the revised BSD License.
- * Copyright 2010-2012 Bram Stein
- * All rights reserved.
- */
-
-/**
- * Creates a new empty BitArray with the given length or initialises the BitArray with the given hex representation.
- */
-var BitArray = function (size, hex) {
-    this.values = [];
-
-    if (hex) {
-        hex = hex.slice(/^0x/.exec(hex) ? 2 : 0);
-
-        if (hex.length * 4 > this.length) {
-            throw 'Hex value is too large for this bit array.'
-        } else if (hex.length * 4 < this.length) {
-            // pad it
-            while(hex.length * 4 < this.length) {
-                hex = '0' + hex;
-            }
-        }
-
-        for (var i = 0; i < (hex.length / 8); i++) {
-            var slice = hex.slice(i * 8, i * 8 + 8);
-            this.values[i] = parseInt(slice, 16);
-        }
-    } else {
-        for (var i = 0; i < Math.ceil(size / 32); i += 1) {
-            this.values[i] = 0;
-        }
-    }
-};
-
-/**
- * Returns the total number of bits in this BitArray.
- */
-BitArray.prototype.size = function () {
-	return this.values.length * 32;
-};
-
-/**
- * Sets the bit at index to a value (boolean.)
- */
-BitArray.prototype.set = function (index, value) {
-	var i = Math.floor(index / 32);
-	// Since "undefined | 1 << index" is equivalent to "0 | 1 << index" we do not need to initialise the array explicitly here.
-	if (value) {
-		this.values[i] |= 1 << index - i * 32;
-	} else {
-		this.values[i] &= ~(1 << index - i * 32);
-	}
-	return this;
-};
-
-/**
- * Toggles the bit at index. If the bit is on, it is turned off. Likewise, if the bit is off it is turned on.
- */
-BitArray.prototype.toggle = function (index) {
-	var i = Math.floor(index / 32);
-	this.values[i] ^= 1 << index - i * 32;
-	return this;
-};
-
-/**
- * Returns the value of the bit at index (boolean.)
- */
-BitArray.prototype.get = function (index) {
-	var i = Math.floor(index / 32);
-	return !!(this.values[i] & (1 << index - i * 32));
-};
-
-/**
- * Resets the BitArray so that it is empty and can be re-used.
- */
-BitArray.prototype.reset = function () {
-	this.values = [];
-	return this;
-};
-
-/**
- * Returns a copy of this BitArray.
- */
-BitArray.prototype.copy = function () {
-	var cp = new BitArray();
-	cp.length = this.length;
-	cp.values = [].concat(this.values);
-	return cp;
-};
-
-/**
- * Returns true if this BitArray equals another. Two BitArrays are considered
- * equal if both have the same length and bit pattern.
- */
-BitArray.prototype.equals = function (x) {
-	return this.values.length === x.values.length &&
-		this.values.every(function (value, index) {
-		return value === x.values[index];
-	});
-};
-
-/**
- * Returns the JSON representation of this BitArray.
- */
-BitArray.prototype.toJSON = function () {
-	return JSON.stringify(this.values);
-};
-
-/**
- * Returns a string representation of the BitArray with bits
- * in logical order.
- */
-BitArray.prototype.toString = function () {
-	return this.toArray().map(function (value) {
-		return value ? '1' : '0';
-	}).join('');
-};
-
-/**
- * Returns a string representation of the BitArray with bits
- * in mathemetical order.
- */
-BitArray.prototype.toBinaryString = function () {
-	return this.toArray().map(function (value) {
-		return value ? '1' : '0';
-	}).reverse().join('');
-};
-
-/**
- * Returns a hexadecimal string representation of the BitArray
- * with bits in logical order.
- */
-BitArray.prototype.toHexString = function () {
-  var result = [];
-
-  for (var i = 0; i < this.values.length; i += 1) {
-    result.push(('00000000' + (this.values[i] >>> 0).toString(16)).slice(-8));
-  }
-  return result.join('');
-};
-
-/**
- * Convert the BitArray to an Array of boolean values.
- */
-BitArray.prototype.toArray = function () {
-	var result = [];
-
-    for (var i = 0; i < this.values.length * 32; i += 1) {
-        result.push(this.get(i));
-    }
-	return result;
-};
-
-/**
- * Returns the total number of bits set to one in this BitArray.
- */
-BitArray.prototype.count = function () {
-	var total = 0;
-
-	// If we remove the toggle method we could efficiently cache the number of bits without calculating it on the fly.
-	this.values.forEach(function (x) {
-		// See: http://bits.stephan-brumme.com/countBits.html for an explanation
-		x  = x - ((x >> 1) & 0x55555555);
-		x  = (x & 0x33333333) + ((x >> 2) & 0x33333333);
-		x  = x + (x >> 4);
-		x &= 0xF0F0F0F;
-
-		total += (x * 0x01010101) >> 24;
-	});
-	return total;
-};
-
-/**
- * Inverts this BitArray.
- */
-BitArray.prototype.not = function () {
-	this.values = this.values.map(function (v) {
-		return ~v;
-	});
-	return this;
-};
-
-/**
- * Bitwise OR on the values of this BitArray using BitArray x.
- */
-BitArray.prototype.or = function (x) {
-	if (this.values.length !== x.values.length) {
-		throw 'Arguments must be of the same length.';
-	}
-	this.values = this.values.map(function (v, i) {
-		return v | x.values[i];
-	});
-	return this;
-};
-
-/**
- * Bitwise AND on the values of this BitArray using BitArray x.
- */
-BitArray.prototype.and = function (x) {
-	if (this.values.length !== x.values.length) {
-		throw 'Arguments must be of the same length.';
-	}
-	this.values = this.values.map(function (v, i) {
-		return v & x.values[i];
-	});
-	return this;
-};
-
-/**
- * Bitwise XOR on the values of this BitArray using BitArray x.
- */
-BitArray.prototype.xor = function (x) {
-	if (this.values.length !== x.values.length) {
-		throw 'Arguments must be of the same length.';
-	}
-	this.values = this.values.map(function (v, i) {
-		return v ^ x.values[i];
-	});
-	return this;
-};
-
+/**
+ * JavaScript BitArray - v0.2.0
+ *
+ * Licensed under the revised BSD License.
+ * Copyright 2010-2012 Bram Stein
+ * All rights reserved.
+ */
+
+/**
+ * Creates a new empty BitArray with the given length or initialises the BitArray with the given hex representation.
+ */
+var BitArray = function (size, hex) {
+    this.values = [];
+
+    if (hex) {
+        hex = hex.slice(/^0x/.exec(hex) ? 2 : 0);
+
+        if (hex.length * 4 > this.length) {
+            throw 'Hex value is too large for this bit array.'
+        } else if (hex.length * 4 < this.length) {
+            // pad it
+            while(hex.length * 4 < this.length) {
+                hex = '0' + hex;
+            }
+        }
+
+        for (var i = 0; i < (hex.length / 8); i++) {
+            var slice = hex.slice(i * 8, i * 8 + 8);
+            this.values[i] = parseInt(slice, 16);
+        }
+    } else {
+        for (var i = 0; i < Math.ceil(size / 32); i += 1) {
+            this.values[i] = 0;
+        }
+    }
+};
+
+/**
+ * Returns the total number of bits in this BitArray.
+ */
+BitArray.prototype.size = function () {
+	return this.values.length * 32;
+};
+
+/**
+ * Sets the bit at index to a value (boolean.)
+ */
+BitArray.prototype.set = function (index, value) {
+	var i = Math.floor(index / 32);
+	// Since "undefined | 1 << index" is equivalent to "0 | 1 << index" we do not need to initialise the array explicitly here.
+	if (value) {
+		this.values[i] |= 1 << index - i * 32;
+	} else {
+		this.values[i] &= ~(1 << index - i * 32);
+	}
+	return this;
+};
+
+/**
+ * Toggles the bit at index. If the bit is on, it is turned off. Likewise, if the bit is off it is turned on.
+ */
+BitArray.prototype.toggle = function (index) {
+	var i = Math.floor(index / 32);
+	this.values[i] ^= 1 << index - i * 32;
+	return this;
+};
+
+/**
+ * Returns the value of the bit at index (boolean.)
+ */
+BitArray.prototype.get = function (index) {
+	var i = Math.floor(index / 32);
+	return !!(this.values[i] & (1 << index - i * 32));
+};
+
+/**
+ * Resets the BitArray so that it is empty and can be re-used.
+ */
+BitArray.prototype.reset = function () {
+	this.values = [];
+	return this;
+};
+
+/**
+ * Returns a copy of this BitArray.
+ */
+BitArray.prototype.copy = function () {
+	var cp = new BitArray();
+	cp.length = this.length;
+	cp.values = [].concat(this.values);
+	return cp;
+};
+
+/**
+ * Returns true if this BitArray equals another. Two BitArrays are considered
+ * equal if both have the same length and bit pattern.
+ */
+BitArray.prototype.equals = function (x) {
+	return this.values.length === x.values.length &&
+		this.values.every(function (value, index) {
+		return value === x.values[index];
+	});
+};
+
+/**
+ * Returns the JSON representation of this BitArray.
+ */
+BitArray.prototype.toJSON = function () {
+	return JSON.stringify(this.values);
+};
+
+/**
+ * Returns a string representation of the BitArray with bits
+ * in logical order.
+ */
+BitArray.prototype.toString = function () {
+	return this.toArray().map(function (value) {
+		return value ? '1' : '0';
+	}).join('');
+};
+
+/**
+ * Returns a string representation of the BitArray with bits
+ * in mathemetical order.
+ */
+BitArray.prototype.toBinaryString = function () {
+	return this.toArray().map(function (value) {
+		return value ? '1' : '0';
+	}).reverse().join('');
+};
+
+/**
+ * Returns a hexadecimal string representation of the BitArray
+ * with bits in logical order.
+ */
+BitArray.prototype.toHexString = function () {
+  var result = [];
+
+  for (var i = 0; i < this.values.length; i += 1) {
+    result.push(('00000000' + (this.values[i] >>> 0).toString(16)).slice(-8));
+  }
+  return result.join('');
+};
+
+/**
+ * Convert the BitArray to an Array of boolean values.
+ */
+BitArray.prototype.toArray = function () {
+	var result = [];
+
+    for (var i = 0; i < this.values.length * 32; i += 1) {
+        result.push(this.get(i));
+    }
+	return result;
+};
+
+/**
+ * Returns the total number of bits set to one in this BitArray.
+ */
+BitArray.prototype.count = function () {
+	var total = 0;
+
+	// If we remove the toggle method we could efficiently cache the number of bits without calculating it on the fly.
+	this.values.forEach(function (x) {
+		// See: http://bits.stephan-brumme.com/countBits.html for an explanation
+		x  = x - ((x >> 1) & 0x55555555);
+		x  = (x & 0x33333333) + ((x >> 2) & 0x33333333);
+		x  = x + (x >> 4);
+		x &= 0xF0F0F0F;
+
+		total += (x * 0x01010101) >> 24;
+	});
+	return total;
+};
+
+/**
+ * Inverts this BitArray.
+ */
+BitArray.prototype.not = function () {
+	this.values = this.values.map(function (v) {
+		return ~v;
+	});
+	return this;
+};
+
+/**
+ * Bitwise OR on the values of this BitArray using BitArray x.
+ */
+BitArray.prototype.or = function (x) {
+	if (this.values.length !== x.values.length) {
+		throw 'Arguments must be of the same length.';
+	}
+	this.values = this.values.map(function (v, i) {
+		return v | x.values[i];
+	});
+	return this;
+};
+
+/**
+ * Bitwise AND on the values of this BitArray using BitArray x.
+ */
+BitArray.prototype.and = function (x) {
+	if (this.values.length !== x.values.length) {
+		throw 'Arguments must be of the same length.';
+	}
+	this.values = this.values.map(function (v, i) {
+		return v & x.values[i];
+	});
+	return this;
+};
+
+/**
+ * Bitwise XOR on the values of this BitArray using BitArray x.
+ */
+BitArray.prototype.xor = function (x) {
+	if (this.values.length !== x.values.length) {
+		throw 'Arguments must be of the same length.';
+	}
+	this.values = this.values.map(function (v, i) {
+		return v ^ x.values[i];
+	});
+	return this;
+};
+
 module.exports = BitArray;
\ No newline at end of file
diff --git a/sim/btc.js b/sim/TinyNets/public_html/btc.js
old mode 100755
new mode 100644
similarity index 96%
rename from sim/btc.js
rename to sim/TinyNets/public_html/btc.js
index a4c64e4f3c19b702ea03ac7b4e8e0c64f715e16d..9068407d58bd810ba6727e7626362376bfd9fb01
--- a/sim/btc.js
+++ b/sim/TinyNets/public_html/btc.js
@@ -1,18 +1,18 @@
-var Inventory = require("./btc/inventory.js")
-var Mempool = require("./btc/mempool.js")
-var Transactions = require("./btc/transactions.js")
-var Blockchain = require("./btc/blockchain.js")
-var Miner = require("./btc/miner.js")
-
-var btc = function(self) {
-	new Inventory(self);
-	new Mempool(self);
-	new Transactions(self);
-	new Blockchain(self);
-	new Miner(self);
-};
-
-
-btc.Blockchain = Blockchain.prototype;
-
+var Inventory = require("./btc/inventory.js")
+var Mempool = require("./btc/mempool.js")
+var Transactions = require("./btc/transactions.js")
+var Blockchain = require("./btc/blockchain.js")
+var Miner = require("./btc/miner.js")
+
+var btc = function(self) {
+	new Inventory(self);
+	new Mempool(self);
+	new Transactions(self);
+	new Blockchain(self);
+	new Miner(self);
+};
+
+
+btc.Blockchain = Blockchain.prototype;
+
 module.exports = btc;
\ No newline at end of file
diff --git a/sim/btc/blockchain.js b/sim/TinyNets/public_html/btc/blockchain.js
old mode 100755
new mode 100644
similarity index 95%
rename from sim/btc/blockchain.js
rename to sim/TinyNets/public_html/btc/blockchain.js
index 920f8b7faf86635c0f77c87efc48c73c635c9af5..2eead6a79fe686792e8a58df8808b8629ef52449
--- a/sim/btc/blockchain.js
+++ b/sim/TinyNets/public_html/btc/blockchain.js
@@ -1,339 +1,339 @@
-/*
-	btc-blockchain
-*/
-
-var colors = ["green", "orange", "blue", "purple", "brown", "steelblue", "red"]
-var color_i = 0;
-
-function Block(prev, time, miner) {
-	this.__prev = prev;
-
-	this.transactions = [];
-
-	if (miner) {
-		this.credit = miner.id;
-		this.transactions = miner.mempool.getList();
-	}
-	else
-		this.credit = false;
-
-	this.time = time;
-	this.color = colors[++color_i % colors.length]
-
-	if (prev) {
-		this.id = miner.network.rand();
-		this.h = prev.h + 1;
-		this.prev = prev.id;
-		this.difficulty = prev.difficulty;
-		this.work = prev.work + prev.difficulty;
-
-		if (!(this.h % this.difficulty_adjustment_period)) {
-			this.difficultyAdjustment()
-		}
-	}
-	else {
-		//this.id = String.fromCharCode(252, 124, 195, 233, 126, 94, 182, 200, 23, 107, 236, 43, 77, 137);
-		this.id = 'xxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
-		    var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
-		    return v.toString(16);
-		});
-		this.h = 0;
-		this.prev = false;
-		this.difficulty = 600000;
-		this.work = 0;
-	}
-}
-
-function PrevState(status) {
-	this.status = status;
-
-	this.equals = function(v) {
-		return (v.status == this.status)
-	}
-}
-
-var GenesisBlock = new Block(false, 0);
-
-Block.prototype = {
-	target_avg_between_blocks: 10 * 60 * 1000,
-	difficulty_adjustment_period: 2016,
-
-	difficultyAdjustment: function() {
-		var total = 0;
-		var last = this.time;
-		var cur = this._prev();
-
-		for (var i=0;i<this.difficulty_adjustment_period;i++) {
-			total += last - cur.time;
-			last = cur.time;
-			cur = cur._prev()
-		}
-		var avg = total / this.difficulty_adjustment_period;
-
-		var old = this.difficulty;
-		this.difficulty *= this.target_avg_between_blocks / avg;
-
-		console.log("(h=" + this.h + ") difficulty adjustment " + (this.target_avg_between_blocks / avg) + "x")
-	},
-	_prev: function() {
-		return this.__prev;
-	},
-
-	addPrev: function(me) {
-		me.set(this.id, new PrevState("set"))
-	},
-
-	rmPrev: function(me) {
-		me.set(this.id, new PrevState("none"))
-	}
-}
-
-function MapOrphanBlocks(self) {
-	this.mapOrphans = [];
-	this.mapOrphansByPrev = {};
-}
-
-MapOrphanBlocks.prototype = {
-	add: function(b) {
-		if (this.mapOrphans.indexOf(b) != -1)
-			return false;
-
-		if (this.mapOrphans.length == 100) {
-			this.delete(this.mapOrphans[0]);
-		}
-
-		this.mapOrphans.push(b);
-
-		if (!(b._prev().id in this.mapOrphansByPrev)) {
-			this.mapOrphansByPrev[b._prev().id] = [];
-		}
-		this.mapOrphansByPrev[b._prev().id].push(b);
-
-		return true;
-	},
-
-	delete: function(b) {
-		if (this.mapOrphans.indexOf(b) == -1)
-			return false;
-
-		var removed = this.mapOrphans.splice(this.mapOrphans.indexOf(b), 1)
-		var m = this.mapOrphansByPrev[b._prev().id];
-		
-		m.splice(m.indexOf(b), 1);
-
-		if (m.length == 0) {
-			delete this.mapOrphansByPrev[b._prev().id]
-		}
-
-		return true;
-	},
-
-	// returns boolean whether the block is an orphan already
-	is: function(b) {
-		if (this.mapOrphans.indexOf(b) == -1)
-			return false;
-
-		return true;
-	},
-
-	// finds any blocks that depended on this block within this maporphans
-	getForPrev: function(prev) {
-		if (prev.id in this.mapOrphansByPrev) {
-			return this.mapOrphansByPrev[prev.id];
-		}
-
-		return [];
-	}
-}
-
-var GenesisBlock = new Block(false, 0);
-
-function Chainstate(head, self) {
-	this.self = self;
-
-	this.prevs = self.network.shared("chainstate_prevs");
-
-	this.mapOrphans = new MapOrphanBlocks(self);
-
-	this.forward(head)
-}
-
-Chainstate.prototype = {
-	forward: function(b) {
-		this.self.setColor(b.color)
-		this.head = b
-
-		this.head.transactions.forEach(function(tx) {
-			// transaction _must_ be entered into UTXO to advance to this state
-			this.self.transactions.enter(tx, true);
-
-			// transaction must be removed from mempool
-			this.self.mempool.remove(tx);
-		}, this);
-		
-		b.addPrev(this.prevs);
-
-		if (this.mapOrphans.delete(this.head))
-			this.self.inventory.relay(this.head.id);
-	},
-	reverse: function() {
-		this.head.transactions.forEach(function(tx) {
-			// transaction must be added back to mempool
-			this.self.mempool.add(tx);
-		}, this);
-
-		this.mapOrphans.add(this.head)
-
-		this.head.rmPrev(this.prevs);
-
-		this.head = this.head._prev()
-	},
-	// (recursively) resolves the best orphan branch for comparison with the chainstate head
-	getOrphanWorkPath: function(block) {
-		var works = [];
-
-		this.mapOrphans.getForPrev(block).forEach(function(sub) {
-			works.push(this.getOrphanWorkPath(sub))
-		}, this)
-
-		if (works.length == 0) {
-			// there aren't any subworks
-			return {end:block,work:block.work}
-		} else {
-			// pick the largest one
-			var largestWork = {end:false,work:Number.NEGATIVE_INFINITY};
-
-			works.forEach(function(subwork) {
-				if (subwork.work > largestWork.work) {
-					largestWork = subwork;
-				}
-			})
-
-			// return it
-			return largestWork;
-		}
-	},
-	// this function helps identify orphan blocks
-	reorg: function(block, numorphan, force) {
-		var ourorphans = 0;
-		if (numorphan == -1) {
-			// This block couldn't be entered into the chainstate, so it's an orphan.
-			if (!this.mapOrphans.is(block)) {
-				this.mapOrphans.add(block)
-			} else {
-				return numorphan;
-			}
-		}
-
-		// maybe it completes a chain though
-		var cur = block;
-
-		while(true) {
-			var curprev = this.prevs.get(cur.id);
-			if (curprev.status == "set") {
-				var bestOrphanPath = this.getOrphanWorkPath(cur)
-				if ((force && bestOrphanPath.work >= this.head.work) || bestOrphanPath.work > this.head.work) {
-					//console.log(this.self.id + ": adopting orphan chain of (w=" + bestOrphanPath.work + " vs. local " + this.head.work + ")")
-					ourorphans += this.enter(bestOrphanPath.end, true, true)
-				}
-
-				break;
-			} else {
-				cur = cur._prev();
-			}
-		}
-		if (numorphan == -1) {
-			if (ourorphans == 0)
-				return numorphan;
-			else
-				return ourorphans
-		}
-		else
-			return numorphan + ourorphans;
-	},
-	// enter a block into the chainstate, perhaps resulting in a reorg, and also perhaps resulting in its inclusion within maporphans
-	enter: function(block, force, doingReorg) {
-		//console.log((doingReorg ? "(reorg) " : "") + "entering new block at height " + block.h)
-		if (block == this.head)
-			return -1
-
-		var bprev = this.prevs.get(block._prev().id)
-
-		if (bprev.status == "none") {
-			// this block's prev doesn't exist, it's an orphan!
-			if (!doingReorg)
-				return this.reorg(block, -1, force)
-		}
-
-		if (typeof force == "undefined")
-			force = false;
-		//else if (force)
-		//	this.self.log("\tchainstate forcefully entering branch")
-
-		var numorphan = -1;
-
-		if ((this.head.work < block.work) || force) {
-			// the current head is now obsolete
-
-			numorphan = 0;
-			var forwards = []
-			var cur = block
-
-			reorg:
-			while(true) {
-				if (cur.h > this.head.h) {
-					forwards.push(cur)
-					cur = cur._prev()
-				} else if (cur == this.head) {
-					while(true) {
-						if (forwards.length > 0) {
-							this.forward(forwards.pop())
-						} else {
-							break reorg;
-						}
-					}
-				} else {
-					numorphan++;
-					this.reverse()
-				}
-			}
-		} else if (this.head.work == block.work) {
-			//this.self.log("\tblock rejected; already seen one at this chainlength")
-		}
-
-		if (!doingReorg)
-			numorphan = this.reorg(block, numorphan)
-
-		return numorphan
-	}
-}
-
-function Blockchain(self) {
-	self.blockchain = this;
-
-	this.chainstate = new Chainstate(GenesisBlock, self);
-
-	this.newChainstate = function() {
-		return new Chainstate(this.chainstate.head, self);
-	}
-
-	// When we receive a new block over the wire, process it here.
-	this.onBlock = function(b) {
-		if (this.chainstate.enter(b) != -1) {
-			self.inventory.relay(b.id);
-			return true;
-		};
-	}
-
-	self.on("obj:block", function(from, o) {
-		if (this.onBlock(o))
-			self.handle(from, "blockchain:block", o);
-	}, this)
-}
-
-Blockchain.prototype = {
-	Block: Block,
-	GenesisBlock: GenesisBlock
-}
-
+/*
+	btc-blockchain
+*/
+
+var colors = ["green", "orange", "blue", "purple", "brown", "steelblue", "red"]
+var color_i = 0;
+
+function Block(prev, time, miner) {
+	this.__prev = prev;
+
+	this.transactions = [];
+
+	if (miner) {
+		this.credit = miner.id;
+		this.transactions = miner.mempool.getList();
+	}
+	else
+		this.credit = false;
+
+	this.time = time;
+	this.color = colors[++color_i % colors.length]
+
+	if (prev) {
+		this.id = miner.network.rand();
+		this.h = prev.h + 1;
+		this.prev = prev.id;
+		this.difficulty = prev.difficulty;
+		this.work = prev.work + prev.difficulty;
+
+		if (!(this.h % this.difficulty_adjustment_period)) {
+			this.difficultyAdjustment()
+		}
+	}
+	else {
+		//this.id = String.fromCharCode(252, 124, 195, 233, 126, 94, 182, 200, 23, 107, 236, 43, 77, 137);
+		this.id = 'xxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
+		    var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
+		    return v.toString(16);
+		});
+		this.h = 0;
+		this.prev = false;
+		this.difficulty = 600000;
+		this.work = 0;
+	}
+}
+
+function PrevState(status) {
+	this.status = status;
+
+	this.equals = function(v) {
+		return (v.status == this.status)
+	}
+}
+
+var GenesisBlock = new Block(false, 0);
+
+Block.prototype = {
+	target_avg_between_blocks: 10 * 60 * 1000,
+	difficulty_adjustment_period: 2016,
+
+	difficultyAdjustment: function() {
+		var total = 0;
+		var last = this.time;
+		var cur = this._prev();
+
+		for (var i=0;i<this.difficulty_adjustment_period;i++) {
+			total += last - cur.time;
+			last = cur.time;
+			cur = cur._prev()
+		}
+		var avg = total / this.difficulty_adjustment_period;
+
+		var old = this.difficulty;
+		this.difficulty *= this.target_avg_between_blocks / avg;
+
+		console.log("(h=" + this.h + ") difficulty adjustment " + (this.target_avg_between_blocks / avg) + "x")
+	},
+	_prev: function() {
+		return this.__prev;
+	},
+
+	addPrev: function(me) {
+		me.set(this.id, new PrevState("set"))
+	},
+
+	rmPrev: function(me) {
+		me.set(this.id, new PrevState("none"))
+	}
+}
+
+function MapOrphanBlocks(self) {
+	this.mapOrphans = [];
+	this.mapOrphansByPrev = {};
+}
+
+MapOrphanBlocks.prototype = {
+	add: function(b) {
+		if (this.mapOrphans.indexOf(b) != -1)
+			return false;
+
+		if (this.mapOrphans.length == 100) {
+			this.delete(this.mapOrphans[0]);
+		}
+
+		this.mapOrphans.push(b);
+
+		if (!(b._prev().id in this.mapOrphansByPrev)) {
+			this.mapOrphansByPrev[b._prev().id] = [];
+		}
+		this.mapOrphansByPrev[b._prev().id].push(b);
+
+		return true;
+	},
+
+	delete: function(b) {
+		if (this.mapOrphans.indexOf(b) == -1)
+			return false;
+
+		var removed = this.mapOrphans.splice(this.mapOrphans.indexOf(b), 1)
+		var m = this.mapOrphansByPrev[b._prev().id];
+		
+		m.splice(m.indexOf(b), 1);
+
+		if (m.length == 0) {
+			delete this.mapOrphansByPrev[b._prev().id]
+		}
+
+		return true;
+	},
+
+	// returns boolean whether the block is an orphan already
+	is: function(b) {
+		if (this.mapOrphans.indexOf(b) == -1)
+			return false;
+
+		return true;
+	},
+
+	// finds any blocks that depended on this block within this maporphans
+	getForPrev: function(prev) {
+		if (prev.id in this.mapOrphansByPrev) {
+			return this.mapOrphansByPrev[prev.id];
+		}
+
+		return [];
+	}
+}
+
+var GenesisBlock = new Block(false, 0);
+
+function Chainstate(head, self) {
+	this.self = self;
+
+	this.prevs = self.network.shared("chainstate_prevs");
+
+	this.mapOrphans = new MapOrphanBlocks(self);
+
+	this.forward(head)
+}
+
+Chainstate.prototype = {
+	forward: function(b) {
+		this.self.setColor(b.color)
+		this.head = b
+
+		this.head.transactions.forEach(function(tx) {
+			// transaction _must_ be entered into UTXO to advance to this state
+			this.self.transactions.enter(tx, true);
+
+			// transaction must be removed from mempool
+			this.self.mempool.remove(tx);
+		}, this);
+		
+		b.addPrev(this.prevs);
+
+		if (this.mapOrphans.delete(this.head))
+			this.self.inventory.relay(this.head.id);
+	},
+	reverse: function() {
+		this.head.transactions.forEach(function(tx) {
+			// transaction must be added back to mempool
+			this.self.mempool.add(tx);
+		}, this);
+
+		this.mapOrphans.add(this.head)
+
+		this.head.rmPrev(this.prevs);
+
+		this.head = this.head._prev()
+	},
+	// (recursively) resolves the best orphan branch for comparison with the chainstate head
+	getOrphanWorkPath: function(block) {
+		var works = [];
+
+		this.mapOrphans.getForPrev(block).forEach(function(sub) {
+			works.push(this.getOrphanWorkPath(sub))
+		}, this)
+
+		if (works.length == 0) {
+			// there aren't any subworks
+			return {end:block,work:block.work}
+		} else {
+			// pick the largest one
+			var largestWork = {end:false,work:Number.NEGATIVE_INFINITY};
+
+			works.forEach(function(subwork) {
+				if (subwork.work > largestWork.work) {
+					largestWork = subwork;
+				}
+			})
+
+			// return it
+			return largestWork;
+		}
+	},
+	// this function helps identify orphan blocks
+	reorg: function(block, numorphan, force) {
+		var ourorphans = 0;
+		if (numorphan == -1) {
+			// This block couldn't be entered into the chainstate, so it's an orphan.
+			if (!this.mapOrphans.is(block)) {
+				this.mapOrphans.add(block)
+			} else {
+				return numorphan;
+			}
+		}
+
+		// maybe it completes a chain though
+		var cur = block;
+
+		while(true) {
+			var curprev = this.prevs.get(cur.id);
+			if (curprev.status == "set") {
+				var bestOrphanPath = this.getOrphanWorkPath(cur)
+				if ((force && bestOrphanPath.work >= this.head.work) || bestOrphanPath.work > this.head.work) {
+					//console.log(this.self.id + ": adopting orphan chain of (w=" + bestOrphanPath.work + " vs. local " + this.head.work + ")")
+					ourorphans += this.enter(bestOrphanPath.end, true, true)
+				}
+
+				break;
+			} else {
+				cur = cur._prev();
+			}
+		}
+		if (numorphan == -1) {
+			if (ourorphans == 0)
+				return numorphan;
+			else
+				return ourorphans
+		}
+		else
+			return numorphan + ourorphans;
+	},
+	// enter a block into the chainstate, perhaps resulting in a reorg, and also perhaps resulting in its inclusion within maporphans
+	enter: function(block, force, doingReorg) {
+		//console.log((doingReorg ? "(reorg) " : "") + "entering new block at height " + block.h)
+		if (block == this.head)
+			return -1
+
+		var bprev = this.prevs.get(block._prev().id)
+
+		if (bprev.status == "none") {
+			// this block's prev doesn't exist, it's an orphan!
+			if (!doingReorg)
+				return this.reorg(block, -1, force)
+		}
+
+		if (typeof force == "undefined")
+			force = false;
+		//else if (force)
+		//	this.self.log("\tchainstate forcefully entering branch")
+
+		var numorphan = -1;
+
+		if ((this.head.work < block.work) || force) {
+			// the current head is now obsolete
+
+			numorphan = 0;
+			var forwards = []
+			var cur = block
+
+			reorg:
+			while(true) {
+				if (cur.h > this.head.h) {
+					forwards.push(cur)
+					cur = cur._prev()
+				} else if (cur == this.head) {
+					while(true) {
+						if (forwards.length > 0) {
+							this.forward(forwards.pop())
+						} else {
+							break reorg;
+						}
+					}
+				} else {
+					numorphan++;
+					this.reverse()
+				}
+			}
+		} else if (this.head.work == block.work) {
+			//this.self.log("\tblock rejected; already seen one at this chainlength")
+		}
+
+		if (!doingReorg)
+			numorphan = this.reorg(block, numorphan)
+
+		return numorphan
+	}
+}
+
+function Blockchain(self) {
+	self.blockchain = this;
+
+	this.chainstate = new Chainstate(GenesisBlock, self);
+
+	this.newChainstate = function() {
+		return new Chainstate(this.chainstate.head, self);
+	}
+
+	// When we receive a new block over the wire, process it here.
+	this.onBlock = function(b) {
+		if (this.chainstate.enter(b) != -1) {
+			self.inventory.relay(b.id);
+			return true;
+		};
+	}
+
+	self.on("obj:block", function(from, o) {
+		if (this.onBlock(o))
+			self.handle(from, "blockchain:block", o);
+	}, this)
+}
+
+Blockchain.prototype = {
+	Block: Block,
+	GenesisBlock: GenesisBlock
+}
+
 module.exports = Blockchain;
\ No newline at end of file
diff --git a/sim/btc/inventory.js b/sim/TinyNets/public_html/btc/inventory.js
old mode 100755
new mode 100644
similarity index 95%
rename from sim/btc/inventory.js
rename to sim/TinyNets/public_html/btc/inventory.js
index aa268f79c7a88b059dadf6c599f71722560f2b0a..affb45bd93367b8fcef37cc2e3fe7880fe617e9b
--- a/sim/btc/inventory.js
+++ b/sim/TinyNets/public_html/btc/inventory.js
@@ -1,254 +1,254 @@
-/*
-	btc-inventory
-
-	Mimics the Bitcoin inventory system.
-*/
-
-function InventoryObject(type, obj) {
-	this.type = type;
-	this.obj = obj;
-	this.id = obj.id;
-}
-
-function InventoryState(status) {
-	this.status = status;
-
-	this.equals = function(v) {
-		return this.status == v.status;
-	}
-}
-
-InventoryObject.prototype = {
-	init: function(consensus) {
-		consensus.add(this.id, this);
-	},
-
-	seen: function(me) {
-		var ir = me.get(this.id);
-
-		if (ir.status == "none") {
-			me.set(this.id, new InventoryState("seen"))
-
-			return true;
-		}
-
-		return false;
-	},
-
-	relay: function(me) {
-		var ir = me.get(this.id);
-
-		if (ir.status == "seen") {
-			me.set(this.id, new InventoryState("relay"))
-
-			return true;
-		}
-
-		return false;
-	}
-}
-
-function Inventory(self) {
-	self.inventory = this;
-
-	this.polling = false;
-
-	this.objects = self.network.shared("inventory");
-
-	this.peerHas = {};
-	this.tellPeer = {};
-	this.mapAskFor = {};
-	this.mapAlreadyAskedFor = {};
-
-	this.addTick = function() {
-		if (!this.polling) {
-			this.polling = true;
-
-			self.tick(1000, this.invTick, this)
-		}
-	}
-
-	this.invTick = function() {
-		var doneSomething = false;
-
-		for (var p in this.tellPeer) {
-			var invPacket = this.tellPeer[p];
-
-			if (Object.keys(invPacket).length != 0) {
-				doneSomething = true;
-				this.__send_inv(p, invPacket)
-
-				this.tellPeer[p] = {}; // don't need to tell the peer that anymore
-			}
-		}
-
-		var askMap = {};
-		for (var p in this.peerHas) {
-			askMap[p] = [];
-		}
-
-		for (var p in this.mapAskFor) {
-			for (name in this.mapAskFor[p]) {
-				if (this.mapAskFor[p][name] <= self.now()) {
-					askMap[p].push(name);
-					delete this.mapAskFor[p][name]
-				}
-			}
-		}
-
-		for (var p in askMap) {
-			if (askMap[p].length == 0)
-				continue;
-
-			doneSomething = true;
-
-			this.__send_getdata(p, askMap[p])
-		}
-
-		if (!doneSomething) {
-			this.polling = false; // we don't need to poll again
-			return false; // don't tick again
-		}
-	}
-
-	/*
-		p, {name1: type1, name2: type2, ...}
-	*/
-	this.__send_inv = function(p, mapNameTypes) {
-		self.peermgr.send(p, "inv", mapNameTypes);
-	}
-
-	/*
-		p, [name1, name2, name3]
-	*/
-	this.__send_getdata = function(p, askList) {
-		self.peermgr.send(p, "getdata", askList);
-	}
-
-	/*
-		p, (InventoryObject) o
-	*/
-	this.__send_invobj = function(p, o) {
-		self.peermgr.send(p, "invobj", o);
-	}
-
-	this.relay = function(name, now) {
-		var ir = this.objects.get(name);
-
-		if ('relay' in ir) {
-			if (ir.relay(this.objects)) {
-				for (var p in this.tellPeer) {
-					if (now) {
-						this.__send_invobj(p, ir);
-					} else {
-						this.addTick();
-						this.tellPeer[p][name] = ir.type;
-					}
-				}
-			}
-		}
-	}
-
-	this.getObj = function(name, mustRelay) {
-		var ir = this.objects.get(name);
-
-		if (ir.status == "none")
-			return false;
-
-		if (mustRelay && ir.status == "seen")
-			return false;
-
-		return ir.__proto__;
-	}
-
-	this.onGetdata = function(from, msg) {
-		msg.forEach(function(name) {
-			if (o = this.getObj(name, true)) {
-				this.__send_invobj(from, o);
-			}
-		}, this)
-	}
-
-	this.onInv = function(from, msg) {
-		for (var name in msg) {
-			// do we already have it? then we don't care
-			if (this.getObj(name)) {
-				// we already have it, so who cares
-			} else {
-				// start asking for it
-				// and record who has it
-				this.peerHas[from][name] = msg[name]
-
-				if (!(name in this.mapAlreadyAskedFor)) {
-					this.mapAlreadyAskedFor[name] = self.now();
-				} else {
-					this.mapAlreadyAskedFor[name] += 2 * 60 * 1000;
-				}
-				this.mapAskFor[from][name] = this.mapAlreadyAskedFor[name];
-				this.addTick()
-			}
-		}
-	}
-
-	this.onInvobj = function(from, o) {
-		// add it
-		if (this.addObj(o)) {
-			// stop asking other peers for it (if we are)
-			delete this.mapAlreadyAskedFor[o.id]
-
-			for (var p in this.mapAskFor) {
-				delete this.mapAskFor[p][o.id]
-			}
-
-			// we no longer care that our peers have this object
-			for (var p in this.peerHas) {
-				delete this.peerHas[p][o.id]
-			}
-
-			// now run a handler
-			self.handle(from, "obj:" + o.type, o.obj)
-		}
-	}
-
-	this.addObj = function(obj) {
-		return obj.seen(this.objects);
-	}
-
-	// obj must have `name` property
-	this.createObj = function(type, obj) {
-		var o = new InventoryObject(type, obj);
-
-		this.objects.create(o);
-		this.addObj(o);
-
-		return o;
-	}
-
-	self.on("peermgr:connect", function(from) {
-		var relaySet = this.objects.find({status:"relay"});
-
-		this.peerHas[from] = {};
-		this.tellPeer[from] = {};
-		this.mapAskFor[from] = {};
-
-		relaySet.forEach(function(o) {
-			this.tellPeer[from][o.id] = o.type;
-		}, this)
-
-		this.addTick();
-	}, this)
-
-	self.on("peermgr:disconnect", function(from) {
-		delete this.peerHas[from]
-		delete this.tellPeer[from]
-		delete this.mapAlreadyAskedFor[from]
-		delete this.mapAskFor[from];
-	}, this)
-
-	self.on("inv", this.onInv, this)
-	self.on("getdata", this.onGetdata, this)
-	self.on("invobj", this.onInvobj, this)
-	this.addTick();
-}
-
+/*
+	btc-inventory
+
+	Mimics the Bitcoin inventory system.
+*/
+
+function InventoryObject(type, obj) {
+	this.type = type;
+	this.obj = obj;
+	this.id = obj.id;
+}
+
+function InventoryState(status) {
+	this.status = status;
+
+	this.equals = function(v) {
+		return this.status == v.status;
+	}
+}
+
+InventoryObject.prototype = {
+	init: function(consensus) {
+		consensus.add(this.id, this);
+	},
+
+	seen: function(me) {
+		var ir = me.get(this.id);
+
+		if (ir.status == "none") {
+			me.set(this.id, new InventoryState("seen"))
+
+			return true;
+		}
+
+		return false;
+	},
+
+	relay: function(me) {
+		var ir = me.get(this.id);
+
+		if (ir.status == "seen") {
+			me.set(this.id, new InventoryState("relay"))
+
+			return true;
+		}
+
+		return false;
+	}
+}
+
+function Inventory(self) {
+	self.inventory = this;
+
+	this.polling = false;
+
+	this.objects = self.network.shared("inventory");
+
+	this.peerHas = {};
+	this.tellPeer = {};
+	this.mapAskFor = {};
+	this.mapAlreadyAskedFor = {};
+
+	this.addTick = function() {
+		if (!this.polling) {
+			this.polling = true;
+
+			self.tick(1000, this.invTick, this)
+		}
+	}
+
+	this.invTick = function() {
+		var doneSomething = false;
+
+		for (var p in this.tellPeer) {
+			var invPacket = this.tellPeer[p];
+
+			if (Object.keys(invPacket).length != 0) {
+				doneSomething = true;
+				this.__send_inv(p, invPacket)
+
+				this.tellPeer[p] = {}; // don't need to tell the peer that anymore
+			}
+		}
+
+		var askMap = {};
+		for (var p in this.peerHas) {
+			askMap[p] = [];
+		}
+
+		for (var p in this.mapAskFor) {
+			for (name in this.mapAskFor[p]) {
+				if (this.mapAskFor[p][name] <= self.now()) {
+					askMap[p].push(name);
+					delete this.mapAskFor[p][name]
+				}
+			}
+		}
+
+		for (var p in askMap) {
+			if (askMap[p].length == 0)
+				continue;
+
+			doneSomething = true;
+
+			this.__send_getdata(p, askMap[p])
+		}
+
+		if (!doneSomething) {
+			this.polling = false; // we don't need to poll again
+			return false; // don't tick again
+		}
+	}
+
+	/*
+		p, {name1: type1, name2: type2, ...}
+	*/
+	this.__send_inv = function(p, mapNameTypes) {
+		self.peermgr.send(p, "inv", mapNameTypes);
+	}
+
+	/*
+		p, [name1, name2, name3]
+	*/
+	this.__send_getdata = function(p, askList) {
+		self.peermgr.send(p, "getdata", askList);
+	}
+
+	/*
+		p, (InventoryObject) o
+	*/
+	this.__send_invobj = function(p, o) {
+		self.peermgr.send(p, "invobj", o);
+	}
+
+	this.relay = function(name, now) {
+		var ir = this.objects.get(name);
+
+		if ('relay' in ir) {
+			if (ir.relay(this.objects)) {
+				for (var p in this.tellPeer) {
+					if (now) {
+						this.__send_invobj(p, ir);
+					} else {
+						this.addTick();
+						this.tellPeer[p][name] = ir.type;
+					}
+				}
+			}
+		}
+	}
+
+	this.getObj = function(name, mustRelay) {
+		var ir = this.objects.get(name);
+
+		if (ir.status == "none")
+			return false;
+
+		if (mustRelay && ir.status == "seen")
+			return false;
+
+		return ir.__proto__;
+	}
+
+	this.onGetdata = function(from, msg) {
+		msg.forEach(function(name) {
+			if (o = this.getObj(name, true)) {
+				this.__send_invobj(from, o);
+			}
+		}, this)
+	}
+
+	this.onInv = function(from, msg) {
+		for (var name in msg) {
+			// do we already have it? then we don't care
+			if (this.getObj(name)) {
+				// we already have it, so who cares
+			} else {
+				// start asking for it
+				// and record who has it
+				this.peerHas[from][name] = msg[name]
+
+				if (!(name in this.mapAlreadyAskedFor)) {
+					this.mapAlreadyAskedFor[name] = self.now();
+				} else {
+					this.mapAlreadyAskedFor[name] += 2 * 60 * 1000;
+				}
+				this.mapAskFor[from][name] = this.mapAlreadyAskedFor[name];
+				this.addTick()
+			}
+		}
+	}
+
+	this.onInvobj = function(from, o) {
+		// add it
+		if (this.addObj(o)) {
+			// stop asking other peers for it (if we are)
+			delete this.mapAlreadyAskedFor[o.id]
+
+			for (var p in this.mapAskFor) {
+				delete this.mapAskFor[p][o.id]
+			}
+
+			// we no longer care that our peers have this object
+			for (var p in this.peerHas) {
+				delete this.peerHas[p][o.id]
+			}
+
+			// now run a handler
+			self.handle(from, "obj:" + o.type, o.obj)
+		}
+	}
+
+	this.addObj = function(obj) {
+		return obj.seen(this.objects);
+	}
+
+	// obj must have `name` property
+	this.createObj = function(type, obj) {
+		var o = new InventoryObject(type, obj);
+
+		this.objects.create(o);
+		this.addObj(o);
+
+		return o;
+	}
+
+	self.on("peermgr:connect", function(from) {
+		var relaySet = this.objects.find({status:"relay"});
+
+		this.peerHas[from] = {};
+		this.tellPeer[from] = {};
+		this.mapAskFor[from] = {};
+
+		relaySet.forEach(function(o) {
+			this.tellPeer[from][o.id] = o.type;
+		}, this)
+
+		this.addTick();
+	}, this)
+
+	self.on("peermgr:disconnect", function(from) {
+		delete this.peerHas[from]
+		delete this.tellPeer[from]
+		delete this.mapAlreadyAskedFor[from]
+		delete this.mapAskFor[from];
+	}, this)
+
+	self.on("inv", this.onInv, this)
+	self.on("getdata", this.onGetdata, this)
+	self.on("invobj", this.onInvobj, this)
+	this.addTick();
+}
+
 module.exports = Inventory;
\ No newline at end of file
diff --git a/sim/btc/mempool.js b/sim/TinyNets/public_html/btc/mempool.js
similarity index 100%
rename from sim/btc/mempool.js
rename to sim/TinyNets/public_html/btc/mempool.js
diff --git a/sim/btc/miner.js b/sim/TinyNets/public_html/btc/miner.js
old mode 100755
new mode 100644
similarity index 95%
rename from sim/btc/miner.js
rename to sim/TinyNets/public_html/btc/miner.js
index 71fdbfe0ba76e6daec6315c33fe8ea0abb9ce7be..ac023aa4799fb9f22c6564d097397e811c680622
--- a/sim/btc/miner.js
+++ b/sim/TinyNets/public_html/btc/miner.js
@@ -1,70 +1,70 @@
-function Miner(self) {
-	self.miner = this;
-
-	this.restage = function () {
-		self.miner.difficulty = self.miner.staged.difficulty;
-		if (self.miner.enabled) {
-			self.miner.stopMining()
-			self.miner.startMining()
-		}
-	}
-
-	self.mprob = 0;
-	this.mcb = function() {
-		return new self.blockchain.Block(self.blockchain.chainstate.head, self.now(), self);
-	}
-	this.staged = false;
-	this.enabled = false;
-	this.difficulty = false;
-
-	// expose mine() to NodeState
-	self.mine = function(amt, cb) {
-		this.mprob = amt;
-		if (cb)
-			self.miner.mcb = cb;
-
-		self.miner.startMining();
-	}
-
-	this.stopMining = function() {
-		if (!this.enabled)
-			return;
-
-		this.enabled = false;
-		self.deprob("mining")
-	}
-
-	this.startMining = function() {
-		if (this.enabled)
-			return;
-
-		this.staged = this.mcb.call(self); // restage next block
-		this.difficulty = this.staged.difficulty;
-		this.enabled = true;
-
-		if (self.mprob) {
-			self.prob("mining", self.mprob / this.staged.difficulty, function() {
-				self.handle(-1, "miner:success", this.staged);
-
-				this.restage();
-			}, this)
-		}
-	}
-
-	self.on("miner:success", function(from, b) {
-		b.time = self.now();
-		b.transactions = self.mempool.getList();
-
-		self.inventory.createObj("block", b)
-
-		if (self.blockchain.chainstate.enter(b) != -1) {
-			self.inventory.relay(b.id, true);
-		}
-	}, this)
-
-	self.on("blockchain:block", function(from, b) {
-		this.restage();
-	}, this)
-}
-
+function Miner(self) {
+	self.miner = this;
+
+	this.restage = function () {
+		self.miner.difficulty = self.miner.staged.difficulty;
+		if (self.miner.enabled) {
+			self.miner.stopMining()
+			self.miner.startMining()
+		}
+	}
+
+	self.mprob = 0;
+	this.mcb = function() {
+		return new self.blockchain.Block(self.blockchain.chainstate.head, self.now(), self);
+	}
+	this.staged = false;
+	this.enabled = false;
+	this.difficulty = false;
+
+	// expose mine() to NodeState
+	self.mine = function(amt, cb) {
+		this.mprob = amt;
+		if (cb)
+			self.miner.mcb = cb;
+
+		self.miner.startMining();
+	}
+
+	this.stopMining = function() {
+		if (!this.enabled)
+			return;
+
+		this.enabled = false;
+		self.deprob("mining")
+	}
+
+	this.startMining = function() {
+		if (this.enabled)
+			return;
+
+		this.staged = this.mcb.call(self); // restage next block
+		this.difficulty = this.staged.difficulty;
+		this.enabled = true;
+
+		if (self.mprob) {
+			self.prob("mining", self.mprob / this.staged.difficulty, function() {
+				self.handle(-1, "miner:success", this.staged);
+
+				this.restage();
+			}, this)
+		}
+	}
+
+	self.on("miner:success", function(from, b) {
+		b.time = self.now();
+		b.transactions = self.mempool.getList();
+
+		self.inventory.createObj("block", b)
+
+		if (self.blockchain.chainstate.enter(b) != -1) {
+			self.inventory.relay(b.id, true);
+		}
+	}, this)
+
+	self.on("blockchain:block", function(from, b) {
+		this.restage();
+	}, this)
+}
+
 module.exports = Miner;
\ No newline at end of file
diff --git a/sim/btc/transactions.js b/sim/TinyNets/public_html/btc/transactions.js
old mode 100755
new mode 100644
similarity index 95%
rename from sim/btc/transactions.js
rename to sim/TinyNets/public_html/btc/transactions.js
index f956b10caaff31312611fac86d28c4105fc499e8..e2973bfbe3d69a3f3da48c3e6f9370d753ea7090
--- a/sim/btc/transactions.js
+++ b/sim/TinyNets/public_html/btc/transactions.js
@@ -1,389 +1,389 @@
-/*
-	btc-transactions
-*/
-
-function TxIn(ref, n) {
-	this.ref = ref;
-	this.n = n;
-	this.k = ref.id + ':' + n;
-
-	this.isvalid = function() {return true;}
-}
-
-function TxOut(txid, n) {
-	this.n = n;
-	this.k = txid + ':' + n;
-}
-
-function Transaction(id, inputs, n) {
-	this.id = id;
-	this.vin = inputs;
-	this.vout = [];
-
-	for (var i = 0;i<n;i++) {
-		this.vout.push(new TxOut(this.id, i));
-	}
-}
-
-function MapOrphanTransactions(self) {
-	this.mapOrphans = [];
-	this.mapOrphansByPrev = {};
-}
-
-MapOrphanTransactions.prototype = {
-	add: function(b) {
-		if (this.mapOrphans.indexOf(b) != -1)
-			return false;
-
-		if (this.mapOrphans.length == 100) {
-			this.delete(this.mapOrphans[0]);
-		}
-
-		this.mapOrphans.push(b);
-
-		b.vin.forEach(function(input) {
-			if (!(input.k in this.mapOrphansByPrev))
-				this.mapOrphansByPrev[input.k] = []
-
-			this.mapOrphansByPrev[input.k].push(b)
-		}, this)
-
-		return true;
-	},
-
-	delete: function(b) {
-		if (this.mapOrphans.indexOf(b) == -1)
-			return false;
-
-		var removed = this.mapOrphans.splice(this.mapOrphans.indexOf(b), 1)
-
-		b.vin.forEach(function(input) {
-			var m = this.mapOrphansByPrev[input.k];
-
-			m.splice(m.indexOf(b), 1);
-
-			if (m.length == 0) {
-				delete this.mapOrphansByPrev[input.k]
-			}
-		}, this)
-
-		return true;
-	},
-
-	// returns boolean whether the block is an orphan already
-	is: function(b) {
-		if (this.mapOrphans.indexOf(b) == -1)
-			return false;
-
-		return true;
-	},
-
-	// finds any blocks that depended on this block within this maporphans
-	getForPrev: function(prev) {
-		var ret = [];
-
-		prev.vout.forEach(function(output) {
-			if (output.k in this.mapOrphansByPrev) {
-				ret = ret.concat(this.mapOrphansByPrev[output.k]);
-			}
-		}, this)
-
-		return ret;
-	}
-}
-
-function TransactionState(status, spentBy, spentByN) {
-	this.status = status;
-	this.spentBy = spentBy;
-	this.spentByN = spentByN;
-
-	this.equals = function(v) {
-		switch (v.status) {
-			case "spent":
-				if (this.status == "spent") {
-					if ('spentBy' in v) {
-						if (this.spentBy == v.spentBy) {
-							if ('spentByN' in v) {
-								if (this.spentByN == v.spentByN) {
-									return true;
-								}
-							}
-						}
-					}
-				}
-			break;
-			default:
-				if (v.status == this.status)
-					return true;
-			break;
-		}
-
-		return false;
-	}
-}
-
-// Transaction validator:
-function TransactionValidator(tx) {
-	this.tx = tx;
-	this.state = this.DEFAULT;
-	this.conflicts = [];
-}
-
-TransactionValidator.prototype = {
-	DEFAULT: 0,
-	ORPHAN: 1,
-	CONFLICT: 2,
-	INVALID: 3,
-	VALID: 4,
-
-	clean: function() {
-		var newConflicts = [];
-
-		this.conflicts.forEach(function(c) {
-			if (newConflicts.indexOf(c) == -1) {
-				newConflicts.push(c);
-			}
-		})
-
-		this.conflicts = newConflicts;
-	},
-
-	// apply a transaction to the state
-	apply: function(me) {
-		if (this.state != this.VALID) {
-			return false;
-		}
-
-		var removed = [];
-		var added = [];
-
-		// remove all conflicting transactions
-		this.conflicts.forEach(function(ctx) {
-			ctx.remove(me);
-			removed.push(ctx);
-		}, this)
-
-		// Now, spend our inputs...
-		var spentByN = 0;
-
-		this.tx.vin.forEach(function(input) {
-			me.set(input.k, new TransactionState("spent", this.tx, spentByN))
-			spentByN++;
-		}, this);
-
-		// Now, set our outputs as unspent...
-		this.tx.vout.forEach(function(output) {
-			me.set(output.k, new TransactionState("unspent"))
-		}, this);
-
-		added.push(this.tx);
-
-		return {added:added, removed:removed};
-	},
-
-	unapply: function(me) {
-		if (this.state != this.VALID)
-			return false;
-
-		var removed = [];
-
-		// remove child transactions
-		this.conflicts.forEach(function(ctx) {
-			ctx.remove(me);
-			removed.push(ctx);
-		}, this)
-
-		this.tx.remove(me);
-
-		removed.push(this.tx);
-
-		return {added:[], removed:removed};
-	}
-};
-
-Transaction.prototype = {
-	in: function(n) {
-		return new TxIn(this, n);
-	},
-
-	init: function(consensus) {
-		var n = 0;
-
-		this.vout.forEach(function(output) {
-			consensus.add(this.id + ':' + output.n, output);
-		}, this);
-	},
-
-	validate: function(me) {
-		// Check if a transaction is valid given state `me`.
-
-		var fin = new TransactionValidator(this);
-
-		this.vin.forEach(function(input) {
-			// Check if we have the input in our UTXO
-
-			var ir = me.get(input.k);
-
-			switch (ir.status) {
-				case "none":
-					if (fin.state == fin.DEFAULT) {
-						fin.state = fin.ORPHAN; // This input is not in our UTXO.
-					}
-				break;
-				case "spent":
-					if (fin.state < fin.INVALID) {
-						fin.state = fin.CONFLICT; // This input has been spent, and so this tx conflicts with another.
-
-						var sub = ir.spentBy.invalidate(me);
-
-						fin.conflicts.concat(sub.conflicts);
-						fin.conflicts.push(ir.spentBy);
-					}
-				break;
-			}
-
-			if (!input.isvalid()) {
-				fin.state = fin.INVALID; // This input is not valid. (Script failed?)
-			}
-		}, this)
-
-		if (fin.state == fin.DEFAULT)
-			fin.state = fin.VALID; // If we didn't run into problems, tx is valid.
-
-		fin.clean();
-
-		return fin;
-	},
-
-	invalidate: function(me) {
-		var fin = new TransactionValidator(this);
-
-		var fault = false;
-
-		this.vin.forEach(function(input) {
-			var ir = me.get(input.k);
-
-			if ((ir.status != "spent") || (ir.spentBy != this)) {
-				fault = true;
-			}
-		}, this)
-
-		if (fault) {
-			fin.state = fin.INVALID;
-			return fin;
-		}
-
-		this.vout.forEach(function(output) {
-			var ir = me.get(output.k);
-
-			if (ir.status == "spent") {
-				var sub = ir.spentBy.invalidate(me);
-
-				fin.conflicts.concat(sub.conflicts);
-				fin.conflicts.push(ir.spentBy);
-			}
-		}, this)
-
-		fin.state = fin.VALID;
-
-		return fin;
-	},
-
-	remove: function(me) {
-		// delete all outputs
-		this.vout.forEach(function(output) {
-			me.set(output.k, new TransactionState("none"))
-		}, this);
-
-		// set all inputs as unspent (if they weren't already purged)
-		this.vin.forEach(function(input) {
-			var cir = me.get(input.k)
-
-			if (cir.status == "spent")
-				me.set(input.k, new TransactionState("unspent"));
-
-		}, this);
-	},
-};
-
-function Transactions(self) {
-	self.transactions = this;
-
-	this.UTXO = self.network.shared("UTXO");
-	this.mapOrphans = new MapOrphanTransactions(self);
-
-	this.create = function(inputs, n) {
-		var nid = this.UTXO.rand();
-
-		var tx = new Transaction(nid, inputs, n);
-
-		this.UTXO.create(tx);
-
-		return tx;
-	}
-
-	// updates the mempool given a delta of transactions added or removed from the UTXO
-	this.updateMempool = function(delta) {
-		delta.added.forEach(function(addTx) {
-			self.mempool.add(addTx);
-		})
-		delta.removed.forEach(function(removeTx) {
-			self.mempool.remove(removeTx);
-		})
-	}
-
-	// tries to add transactions which this tx may have 
-	this.processOrphans = function(tx) {
-		// find any tx in mapOrphans which spends from our TxOuts
-
-		var descend = this.mapOrphans.getForPrev(tx);
-
-		descend.forEach(function(sub) {
-			if (this.mapOrphans.is(sub) && this.enter(sub)) {
-				self.log("removed tx from mapOrphans")
-				self.inventory.relay(sub.id)
-				this.processOrphans(sub)
-			}
-		}, this)
-	}
-
-	// attempts to enter tx into utxo/mempool/maporphans
-	// returns bool whether we accepted it, and it should be relayed
-	this.enter = function(tx, force) {
-		var val = tx.validate(this.UTXO);
-
-		if (force && val.state == val.CONFLICT)
-			val.state = val.VALID;
-
-		switch (val.state) {
-			case val.INVALID:
-				self.log("rejected tx, invalid")
-				return false;
-			break;
-			case val.ORPHAN:
-				this.mapOrphans.add(tx);
-				self.log("rejected tx, added to mapOrphans")
-				return false;
-			break;
-			case val.CONFLICT:
-				self.log("rejected tx, double-spend")
-				return false;
-			break;
-			case val.VALID:
-				var delta = val.apply(this.UTXO); // add to UTXO
-				this.updateMempool(delta);
-				this.processOrphans(tx);
-				return true;
-			break;
-		}
-	}
-
-	self.on("obj:tx", function(from, tx) {
-		self.log("Transactions: received tx " + tx.id)
-		if (this.enter(tx)) {
-			self.inventory.relay(tx.id)
-		}
-	}, this)
-}
-
+/*
+	btc-transactions
+*/
+
+function TxIn(ref, n) {
+	this.ref = ref;
+	this.n = n;
+	this.k = ref.id + ':' + n;
+
+	this.isvalid = function() {return true;}
+}
+
+function TxOut(txid, n) {
+	this.n = n;
+	this.k = txid + ':' + n;
+}
+
+function Transaction(id, inputs, n) {
+	this.id = id;
+	this.vin = inputs;
+	this.vout = [];
+
+	for (var i = 0;i<n;i++) {
+		this.vout.push(new TxOut(this.id, i));
+	}
+}
+
+function MapOrphanTransactions(self) {
+	this.mapOrphans = [];
+	this.mapOrphansByPrev = {};
+}
+
+MapOrphanTransactions.prototype = {
+	add: function(b) {
+		if (this.mapOrphans.indexOf(b) != -1)
+			return false;
+
+		if (this.mapOrphans.length == 100) {
+			this.delete(this.mapOrphans[0]);
+		}
+
+		this.mapOrphans.push(b);
+
+		b.vin.forEach(function(input) {
+			if (!(input.k in this.mapOrphansByPrev))
+				this.mapOrphansByPrev[input.k] = []
+
+			this.mapOrphansByPrev[input.k].push(b)
+		}, this)
+
+		return true;
+	},
+
+	delete: function(b) {
+		if (this.mapOrphans.indexOf(b) == -1)
+			return false;
+
+		var removed = this.mapOrphans.splice(this.mapOrphans.indexOf(b), 1)
+
+		b.vin.forEach(function(input) {
+			var m = this.mapOrphansByPrev[input.k];
+
+			m.splice(m.indexOf(b), 1);
+
+			if (m.length == 0) {
+				delete this.mapOrphansByPrev[input.k]
+			}
+		}, this)
+
+		return true;
+	},
+
+	// returns boolean whether the block is an orphan already
+	is: function(b) {
+		if (this.mapOrphans.indexOf(b) == -1)
+			return false;
+
+		return true;
+	},
+
+	// finds any blocks that depended on this block within this maporphans
+	getForPrev: function(prev) {
+		var ret = [];
+
+		prev.vout.forEach(function(output) {
+			if (output.k in this.mapOrphansByPrev) {
+				ret = ret.concat(this.mapOrphansByPrev[output.k]);
+			}
+		}, this)
+
+		return ret;
+	}
+}
+
+function TransactionState(status, spentBy, spentByN) {
+	this.status = status;
+	this.spentBy = spentBy;
+	this.spentByN = spentByN;
+
+	this.equals = function(v) {
+		switch (v.status) {
+			case "spent":
+				if (this.status == "spent") {
+					if ('spentBy' in v) {
+						if (this.spentBy == v.spentBy) {
+							if ('spentByN' in v) {
+								if (this.spentByN == v.spentByN) {
+									return true;
+								}
+							}
+						}
+					}
+				}
+			break;
+			default:
+				if (v.status == this.status)
+					return true;
+			break;
+		}
+
+		return false;
+	}
+}
+
+// Transaction validator:
+function TransactionValidator(tx) {
+	this.tx = tx;
+	this.state = this.DEFAULT;
+	this.conflicts = [];
+}
+
+TransactionValidator.prototype = {
+	DEFAULT: 0,
+	ORPHAN: 1,
+	CONFLICT: 2,
+	INVALID: 3,
+	VALID: 4,
+
+	clean: function() {
+		var newConflicts = [];
+
+		this.conflicts.forEach(function(c) {
+			if (newConflicts.indexOf(c) == -1) {
+				newConflicts.push(c);
+			}
+		})
+
+		this.conflicts = newConflicts;
+	},
+
+	// apply a transaction to the state
+	apply: function(me) {
+		if (this.state != this.VALID) {
+			return false;
+		}
+
+		var removed = [];
+		var added = [];
+
+		// remove all conflicting transactions
+		this.conflicts.forEach(function(ctx) {
+			ctx.remove(me);
+			removed.push(ctx);
+		}, this)
+
+		// Now, spend our inputs...
+		var spentByN = 0;
+
+		this.tx.vin.forEach(function(input) {
+			me.set(input.k, new TransactionState("spent", this.tx, spentByN))
+			spentByN++;
+		}, this);
+
+		// Now, set our outputs as unspent...
+		this.tx.vout.forEach(function(output) {
+			me.set(output.k, new TransactionState("unspent"))
+		}, this);
+
+		added.push(this.tx);
+
+		return {added:added, removed:removed};
+	},
+
+	unapply: function(me) {
+		if (this.state != this.VALID)
+			return false;
+
+		var removed = [];
+
+		// remove child transactions
+		this.conflicts.forEach(function(ctx) {
+			ctx.remove(me);
+			removed.push(ctx);
+		}, this)
+
+		this.tx.remove(me);
+
+		removed.push(this.tx);
+
+		return {added:[], removed:removed};
+	}
+};
+
+Transaction.prototype = {
+	in: function(n) {
+		return new TxIn(this, n);
+	},
+
+	init: function(consensus) {
+		var n = 0;
+
+		this.vout.forEach(function(output) {
+			consensus.add(this.id + ':' + output.n, output);
+		}, this);
+	},
+
+	validate: function(me) {
+		// Check if a transaction is valid given state `me`.
+
+		var fin = new TransactionValidator(this);
+
+		this.vin.forEach(function(input) {
+			// Check if we have the input in our UTXO
+
+			var ir = me.get(input.k);
+
+			switch (ir.status) {
+				case "none":
+					if (fin.state == fin.DEFAULT) {
+						fin.state = fin.ORPHAN; // This input is not in our UTXO.
+					}
+				break;
+				case "spent":
+					if (fin.state < fin.INVALID) {
+						fin.state = fin.CONFLICT; // This input has been spent, and so this tx conflicts with another.
+
+						var sub = ir.spentBy.invalidate(me);
+
+						fin.conflicts.concat(sub.conflicts);
+						fin.conflicts.push(ir.spentBy);
+					}
+				break;
+			}
+
+			if (!input.isvalid()) {
+				fin.state = fin.INVALID; // This input is not valid. (Script failed?)
+			}
+		}, this)
+
+		if (fin.state == fin.DEFAULT)
+			fin.state = fin.VALID; // If we didn't run into problems, tx is valid.
+
+		fin.clean();
+
+		return fin;
+	},
+
+	invalidate: function(me) {
+		var fin = new TransactionValidator(this);
+
+		var fault = false;
+
+		this.vin.forEach(function(input) {
+			var ir = me.get(input.k);
+
+			if ((ir.status != "spent") || (ir.spentBy != this)) {
+				fault = true;
+			}
+		}, this)
+
+		if (fault) {
+			fin.state = fin.INVALID;
+			return fin;
+		}
+
+		this.vout.forEach(function(output) {
+			var ir = me.get(output.k);
+
+			if (ir.status == "spent") {
+				var sub = ir.spentBy.invalidate(me);
+
+				fin.conflicts.concat(sub.conflicts);
+				fin.conflicts.push(ir.spentBy);
+			}
+		}, this)
+
+		fin.state = fin.VALID;
+
+		return fin;
+	},
+
+	remove: function(me) {
+		// delete all outputs
+		this.vout.forEach(function(output) {
+			me.set(output.k, new TransactionState("none"))
+		}, this);
+
+		// set all inputs as unspent (if they weren't already purged)
+		this.vin.forEach(function(input) {
+			var cir = me.get(input.k)
+
+			if (cir.status == "spent")
+				me.set(input.k, new TransactionState("unspent"));
+
+		}, this);
+	},
+};
+
+function Transactions(self) {
+	self.transactions = this;
+
+	this.UTXO = self.network.shared("UTXO");
+	this.mapOrphans = new MapOrphanTransactions(self);
+
+	this.create = function(inputs, n) {
+		var nid = this.UTXO.rand();
+
+		var tx = new Transaction(nid, inputs, n);
+
+		this.UTXO.create(tx);
+
+		return tx;
+	}
+
+	// updates the mempool given a delta of transactions added or removed from the UTXO
+	this.updateMempool = function(delta) {
+		delta.added.forEach(function(addTx) {
+			self.mempool.add(addTx);
+		})
+		delta.removed.forEach(function(removeTx) {
+			self.mempool.remove(removeTx);
+		})
+	}
+
+	// tries to add transactions which this tx may have 
+	this.processOrphans = function(tx) {
+		// find any tx in mapOrphans which spends from our TxOuts
+
+		var descend = this.mapOrphans.getForPrev(tx);
+
+		descend.forEach(function(sub) {
+			if (this.mapOrphans.is(sub) && this.enter(sub)) {
+				self.log("removed tx from mapOrphans")
+				self.inventory.relay(sub.id)
+				this.processOrphans(sub)
+			}
+		}, this)
+	}
+
+	// attempts to enter tx into utxo/mempool/maporphans
+	// returns bool whether we accepted it, and it should be relayed
+	this.enter = function(tx, force) {
+		var val = tx.validate(this.UTXO);
+
+		if (force && val.state == val.CONFLICT)
+			val.state = val.VALID;
+
+		switch (val.state) {
+			case val.INVALID:
+				self.log("rejected tx, invalid")
+				return false;
+			break;
+			case val.ORPHAN:
+				this.mapOrphans.add(tx);
+				self.log("rejected tx, added to mapOrphans")
+				return false;
+			break;
+			case val.CONFLICT:
+				self.log("rejected tx, double-spend")
+				return false;
+			break;
+			case val.VALID:
+				var delta = val.apply(this.UTXO); // add to UTXO
+				this.updateMempool(delta);
+				this.processOrphans(tx);
+				return true;
+			break;
+		}
+	}
+
+	self.on("obj:tx", function(from, tx) {
+		self.log("Transactions: received tx " + tx.id)
+		if (this.enter(tx)) {
+			self.inventory.relay(tx.id)
+		}
+	}, this)
+}
+
 module.exports = Transactions;
\ No newline at end of file
diff --git a/sim/d3.v3.min.js b/sim/TinyNets/public_html/d3.v3.min.js
old mode 100755
new mode 100644
similarity index 100%
rename from sim/d3.v3.min.js
rename to sim/TinyNets/public_html/d3.v3.min.js
diff --git a/sim/goog/array/array.js b/sim/TinyNets/public_html/goog/array/array.js
old mode 100755
new mode 100644
similarity index 100%
rename from sim/goog/array/array.js
rename to sim/TinyNets/public_html/goog/array/array.js
diff --git a/sim/goog/asserts/asserts.js b/sim/TinyNets/public_html/goog/asserts/asserts.js
old mode 100755
new mode 100644
similarity index 100%
rename from sim/goog/asserts/asserts.js
rename to sim/TinyNets/public_html/goog/asserts/asserts.js
diff --git a/sim/goog/base.js b/sim/TinyNets/public_html/goog/base.js
old mode 100755
new mode 100644
similarity index 100%
rename from sim/goog/base.js
rename to sim/TinyNets/public_html/goog/base.js
diff --git a/sim/goog/bootstrap/nodejs.js b/sim/TinyNets/public_html/goog/bootstrap/nodejs.js
old mode 100755
new mode 100644
similarity index 100%
rename from sim/goog/bootstrap/nodejs.js
rename to sim/TinyNets/public_html/goog/bootstrap/nodejs.js
diff --git a/sim/goog/bootstrap/webworkers.js b/sim/TinyNets/public_html/goog/bootstrap/webworkers.js
old mode 100755
new mode 100644
similarity index 100%
rename from sim/goog/bootstrap/webworkers.js
rename to sim/TinyNets/public_html/goog/bootstrap/webworkers.js
diff --git a/sim/goog/debug/error.js b/sim/TinyNets/public_html/goog/debug/error.js
old mode 100755
new mode 100644
similarity index 100%
rename from sim/goog/debug/error.js
rename to sim/TinyNets/public_html/goog/debug/error.js
diff --git a/sim/goog/deps.js b/sim/TinyNets/public_html/goog/deps.js
old mode 100755
new mode 100644
similarity index 100%
rename from sim/goog/deps.js
rename to sim/TinyNets/public_html/goog/deps.js
diff --git a/sim/goog/dom/nodetype.js b/sim/TinyNets/public_html/goog/dom/nodetype.js
old mode 100755
new mode 100644
similarity index 100%
rename from sim/goog/dom/nodetype.js
rename to sim/TinyNets/public_html/goog/dom/nodetype.js
diff --git a/sim/goog/object/object.js b/sim/TinyNets/public_html/goog/object/object.js
old mode 100755
new mode 100644
similarity index 100%
rename from sim/goog/object/object.js
rename to sim/TinyNets/public_html/goog/object/object.js
diff --git a/sim/goog/string/string.js b/sim/TinyNets/public_html/goog/string/string.js
old mode 100755
new mode 100644
similarity index 100%
rename from sim/goog/string/string.js
rename to sim/TinyNets/public_html/goog/string/string.js
diff --git a/sim/goog/structs/heap.js b/sim/TinyNets/public_html/goog/structs/heap.js
old mode 100755
new mode 100644
similarity index 100%
rename from sim/goog/structs/heap.js
rename to sim/TinyNets/public_html/goog/structs/heap.js
diff --git a/sim/goog/structs/node.js b/sim/TinyNets/public_html/goog/structs/node.js
old mode 100755
new mode 100644
similarity index 100%
rename from sim/goog/structs/node.js
rename to sim/TinyNets/public_html/goog/structs/node.js
diff --git a/sim/goog/structs/priorityqueue.js b/sim/TinyNets/public_html/goog/structs/priorityqueue.js
old mode 100755
new mode 100644
similarity index 100%
rename from sim/goog/structs/priorityqueue.js
rename to sim/TinyNets/public_html/goog/structs/priorityqueue.js
diff --git a/sim/graph.js b/sim/TinyNets/public_html/graph.js
similarity index 100%
rename from sim/graph.js
rename to sim/TinyNets/public_html/graph.js
diff --git a/sim/hub.js b/sim/TinyNets/public_html/hub.js
old mode 100755
new mode 100644
similarity index 97%
rename from sim/hub.js
rename to sim/TinyNets/public_html/hub.js
index 486eb3c72a54bc92e6720ed45b8418bbcb0be2d7..d6415866b75576c7a3a9d7266a160ef69b97535c
--- a/sim/hub.js
+++ b/sim/TinyNets/public_html/hub.js
@@ -1,149 +1,149 @@
-// hub script for dispatching simulation tasks to lots of servers
-
-console.log("THIS IS NOT STABLE")
-process.exit(1)
-
-var async = require('async')
-var sys = require('sys')
-
-var exec = require('child_process').exec;
-
-// todo just in case
-var escapeshell = function(cmd) {
-        return '"'+cmd+'"';
-};
-
-function runRemoteCommand(host, cmd, out, cb, pr) {
-        var r = Math.floor(Math.random() * 100000000)
-        var f;
-        if (out)
-                f = "ssh -o \"StrictHostKeyChecking no\" ubuntu@" + host + " " + escapeshell(cmd) + " > " + (out+"-"+r)
-        else
-                f = "ssh -o \"StrictHostKeyChecking no\" ubuntu@" + host + " " + escapeshell(cmd);
-
-        exec(f, function(err, stdout, stderr) {
-                if (err)
-                        console.log(err)
-
-                if (typeof pr != "undefined")
-                        process.stderr.write(stdout.replace(/\s+$/, ""))
-
-                cb(null, null)
-        })
-}
-
-
-/////////////////////////////////////////////////////////////
-
-hosts = [
-        ["ec2-23-20-147-173.compute-1.amazonaws.com", 8],
-        ["ec2-54-205-85-161.compute-1.amazonaws.com", 8],
-        ["ec2-54-204-121-80.compute-1.amazonaws.com", 8],
-        ["ec2-54-227-3-199.compute-1.amazonaws.com", 8],
-        ["ec2-54-205-28-168.compute-1.amazonaws.com", 8],
-        ["ec2-54-204-252-104.compute-1.amazonaws.com", 8],
-        ["ec2-54-221-142-38.compute-1.amazonaws.com", 8],
-        ["ec2-54-196-176-198.compute-1.amazonaws.com", 8],
-        ["ec2-54-196-157-128.compute-1.amazonaws.com", 8],
-        ["ec2-54-242-127-177.compute-1.amazonaws.com", 8],
-        ["ec2-54-227-221-158.compute-1.amazonaws.com", 8],
-        ["ec2-54-196-48-111.compute-1.amazonaws.com", 8],
-        ["ec2-67-202-55-118.compute-1.amazonaws.com", 8],
-        ["ec2-54-204-73-120.compute-1.amazonaws.com", 8],
-        ["ec2-23-20-85-175.compute-1.amazonaws.com", 8],
-        ["ec2-54-196-173-2.compute-1.amazonaws.com", 8],
-        ["ec2-54-211-248-182.compute-1.amazonaws.com", 8],
-        ["ec2-54-196-136-116.compute-1.amazonaws.com", 8],
-        ["ec2-54-234-230-115.compute-1.amazonaws.com", 8]
-]
-
-
-tasks = []
-
-for (var i=0;i<50;i++) {
-        // every percent less than 50 but > 20
-        for (var t=0;t<3;t++) {
-                // 3 trials of each
-                tasks.push(["cd ebfull.github.io && node sim.js " + (i/100).toFixed(2) + " normal", "/home/ubuntu/sim-"+i+"-normal-"+t])
-                tasks.push(["cd ebfull.github.io && node sim.js " + (i/100).toFixed(2) + " sybil", "/home/ubuntu/sim"+i+"-sybil-"+t])
-                tasks.push(["cd ebfull.github.io && node sim.js " + (i/100).toFixed(2) + " selfish", "/home/ubuntu/sim"+i+"-selfish-"+t])
-                tasks.push(["cd ebfull.github.io && node sim.js " + (i/100).toFixed(2) + " both", "/home/ubuntu/sim"+i+"-both-"+t])
-        }
-}
-
-/////////////////////////////////////////////////////////////
-
-function doStuff() {
-
-        var workers = async.queue(function(arg, cb) {
-                var server = arg.server;
-
-                var q = async.queue(function(nope, doneWithTasks) {
-                        var task;
-
-                        async.whilst(function() {return task = tasks.shift();}, function(taskDone) {
-                                console.log("dispatch (" + server[0] + "): " + task[0])
-                                runRemoteCommand(server[0], task[0], task[1], function() {
-                                        console.log("completed (" + server[0] + "): " + task[0])
-                                        taskDone()
-                                });
-                        }, doneWithTasks);
-                }, server[1])
-
-                q.drain = function() {
-                        host[3] = true;
-                        cb();
-                }
-
-                for (var i=0;i<server[1];i++) {
-                        q.push("nope")
-                }
-        }, hosts.length)
-
-        workers.drain = function() {
-                process.exit(1)
-        }
-
-        hosts.forEach(function(host) {
-                workers.push({server:host})
-        })
-
-        setInterval(function() {
-                // get stats for our workers
-                process.stderr.write("-----------------------\n")
-                hosts.forEach(function(host) {
-                        if (typeof host[3] == "undefined") {
-                                runRemoteCommand(host[0], "uptime", false, function() {
-                                        process.stderr.write(" (" + host[0] + ", concurrency=" + host[1] + ")\n")
-                                }, true)
-                        } else {
-                                process.stderr.write("DONE (" + host[0] + ", concurrency=" + host[1] + ")\n")
-                        }
-                })
-        }, 60 * 1000)
-}
-
-/////////////////////////////////////////////////////////////
-
-var provision = async.queue(function(host, cb) {
-        console.log("(" + host + ") provisioning")
-
-        runRemoteCommand(host, "echo -e '\\nMaxSessions 1000\\nMaxStartups 1000\\n' | sudo tee -a /etc/ssh/sshd_config; sudo service ssh restart", false, function() {
-                runRemoteCommand(host, "ps aux | grep -ie sim.js | awk '{print \\$2}' | xargs kill -9", false, function() {
-                        runRemoteCommand(host, "rm -rf ebfull.github.io; git clone https://github.com/ebfull/ebfull.github.io.git", false, function() {
-                                runRemoteCommand(host, "cd ebfull.github.io; node prep.js sim.js", false, function() {
-                                        console.log("(" + host + ") done provisioning");
-                                        cb();
-                                })
-                        })
-                });
-        });
-}, hosts.length);
-
-provision.drain = function() {
-        doStuff();
-}
-
-hosts.forEach(function(h) {
-        provision.push(h[0])
-})
+// hub script for dispatching simulation tasks to lots of servers
+
+console.log("THIS IS NOT STABLE")
+process.exit(1)
+
+var async = require('async')
+var sys = require('sys')
+
+var exec = require('child_process').exec;
+
+// todo just in case
+var escapeshell = function(cmd) {
+        return '"'+cmd+'"';
+};
+
+function runRemoteCommand(host, cmd, out, cb, pr) {
+        var r = Math.floor(Math.random() * 100000000)
+        var f;
+        if (out)
+                f = "ssh -o \"StrictHostKeyChecking no\" ubuntu@" + host + " " + escapeshell(cmd) + " > " + (out+"-"+r)
+        else
+                f = "ssh -o \"StrictHostKeyChecking no\" ubuntu@" + host + " " + escapeshell(cmd);
+
+        exec(f, function(err, stdout, stderr) {
+                if (err)
+                        console.log(err)
+
+                if (typeof pr != "undefined")
+                        process.stderr.write(stdout.replace(/\s+$/, ""))
+
+                cb(null, null)
+        })
+}
+
+
+/////////////////////////////////////////////////////////////
+
+hosts = [
+        ["ec2-23-20-147-173.compute-1.amazonaws.com", 8],
+        ["ec2-54-205-85-161.compute-1.amazonaws.com", 8],
+        ["ec2-54-204-121-80.compute-1.amazonaws.com", 8],
+        ["ec2-54-227-3-199.compute-1.amazonaws.com", 8],
+        ["ec2-54-205-28-168.compute-1.amazonaws.com", 8],
+        ["ec2-54-204-252-104.compute-1.amazonaws.com", 8],
+        ["ec2-54-221-142-38.compute-1.amazonaws.com", 8],
+        ["ec2-54-196-176-198.compute-1.amazonaws.com", 8],
+        ["ec2-54-196-157-128.compute-1.amazonaws.com", 8],
+        ["ec2-54-242-127-177.compute-1.amazonaws.com", 8],
+        ["ec2-54-227-221-158.compute-1.amazonaws.com", 8],
+        ["ec2-54-196-48-111.compute-1.amazonaws.com", 8],
+        ["ec2-67-202-55-118.compute-1.amazonaws.com", 8],
+        ["ec2-54-204-73-120.compute-1.amazonaws.com", 8],
+        ["ec2-23-20-85-175.compute-1.amazonaws.com", 8],
+        ["ec2-54-196-173-2.compute-1.amazonaws.com", 8],
+        ["ec2-54-211-248-182.compute-1.amazonaws.com", 8],
+        ["ec2-54-196-136-116.compute-1.amazonaws.com", 8],
+        ["ec2-54-234-230-115.compute-1.amazonaws.com", 8]
+]
+
+
+tasks = []
+
+for (var i=0;i<50;i++) {
+        // every percent less than 50 but > 20
+        for (var t=0;t<3;t++) {
+                // 3 trials of each
+                tasks.push(["cd ebfull.github.io && node sim.js " + (i/100).toFixed(2) + " normal", "/home/ubuntu/sim-"+i+"-normal-"+t])
+                tasks.push(["cd ebfull.github.io && node sim.js " + (i/100).toFixed(2) + " sybil", "/home/ubuntu/sim"+i+"-sybil-"+t])
+                tasks.push(["cd ebfull.github.io && node sim.js " + (i/100).toFixed(2) + " selfish", "/home/ubuntu/sim"+i+"-selfish-"+t])
+                tasks.push(["cd ebfull.github.io && node sim.js " + (i/100).toFixed(2) + " both", "/home/ubuntu/sim"+i+"-both-"+t])
+        }
+}
+
+/////////////////////////////////////////////////////////////
+
+function doStuff() {
+
+        var workers = async.queue(function(arg, cb) {
+                var server = arg.server;
+
+                var q = async.queue(function(nope, doneWithTasks) {
+                        var task;
+
+                        async.whilst(function() {return task = tasks.shift();}, function(taskDone) {
+                                console.log("dispatch (" + server[0] + "): " + task[0])
+                                runRemoteCommand(server[0], task[0], task[1], function() {
+                                        console.log("completed (" + server[0] + "): " + task[0])
+                                        taskDone()
+                                });
+                        }, doneWithTasks);
+                }, server[1])
+
+                q.drain = function() {
+                        host[3] = true;
+                        cb();
+                }
+
+                for (var i=0;i<server[1];i++) {
+                        q.push("nope")
+                }
+        }, hosts.length)
+
+        workers.drain = function() {
+                process.exit(1)
+        }
+
+        hosts.forEach(function(host) {
+                workers.push({server:host})
+        })
+
+        setInterval(function() {
+                // get stats for our workers
+                process.stderr.write("-----------------------\n")
+                hosts.forEach(function(host) {
+                        if (typeof host[3] == "undefined") {
+                                runRemoteCommand(host[0], "uptime", false, function() {
+                                        process.stderr.write(" (" + host[0] + ", concurrency=" + host[1] + ")\n")
+                                }, true)
+                        } else {
+                                process.stderr.write("DONE (" + host[0] + ", concurrency=" + host[1] + ")\n")
+                        }
+                })
+        }, 60 * 1000)
+}
+
+/////////////////////////////////////////////////////////////
+
+var provision = async.queue(function(host, cb) {
+        console.log("(" + host + ") provisioning")
+
+        runRemoteCommand(host, "echo -e '\\nMaxSessions 1000\\nMaxStartups 1000\\n' | sudo tee -a /etc/ssh/sshd_config; sudo service ssh restart", false, function() {
+                runRemoteCommand(host, "ps aux | grep -ie sim.js | awk '{print \\$2}' | xargs kill -9", false, function() {
+                        runRemoteCommand(host, "rm -rf ebfull.github.io; git clone https://github.com/ebfull/ebfull.github.io.git", false, function() {
+                                runRemoteCommand(host, "cd ebfull.github.io; node prep.js sim.js", false, function() {
+                                        console.log("(" + host + ") done provisioning");
+                                        cb();
+                                })
+                        })
+                });
+        });
+}, hosts.length);
+
+provision.drain = function() {
+        doStuff();
+}
+
+hosts.forEach(function(h) {
+        provision.push(h[0])
+})
diff --git a/sim/index.html b/sim/TinyNets/public_html/index.html
old mode 100755
new mode 100644
similarity index 96%
rename from sim/index.html
rename to sim/TinyNets/public_html/index.html
index 5d1d21aef77df9415deeee8a6ce1de626b232ebd..be54b24e2a768821c6714ca2b78b7ff58fafce56
--- a/sim/index.html
+++ b/sim/TinyNets/public_html/index.html
@@ -1,583 +1,583 @@
-<!-- simbit visualizer frontend for in-browser simulation -->
-<!doctype html>
-<html>
-	<head>
-		<title>simbit</title>
-		<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-		<style>
-		body {
-			font: 10px sans-serif;	
-		}
-
-			.network {
-			  border: 1px solid #DEDEDE;
-			  display:block;
-			  margin:auto;
-			}
-
-			svg {
-			  margin: auto;
-			  display:block;
-			}
-
-			rect {
-			  fill: none;
-			  pointer-events: all;
-			}
-
-			.node {
-			  fill: #000;
-			}
-
-			.link {
-			  stroke: #999;
-			}
-
-			input[type="number"] {
-				width: 50px;
-			}
-
-			path {
-				stroke: steelblue;
-				stroke-width: 2;
-				fill: none;
-			}
-
-			path.diff {
-				stroke: red;
-			}
-
-			path.avShort {
-				stroke: green;
-			}
-
-			.axis path,
-			.axis line {
-				fill: none;
-				stroke: grey;
-				stroke-width: 1;
-				shape-rendering: crispEdges;
-			}
-		</style>
-
-		<script type="text/javascript" src="d3.v3.min.js"></script>
-		<script type="text/javascript" src="jquery.min.js"></script>
-		<script type="text/javascript" src="require.js"></script>
-		<script src="graph.js"></script>
-		<script src="goog/base.js"></script>
-		<script>
-		goog.require("goog.structs.PriorityQueue")
-		</script>
-	</head>
-	<body>
-		<table>
-			<tr>
-				<td id="buttonparent">
-					<div style="float:left">
-						<input id="disable" type="button" value="Disable Visualizer">
-					</div>
-				</td>
-				<td id="optionparent">
-					<div id="graphwindows" style="display:none">
-						&nbsp;&nbsp;Short window:
-						<input id="shortwindow" type="number" min=1 value=10>
-						&nbsp;&nbsp;Long window:
-						<input id="longwindow" type="number" min=10 step=10 value=100>
-					</div>
-				</td>
-			</tr>
-			<tr>
-				<td id="networkparent">
-					<div class="network" style="width: 700px; height: 500px"></div>
-				</td>
-				<td id="graphparent" style="display:none">
-					<div class="graph" style="width: 700px; height: 500px"></div>
-				</td>
-				<td id="logs" valign="top">
-					
-				</td>
-			</tr>
-			<tr>
-				<td valign="top">
-					<div style="float:right">
-					Elapsed: <span id="elapsed">0 seconds</span>&nbsp;&nbsp;
-					<input id="play" type="button" value="Play">&nbsp;&nbsp;
-					<input id="pause" type="button" value="Pause">&nbsp;&nbsp;
-					</div>
-					
-					<div style="float:left">
-					Speed: <input id="slower" type="button" value="⇠"><input id="defaultspeed" type="button" value="Default"><input id="faster" type="button" value="⇢">
-					&nbsp;&nbsp;<span id="relspeed">(1.00x)</span>
-					</div>
-				</td>
-				<td id="timeBetweenBlocks" style="display:none" valign="top">
-					<center>
-					<h1>time between each block</h1>
-					</center>
-					<div class='scatter'>
-			          <!-- /the chart goes here -->
-			        </div>
-				</td>
-			</tr>
-		</table>
-
-
-		<script type="text/javascript">
-			// make it so that net.run() doesn't actually run
-			var DELAY_RUN = {net:false};
-
-			function Visualizer(div) {
-				this.nindex = 0;
-				this.svg = null;
-				this.divname = div;
-				this.force = null;
-				this.nodes = null;
-				this.links = null;
-				this.slink = null;
-				this.snode = null;
-				this.edges = {};
-				this.inodes = [];
-				this.lastmsgs = [];
-				this.updated = false;
-				this.colormap = {};
-				this.colormap_u = false;
-				this.link_colormap = {};
-				this.link_colormap_last = 0;
-			}
-
-			Visualizer.prototype = {
-				width: 700,
-				height: 500,
-				linkDistance: 30,
-				charge: -150,
-				gravity: .5,
-
-				drawGraph: function(data) {
-					var maxx = d3.max(data, function(d) { return d[0]; })
-					var maxdiff = d3.max(data, function(d) { return d[1]; })
-					var mintime = d3.min(data, function(d) { return d[2]; })
-					var maxtime = d3.max(data, function(d) { return d[2]; })
-
-					var margin = {top: 20, right: 60, bottom: 60, left: 60},
-						width = 700 - margin.left - margin.right,
-						height = 500 - margin.top - margin.bottom;
-
-					var x = d3.scale.linear()
-						.domain([0, maxx])
-						.range([ 0, width]);
-
-					var diff = d3.scale.linear()
-						.domain([0, maxdiff])
-						.range([ height, 0 ]);
-
-					var time = d3.scale.linear()
-						.domain([mintime, maxtime])
-						.range([ height, 0 ]);
-
-					 $("#graphparent").css('display', 'block')
-					 $("#graphwindows").css('display', 'inline')
-					 $(".graph").html("")
-
-					var chart = d3.select('.graph')
-						.append('svg:svg')
-						.attr('width', width + margin.right + margin.left)
-						.attr('height', height + margin.top + margin.bottom)
-						.attr('class', 'chart')
-
-					var main = chart.append('g')
-						.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
-						.attr('width', width)
-						.attr('height', height)
-						.attr('class', 'main')
-
-					// draw the x axis
-					var xAxis = d3.svg.axis()
-						.scale(x)
-						.orient('bottom');
-
-					main.append('g')
-						.attr('transform', 'translate(0,' + height + ')')
-						.attr('class', 'main axis date')
-						.call(xAxis)
-						.append("text")
-						.attr("dx", ".71em")
-						.attr("x", 420)
-						.attr("y", -6)
-						.style("text-anchor", "end")
-						.text("Block");
-
-					// draw the d axis
-					var diffAxis = d3.svg.axis()
-						.scale(diff)
-						.orient('left');
-
-					main.append('g')
-						.attr('transform', 'translate(0,0)')
-						.attr('class', 'main axis date')
-						.call(diffAxis)
-						.append("text")
-						.attr("transform", "rotate(-90)")
-						.attr("y", 6)
-						.attr("dy", ".71em")
-						.style("text-anchor", "end")
-						.text("Difficulty");
-
-					// draw the t axis
-					var timeAxis = d3.svg.axis()
-						.scale(time)
-						.orient('right');
-
-					main.append('g')
-						.attr('transform', 'translate(' + width + ',0)')
-						.attr('class', 'main axis date')
-						.call(timeAxis)
-						.append("text")
-						.attr("transform", "rotate(-90)")
-						.attr("y", -10)
-						.attr("dy", ".71em")
-						.style("text-anchor", "end")
-						.text("Block time");
-
-					var dline = d3.svg.line()
-						.x(function(d) { return x(d[0]); })
-						.y(function(d) { return diff(d[1]); });
-
-					var tsline = d3.svg.line()
-						.x(function(d) { return x(d[0]); })
-						.y(function(d) { return time(d[2]); });
-
-					var tlline = d3.svg.line()
-						.x(function(d) { return x(d[0]); })
-						.y(function(d) { return time(d[3]); });
-
-					var g = main.append("svg:g");
-
-					g.append("path")
-						.attr("class", "line diff" )
-						.attr("d", dline(data) );
-
-					g.append("path")
-						.attr("class", "line avShort" )
-						.attr("d", tsline(data) );
-
-					g.append("path")
-						.attr("class", "line" )
-						.attr("d", tlline(data) );
-				},
-
-				drawScatter: function(data) {
-					var maxy = d3.max(data, function(d) { return d[1]; })
-					var maxx = d3.max(data, function(d) { return d[0]; })
-
-					var margin = {top: 20, right: 15, bottom: 60, left: 60}
-				      , width = 500 - margin.left - margin.right
-				      , height = 300 - margin.top - margin.bottom;
-				    
-				    var x = d3.scale.linear()
-				              .domain([0, 1200])
-				              .range([ 0, width]);
-				    
-				    var y = d3.scale.linear()
-				            .domain([0, maxy])
-				            .range([ height, 0 ]);
-
-				     $("#timeBetweenBlocks").css('display', 'block')
-				     $(".scatter").html("")
-
-				    var chart = d3.select('.scatter')
-				  .append('svg:svg')
-				  .attr('width', width + margin.right + margin.left)
-				  .attr('height', height + margin.top + margin.bottom)
-				  .attr('class', 'chart')
-
-				    var main = chart.append('g')
-				  .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
-				  .attr('width', width)
-				  .attr('height', height)
-				  .attr('class', 'main')   
-				        
-				    // draw the x axis
-				    var xAxis = d3.svg.axis()
-				  .scale(x)
-				  .orient('bottom');
-
-				    main.append('g')
-				  .attr('transform', 'translate(0,' + height + ')')
-				  .attr('class', 'main axis date')
-				  .call(xAxis)
-				  .append("text")
-				  .attr("dx", ".71em")
-				  .attr("x", 420)
-				  .attr("y", -6)
-				  .style("text-anchor", "end")
-				  .text("Time between blocks (in seconds)");
-
-				    // draw the y axis
-				    var yAxis = d3.svg.axis()
-				  .scale(y)
-				  .orient('left');
-
-				    main.append('g')
-				  .attr('transform', 'translate(0,0)')
-				  .attr('class', 'main axis date')
-				  .call(yAxis)
-				  .append("text")
-				  .attr("transform", "rotate(-90)")
-				  .attr("y", 6)
-				  .attr("dy", ".71em")
-				  .style("text-anchor", "end")
-				  .text("Blocks");
-
-				    var g = main.append("svg:g"); 
-				    
-				    g.selectAll("scatter-dots")
-				      .data(data)
-				      .enter().append("svg:circle")
-				          .attr("cx", function (d,i) { return x(d[0]); } )
-				          .attr("cy", function (d) { return y(d[1]); } )
-				          .attr("r", 2);
-				},
-
-				init: function() {
-					// init the network layout/svg
-					$(this.divname).css('width', this.width);
-					$(this.divname).css('height', this.height);
-
-					this.force = d3.layout.force()
-						.size([this.width,this.height])
-						.nodes([]) // no nodes
-						.friction(0.5)
-						.linkDistance(function(link) {
-							return link.linkDistance;
-						})
-						.charge(this.charge)
-						.gravity(this.gravity);
-
-					this.svg = d3.select(this.divname).append("svg")
-				    	.attr("width", this.width)
-				    	.attr("height", this.height);
-
-				   	this.svg.append("rect")
-					    .attr("width", this.width)
-					    .attr("height", this.height);
-
-					this.nodes = this.force.nodes();
-					this.links = this.force.links();
-					this.slink = this.svg.selectAll(".link");
-					this.snode = this.svg.selectAll(".node");
-
-					this.force = this.force.on("tick", this.tick());
-
-					this.updated = true;
-					this.rehash(0);
-				},
-
-				log: function(msg) {
-					this.lastmsgs.push(msg);
-					if (this.lastmsgs.length > 35)
-						this.lastmsgs.shift();
-
-					var newlogs = "";
-
-					this.lastmsgs.forEach(function(e) {
-						newlogs += e + "<br />";
-					})
-
-					$("#logs").html(newlogs);
-				},
-
-				setColor: function(p, color) {
-					this.colormap_u = true;
-					this.colormap[p] = color;
-				},
-
-				setLinkActivity: function(p, now) {
-					this.link_colormap[p] = now;
-					this.link_colormap_last = 0;
-				},
-
-				getRandomLink: function() {
-					var result;
-					var count=1;
-					for (var prop in this.edges) {
-						if (Math.random() < 1/++count)
-							result = prop;
-					}
-					if (!result)
-						return -1;
-					var e = result.split("-");
-					return [parseInt(e[0]), parseInt(e[1])];
-				},
-
-				getRandomNode: function() {
-					return this.inodes[Math.floor(Math.random()*this.inodes.length)];
-				},
-
-				getKeyForID: function(id) {
-					return this.inodes.indexOf(id);
-				},
-
-				incCharge: function(amt) {
-					this.force.charge(this.force.charge() - amt);
-					this.updated = true;
-					///////////this.rehash();
-				},
-
-				addNode: function() {
-					// add a node, return the index
-					this.nodes.push({id:"n"+this.nindex});
-					this.inodes.push(this.nindex);
-					this.updated = true;
-					/////////////this.rehash();
-
-					this.nindex++;
-					return this.nindex-1;
-				},
-
-				connect: function(a, b, latency) {
-					if (this.edges.hasOwnProperty(a + '-' + b) || this.edges.hasOwnProperty(b + '-' + a))
-						return false; // we're already connected
-
-					if (a==b)
-						return false; // can't connect to ourself silly!
-
-					this.edges[a + '-' + b] = {source:this.nodes[this.getKeyForID(a)],target:this.nodes[this.getKeyForID(b)],linkDistance:latency};
-					this.links.push(this.edges[a + '-' + b]);
-
-					this.updated = true;
-					//////this.rehash();
-				},
-
-				disconnect: function(a, b) {
-					if (!this.edges.hasOwnProperty(a + '-' + b) && !this.edges.hasOwnProperty(b + '-' + a))
-						return false; // we're already disconnected
-
-					var i = this.links.indexOf(this.edges[a + '-' + b]);
-					if (i<0)
-						i = this.links.indexOf(this.edges[b + '-' + a]);
-
-					delete this.edges[a + '-' + b];
-					delete this.edges[b + '-' + a];
-
-					this.links.splice(i, 1); // remove the link
-
-					this.updated = true;
-					//////this.rehash();
-				},
-
-				removeNode: function(index) {
-					// remove a node at index
-					var i = this.getKeyForID(index);
-					if (i < 0)
-						return false; // this one has already been removed
-
-					this.nodes.splice(i, 1);
-					this.inodes.splice(i, 1);
-					this.updated = true;
-					///////////////////this.rehash();
-				},
-
-				tick: function() {
-					var svg = this.svg;
-					return function() {
-						svg.selectAll(".link").attr("x1", function(d) { return d.source.x; })
-							.attr("y1", function(d) { return d.source.y; })
-							.attr("x2", function(d) { return d.target.x; })
-							.attr("y2", function(d) { return d.target.y; })
-							.attr("id", function(d) {return "l-" + d.source.id + "-" + d.target.id;});
-
-						svg.selectAll(".node").attr("cx", function(d) { return d.x; })
-							.attr("cy", function(d) { return d.y; });
-					}
-				},
-
-				rehash: function(now) {
-					/***** COLORMAP *****/
-					if (this.colormap_u) {
-						for (var p in this.colormap) {
-							$(".n" + p).css('fill', this.colormap[p]);
-						}
-						this.colormap_u = false;
-					}
-
-					if (this.link_colormap_last < (now-100)) {
-						this.link_colormap_last = now;
-						for (var p in this.link_colormap) {
-							if (this.link_colormap[p] + 100 > now) {
-								$("#l-" + p).css('stroke', "black")
-							} else {
-								$("#l-" + p).css('stroke', "#999")
-								delete this.link_colormap[p];
-							}
-						}
-					}
-
-					if (!this.updated)
-						return;
-
-					this.slink = this.slink.data(this.force.links(), function(d) { return d.source.id + "-" + d.target.id; });
-					this.slink.enter().insert("line", ".node")
-						.attr("class", "link");
-					this.slink.exit().remove();
-
-					this.snode = this.snode.data(this.force.nodes(), function(d) {return d.id;});
-					this.snode.enter().append("circle").attr("class", function (d) {return "node " + d.id;})
-						.attr("r", 3)
-					//	.call(this.force.drag);
-					this.snode.exit().remove();
-
-					this.force.start();
-
-					this.updated = false;
-				}
-			};
-
-			$("#network").html("");
-			var VISUALIZER = new Visualizer(".network");
-			VISUALIZER.init();
-		</script>
-		<script type="text/javascript" src="sim.js"></script>
-		<script type="text/javascript">
-			var amt = 10;
-			var play = false;
-
-			$("#play").click(function() {
-				play = true;
-			})
-
-			$("#pause").click(function() {
-				play = false;
-			})
-
-			$("#slower").click(function() {
-				amt = amt / 2;
-				$("#relspeed").html("(" + (amt / 10).toFixed(2) + "x)");
-			})
-
-			$("#faster").click(function() {
-				amt = amt * 2;
-				$("#relspeed").html("(" + (amt / 10).toFixed(2) + "x)");
-			})
-
-			$("#defaultspeed").click(function() {
-				amt = 10;
-				$("#relspeed").html("(" + (amt / 10).toFixed(2) + "x)");
-			})
-
-			$("#disable").click(function() {
-				VISUALIZER.rehash = function() {return;}
-				VISUALIZER.force.stop();
-				$("#disable").prop("disabled", true);
-			})
-			$("#disable").prop("disabled", false);
-
-			setInterval(function() {
-				if (play && DELAY_RUN.net) {
-					DELAY_RUN.net._run(amt);
-					VISUALIZER.rehash(DELAY_RUN.net.now);
-					$("#elapsed").html((DELAY_RUN.net.now / 1000).toFixed(2) + " seconds")
-				}
-			}, 10);
-		</script>
-	</body>
-</html>
+<!-- simbit visualizer frontend for in-browser simulation -->
+<!doctype html>
+<html>
+	<head>
+		<title>simbit</title>
+		<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+		<style>
+		body {
+			font: 10px sans-serif;	
+		}
+
+			.network {
+			  border: 1px solid #DEDEDE;
+			  display:block;
+			  margin:auto;
+			}
+
+			svg {
+			  margin: auto;
+			  display:block;
+			}
+
+			rect {
+			  fill: none;
+			  pointer-events: all;
+			}
+
+			.node {
+			  fill: #000;
+			}
+
+			.link {
+			  stroke: #999;
+			}
+
+			input[type="number"] {
+				width: 50px;
+			}
+
+			path {
+				stroke: steelblue;
+				stroke-width: 2;
+				fill: none;
+			}
+
+			path.diff {
+				stroke: red;
+			}
+
+			path.avShort {
+				stroke: green;
+			}
+
+			.axis path,
+			.axis line {
+				fill: none;
+				stroke: grey;
+				stroke-width: 1;
+				shape-rendering: crispEdges;
+			}
+		</style>
+
+		<script type="text/javascript" src="d3.v3.min.js"></script>
+		<script type="text/javascript" src="jquery.min.js"></script>
+		<script type="text/javascript" src="require.js"></script>
+		<script src="graph.js"></script>
+		<script src="goog/base.js"></script>
+		<script>
+		goog.require("goog.structs.PriorityQueue")
+		</script>
+	</head>
+	<body>
+		<table>
+			<tr>
+				<td id="buttonparent">
+					<div style="float:left">
+						<input id="disable" type="button" value="Disable Visualizer">
+					</div>
+				</td>
+				<td id="optionparent">
+					<div id="graphwindows" style="display:none">
+						&nbsp;&nbsp;Short window:
+						<input id="shortwindow" type="number" min=1 value=10>
+						&nbsp;&nbsp;Long window:
+						<input id="longwindow" type="number" min=10 step=10 value=100>
+					</div>
+				</td>
+			</tr>
+			<tr>
+				<td id="networkparent">
+					<div class="network" style="width: 700px; height: 500px"></div>
+				</td>
+				<td id="graphparent" style="display:none">
+					<div class="graph" style="width: 700px; height: 500px"></div>
+				</td>
+				<td id="logs" valign="top">
+					
+				</td>
+			</tr>
+			<tr>
+				<td valign="top">
+					<div style="float:right">
+					Elapsed: <span id="elapsed">0 seconds</span>&nbsp;&nbsp;
+					<input id="play" type="button" value="Play">&nbsp;&nbsp;
+					<input id="pause" type="button" value="Pause">&nbsp;&nbsp;
+					</div>
+					
+					<div style="float:left">
+					Speed: <input id="slower" type="button" value="⇠"><input id="defaultspeed" type="button" value="Default"><input id="faster" type="button" value="⇢">
+					&nbsp;&nbsp;<span id="relspeed">(1.00x)</span>
+					</div>
+				</td>
+				<td id="timeBetweenBlocks" style="display:none" valign="top">
+					<center>
+					<h1>time between each block</h1>
+					</center>
+					<div class='scatter'>
+			          <!-- /the chart goes here -->
+			        </div>
+				</td>
+			</tr>
+		</table>
+
+
+		<script type="text/javascript">
+			// make it so that net.run() doesn't actually run
+			var DELAY_RUN = {net:false};
+
+			function Visualizer(div) {
+				this.nindex = 0;
+				this.svg = null;
+				this.divname = div;
+				this.force = null;
+				this.nodes = null;
+				this.links = null;
+				this.slink = null;
+				this.snode = null;
+				this.edges = {};
+				this.inodes = [];
+				this.lastmsgs = [];
+				this.updated = false;
+				this.colormap = {};
+				this.colormap_u = false;
+				this.link_colormap = {};
+				this.link_colormap_last = 0;
+			}
+
+			Visualizer.prototype = {
+				width: 700,
+				height: 500,
+				linkDistance: 30,
+				charge: -150,
+				gravity: .5,
+
+				drawGraph: function(data) {
+					var maxx = d3.max(data, function(d) { return d[0]; })
+					var maxdiff = d3.max(data, function(d) { return d[1]; })
+					var mintime = d3.min(data, function(d) { return d[2]; })
+					var maxtime = d3.max(data, function(d) { return d[2]; })
+
+					var margin = {top: 20, right: 60, bottom: 60, left: 60},
+						width = 700 - margin.left - margin.right,
+						height = 500 - margin.top - margin.bottom;
+
+					var x = d3.scale.linear()
+						.domain([0, maxx])
+						.range([ 0, width]);
+
+					var diff = d3.scale.linear()
+						.domain([0, maxdiff])
+						.range([ height, 0 ]);
+
+					var time = d3.scale.linear()
+						.domain([mintime, maxtime])
+						.range([ height, 0 ]);
+
+					 $("#graphparent").css('display', 'block')
+					 $("#graphwindows").css('display', 'inline')
+					 $(".graph").html("")
+
+					var chart = d3.select('.graph')
+						.append('svg:svg')
+						.attr('width', width + margin.right + margin.left)
+						.attr('height', height + margin.top + margin.bottom)
+						.attr('class', 'chart')
+
+					var main = chart.append('g')
+						.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
+						.attr('width', width)
+						.attr('height', height)
+						.attr('class', 'main')
+
+					// draw the x axis
+					var xAxis = d3.svg.axis()
+						.scale(x)
+						.orient('bottom');
+
+					main.append('g')
+						.attr('transform', 'translate(0,' + height + ')')
+						.attr('class', 'main axis date')
+						.call(xAxis)
+						.append("text")
+						.attr("dx", ".71em")
+						.attr("x", 420)
+						.attr("y", -6)
+						.style("text-anchor", "end")
+						.text("Block");
+
+					// draw the d axis
+					var diffAxis = d3.svg.axis()
+						.scale(diff)
+						.orient('left');
+
+					main.append('g')
+						.attr('transform', 'translate(0,0)')
+						.attr('class', 'main axis date')
+						.call(diffAxis)
+						.append("text")
+						.attr("transform", "rotate(-90)")
+						.attr("y", 6)
+						.attr("dy", ".71em")
+						.style("text-anchor", "end")
+						.text("Difficulty");
+
+					// draw the t axis
+					var timeAxis = d3.svg.axis()
+						.scale(time)
+						.orient('right');
+
+					main.append('g')
+						.attr('transform', 'translate(' + width + ',0)')
+						.attr('class', 'main axis date')
+						.call(timeAxis)
+						.append("text")
+						.attr("transform", "rotate(-90)")
+						.attr("y", -10)
+						.attr("dy", ".71em")
+						.style("text-anchor", "end")
+						.text("Block time");
+
+					var dline = d3.svg.line()
+						.x(function(d) { return x(d[0]); })
+						.y(function(d) { return diff(d[1]); });
+
+					var tsline = d3.svg.line()
+						.x(function(d) { return x(d[0]); })
+						.y(function(d) { return time(d[2]); });
+
+					var tlline = d3.svg.line()
+						.x(function(d) { return x(d[0]); })
+						.y(function(d) { return time(d[3]); });
+
+					var g = main.append("svg:g");
+
+					g.append("path")
+						.attr("class", "line diff" )
+						.attr("d", dline(data) );
+
+					g.append("path")
+						.attr("class", "line avShort" )
+						.attr("d", tsline(data) );
+
+					g.append("path")
+						.attr("class", "line" )
+						.attr("d", tlline(data) );
+				},
+
+				drawScatter: function(data) {
+					var maxy = d3.max(data, function(d) { return d[1]; })
+					var maxx = d3.max(data, function(d) { return d[0]; })
+
+					var margin = {top: 20, right: 15, bottom: 60, left: 60}
+				      , width = 500 - margin.left - margin.right
+				      , height = 300 - margin.top - margin.bottom;
+				    
+				    var x = d3.scale.linear()
+				              .domain([0, 1200])
+				              .range([ 0, width]);
+				    
+				    var y = d3.scale.linear()
+				            .domain([0, maxy])
+				            .range([ height, 0 ]);
+
+				     $("#timeBetweenBlocks").css('display', 'block')
+				     $(".scatter").html("")
+
+				    var chart = d3.select('.scatter')
+				  .append('svg:svg')
+				  .attr('width', width + margin.right + margin.left)
+				  .attr('height', height + margin.top + margin.bottom)
+				  .attr('class', 'chart')
+
+				    var main = chart.append('g')
+				  .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
+				  .attr('width', width)
+				  .attr('height', height)
+				  .attr('class', 'main')   
+				        
+				    // draw the x axis
+				    var xAxis = d3.svg.axis()
+				  .scale(x)
+				  .orient('bottom');
+
+				    main.append('g')
+				  .attr('transform', 'translate(0,' + height + ')')
+				  .attr('class', 'main axis date')
+				  .call(xAxis)
+				  .append("text")
+				  .attr("dx", ".71em")
+				  .attr("x", 420)
+				  .attr("y", -6)
+				  .style("text-anchor", "end")
+				  .text("Time between blocks (in seconds)");
+
+				    // draw the y axis
+				    var yAxis = d3.svg.axis()
+				  .scale(y)
+				  .orient('left');
+
+				    main.append('g')
+				  .attr('transform', 'translate(0,0)')
+				  .attr('class', 'main axis date')
+				  .call(yAxis)
+				  .append("text")
+				  .attr("transform", "rotate(-90)")
+				  .attr("y", 6)
+				  .attr("dy", ".71em")
+				  .style("text-anchor", "end")
+				  .text("Blocks");
+
+				    var g = main.append("svg:g"); 
+				    
+				    g.selectAll("scatter-dots")
+				      .data(data)
+				      .enter().append("svg:circle")
+				          .attr("cx", function (d,i) { return x(d[0]); } )
+				          .attr("cy", function (d) { return y(d[1]); } )
+				          .attr("r", 2);
+				},
+
+				init: function() {
+					// init the network layout/svg
+					$(this.divname).css('width', this.width);
+					$(this.divname).css('height', this.height);
+
+					this.force = d3.layout.force()
+						.size([this.width,this.height])
+						.nodes([]) // no nodes
+						.friction(0.5)
+						.linkDistance(function(link) {
+							return link.linkDistance;
+						})
+						.charge(this.charge)
+						.gravity(this.gravity);
+
+					this.svg = d3.select(this.divname).append("svg")
+				    	.attr("width", this.width)
+				    	.attr("height", this.height);
+
+				   	this.svg.append("rect")
+					    .attr("width", this.width)
+					    .attr("height", this.height);
+
+					this.nodes = this.force.nodes();
+					this.links = this.force.links();
+					this.slink = this.svg.selectAll(".link");
+					this.snode = this.svg.selectAll(".node");
+
+					this.force = this.force.on("tick", this.tick());
+
+					this.updated = true;
+					this.rehash(0);
+				},
+
+				log: function(msg) {
+					this.lastmsgs.push(msg);
+					if (this.lastmsgs.length > 35)
+						this.lastmsgs.shift();
+
+					var newlogs = "";
+
+					this.lastmsgs.forEach(function(e) {
+						newlogs += e + "<br />";
+					})
+
+					$("#logs").html(newlogs);
+				},
+
+				setColor: function(p, color) {
+					this.colormap_u = true;
+					this.colormap[p] = color;
+				},
+
+				setLinkActivity: function(p, now) {
+					this.link_colormap[p] = now;
+					this.link_colormap_last = 0;
+				},
+
+				getRandomLink: function() {
+					var result;
+					var count=1;
+					for (var prop in this.edges) {
+						if (Math.random() < 1/++count)
+							result = prop;
+					}
+					if (!result)
+						return -1;
+					var e = result.split("-");
+					return [parseInt(e[0]), parseInt(e[1])];
+				},
+
+				getRandomNode: function() {
+					return this.inodes[Math.floor(Math.random()*this.inodes.length)];
+				},
+
+				getKeyForID: function(id) {
+					return this.inodes.indexOf(id);
+				},
+
+				incCharge: function(amt) {
+					this.force.charge(this.force.charge() - amt);
+					this.updated = true;
+					///////////this.rehash();
+				},
+
+				addNode: function() {
+					// add a node, return the index
+					this.nodes.push({id:"n"+this.nindex});
+					this.inodes.push(this.nindex);
+					this.updated = true;
+					/////////////this.rehash();
+
+					this.nindex++;
+					return this.nindex-1;
+				},
+
+				connect: function(a, b, latency) {
+					if (this.edges.hasOwnProperty(a + '-' + b) || this.edges.hasOwnProperty(b + '-' + a))
+						return false; // we're already connected
+
+					if (a==b)
+						return false; // can't connect to ourself silly!
+
+					this.edges[a + '-' + b] = {source:this.nodes[this.getKeyForID(a)],target:this.nodes[this.getKeyForID(b)],linkDistance:latency};
+					this.links.push(this.edges[a + '-' + b]);
+
+					this.updated = true;
+					//////this.rehash();
+				},
+
+				disconnect: function(a, b) {
+					if (!this.edges.hasOwnProperty(a + '-' + b) && !this.edges.hasOwnProperty(b + '-' + a))
+						return false; // we're already disconnected
+
+					var i = this.links.indexOf(this.edges[a + '-' + b]);
+					if (i<0)
+						i = this.links.indexOf(this.edges[b + '-' + a]);
+
+					delete this.edges[a + '-' + b];
+					delete this.edges[b + '-' + a];
+
+					this.links.splice(i, 1); // remove the link
+
+					this.updated = true;
+					//////this.rehash();
+				},
+
+				removeNode: function(index) {
+					// remove a node at index
+					var i = this.getKeyForID(index);
+					if (i < 0)
+						return false; // this one has already been removed
+
+					this.nodes.splice(i, 1);
+					this.inodes.splice(i, 1);
+					this.updated = true;
+					///////////////////this.rehash();
+				},
+
+				tick: function() {
+					var svg = this.svg;
+					return function() {
+						svg.selectAll(".link").attr("x1", function(d) { return d.source.x; })
+							.attr("y1", function(d) { return d.source.y; })
+							.attr("x2", function(d) { return d.target.x; })
+							.attr("y2", function(d) { return d.target.y; })
+							.attr("id", function(d) {return "l-" + d.source.id + "-" + d.target.id;});
+
+						svg.selectAll(".node").attr("cx", function(d) { return d.x; })
+							.attr("cy", function(d) { return d.y; });
+					}
+				},
+
+				rehash: function(now) {
+					/***** COLORMAP *****/
+					if (this.colormap_u) {
+						for (var p in this.colormap) {
+							$(".n" + p).css('fill', this.colormap[p]);
+						}
+						this.colormap_u = false;
+					}
+
+					if (this.link_colormap_last < (now-100)) {
+						this.link_colormap_last = now;
+						for (var p in this.link_colormap) {
+							if (this.link_colormap[p] + 100 > now) {
+								$("#l-" + p).css('stroke', "black")
+							} else {
+								$("#l-" + p).css('stroke', "#999")
+								delete this.link_colormap[p];
+							}
+						}
+					}
+
+					if (!this.updated)
+						return;
+
+					this.slink = this.slink.data(this.force.links(), function(d) { return d.source.id + "-" + d.target.id; });
+					this.slink.enter().insert("line", ".node")
+						.attr("class", "link");
+					this.slink.exit().remove();
+
+					this.snode = this.snode.data(this.force.nodes(), function(d) {return d.id;});
+					this.snode.enter().append("circle").attr("class", function (d) {return "node " + d.id;})
+						.attr("r", 3)
+					//	.call(this.force.drag);
+					this.snode.exit().remove();
+
+					this.force.start();
+
+					this.updated = false;
+				}
+			};
+
+			$("#network").html("");
+			var VISUALIZER = new Visualizer(".network");
+			VISUALIZER.init();
+		</script>
+		<script type="text/javascript" src="sim.js"></script>
+		<script type="text/javascript">
+			var amt = 10;
+			var play = false;
+
+			$("#play").click(function() {
+				play = true;
+			})
+
+			$("#pause").click(function() {
+				play = false;
+			})
+
+			$("#slower").click(function() {
+				amt = amt / 2;
+				$("#relspeed").html("(" + (amt / 10).toFixed(2) + "x)");
+			})
+
+			$("#faster").click(function() {
+				amt = amt * 2;
+				$("#relspeed").html("(" + (amt / 10).toFixed(2) + "x)");
+			})
+
+			$("#defaultspeed").click(function() {
+				amt = 10;
+				$("#relspeed").html("(" + (amt / 10).toFixed(2) + "x)");
+			})
+
+			$("#disable").click(function() {
+				VISUALIZER.rehash = function() {return;}
+				VISUALIZER.force.stop();
+				$("#disable").prop("disabled", true);
+			})
+			$("#disable").prop("disabled", false);
+
+			setInterval(function() {
+				if (play && DELAY_RUN.net) {
+					DELAY_RUN.net._run(amt);
+					VISUALIZER.rehash(DELAY_RUN.net.now);
+					$("#elapsed").html((DELAY_RUN.net.now / 1000).toFixed(2) + " seconds")
+				}
+			}, 10);
+		</script>
+	</body>
+</html>
diff --git a/sim/jquery.min.js b/sim/TinyNets/public_html/jquery.min.js
old mode 100755
new mode 100644
similarity index 100%
rename from sim/jquery.min.js
rename to sim/TinyNets/public_html/jquery.min.js
diff --git a/sim/manager.js b/sim/TinyNets/public_html/manager.js
similarity index 98%
rename from sim/manager.js
rename to sim/TinyNets/public_html/manager.js
index e13093e7089aea01fed69b23ec9eb91c31d1da0e..f8ac0a0147df851eb2efddb8a088a6acc40e99d3 100644
--- a/sim/manager.js
+++ b/sim/TinyNets/public_html/manager.js
@@ -201,14 +201,14 @@ function Manager(self) {
                 data: packet.data
             };
             if (this.hasSeen(thisFlood)) {                                      // If I have seen it before, don't forward
-                self.log(`not forwarding ${packet.data} from port ${packet.port}`);
+//                self.log(`not forwarding ${packet.data} from port ${packet.port}`);
                 return;
             }
             this.seenFloods.push(thisFlood);                                    // Remember the packet
             if (packet.dest === self.id) {                                      // If I am destination
                 const nextPort = this.getMinCostPort(packet.src);               // Pick the port to send ACK based off minimizing cost
                 self.log(`got flood ${packet.data} from port ${packet.port}. ACKing ${packet.src} along port ${nextPort}`);
-                this.sendPacket(ACK, packet.src, 0, self.id, nextPort);
+                this.sendPacket(ACK, packet.src, undefined, self.id, undefined, undefined, nextPort);
             } else {
                 packet.hopcount++;                                              // Increment hopcount
                 
diff --git a/sim/network.js b/sim/TinyNets/public_html/network.js
old mode 100755
new mode 100644
similarity index 95%
rename from sim/network.js
rename to sim/TinyNets/public_html/network.js
index 0a4bc19382ff50042c29b463d18a0b9eec834c67..a8728a0c3642c4400d1cf5c9b34d46022824c01e
--- a/sim/network.js
+++ b/sim/TinyNets/public_html/network.js
@@ -1,534 +1,534 @@
-if (typeof goog == "undefined") {
-	require('./goog/bootstrap/nodejs')
-	goog.require("goog.structs.PriorityQueue")
-}
-
-var BitArray = require("./bit-array");
-
-var topologySeed = Math.floor(Math.random() * 1000000000);
-
-function latency(a, b) {
-	var min = 10 + Math.abs(((a*topologySeed)^(b*topologySeed)) % 300);
-	var avgVariance = 15;
-
-	return Math.floor((Math.log(1-Math.random())/-1) * (avgVariance)) + min
-}
-
-/*
-	Events
-
-	This object is used to coordinate events that occur in the simulation. It is a proxy
-	for a priority queue.
-*/
-function Events() {
-	this.heapBuckets = {
-		"default":new goog.structs.PriorityQueue(),
-		"probs":new goog.structs.PriorityQueue()
-	};
-}
-
-Events.prototype = {
-	add: function(time, event, bucket) {
-		if (typeof bucket == "undefined")
-			bucket = "default"
-
-		this.heapBuckets[bucket].insert(time, event);
-	},
-
-	next: function(maxtime) {
-		var best = Number.POSITIVE_INFINITY;
-		var best_bucket = false;
-
-		for (var b in this.heapBuckets) {
-			var time = this.heapBuckets[b].peekKey();
-
-			if (typeof time == "undefined")
-				continue; // bucket is empty
-
-			if (time < best) {
-				best = time;
-				best_bucket = b;
-			}
-		}
-
-		if (!best_bucket)
-			return false;
-
-		if (best > maxtime)
-			return false;
-
-		return {time:best, event:this.heapBuckets[best_bucket].dequeue()};
-	}
-}
-
-/*
-	Interface:
-		run(network) - runs an event against the Network
-		delay - msec delay before the event should occur once it is committed to the network
-
-	NodeEvent: runs a function against a node's state
-	NodeMessageEvent: triggers a handler against a node's state, follows middleware paths
-	NodeTickEvent: a repetitive function ran against a node's state.
-		- if the function returns false, we do not run the tick again
-		- the return of this function can override the delay if it is a number
-	NodeProbabilisticTickEvent: a pool of events that can occur at any time, like mining
-*/
-
-function NodeEvent(delay, nid, f, ctx) {
-	this.delay = delay;
-
-	this.run = function(network) {
-		if (typeof ctx == "undefined")
-			ctx = network.nodes[nid]
-
-		f.call(ctx);
-	}
-}
-
-function NodeMessageEvent(from, nid, name, obj) {
-	this.delay = latency(from, nid);
-
-	this.run = function(network) {
-		network.setLinkActivity(from, nid)
-
-		network.nodes[nid].handle(from, name, obj)
-	}
-}
-
-function NodeTickEvent(delay, f, ctx) {
-	this.delay = delay;
-
-	this.run = function(network) {
-		var newDelay;
-		if ((newDelay = f.call(ctx)) !== false) {
-			if (typeof newDelay == "number")
-				this.delay = newDelay;
-
-			network.exec(this)
-		}
-	}
-}
-
-/****
-@probability: used to describe probability of event firing every msec
-@event: function called
-@ctx: function context
-
-NodeProbabilisticTickEvent.ignore is used to disable an event if it's
-never going to occur again, thus avoiding a seek and destroy on the 
-binary heap.
-****/
-function NodeProbabilisticTickEvent(probability, event, nid, ctx) {
-	// The event will occur in this.delay msec
-	this.delay = Math.floor(Math.log(1.0-Math.random())/-probability);
-	this.ignore = false;
-
-	this.run = function(network) {
-		if (this.ignore)
-			return false;
-
-		if (typeof ctx == "undefined")
-			ctx = network.nodes[nid]
-
-		// fire event
-		event.call(ctx)
-	}
-}
-
-/*
-	NodeState
-
-	Has a bunch of helper functions for the node.
-*/
-
-function NodeState(node, network, id) {
-	this.id = id;
-	this.network = network;
-	this.handlers = [];
-
-	node.setup(this);
-}
-
-NodeState.prototype = {
-	prob: function(label, p, f, ctx) {
-		this.network.pregister(label, p, this.id, f, ctx)
-	},
-
-	deprob: function(label) {
-		this.network.depregister(label, this.id)
-	},
-
-	setColor: function(color) {
-		this.network.setColor(this.id, color);
-	},
-
-	connect: function(remoteid) {
-		this.network.connect(this.id, remoteid);
-	},
-
-	disconnect: function(remoteid) {
-		this.network.disconnect(this.id, remoteid);
-	},
-
-	log: function(msg) {
-		var str = "[" + this.now() + "]: " + this.id + ": " + msg;
-
-		this.network.log(str)
-	},
-
-	now: function() {
-		return this.network.now;
-	},
-
-	tick: function(delay, f, ctx) {
-		if (typeof ctx == "undefined")
-			ctx = this;
-
-		this.network.exec(new NodeTickEvent(delay, f, ctx))
-	},
-
-	send: function(nid, name, obj) {
-		this.network.exec(new NodeMessageEvent(this.id, nid, name, obj))
-	},
-
-	handle: function(from, name, obj) {
-		if (typeof this.handlers[name] != "undefined") {
-			return this.handlers[name](from, obj)
-		}
-	},
-
-	on: function(name, f, ctx) {
-		if (typeof ctx == "undefined")
-			ctx = this;
-
-		if (typeof this.handlers[name] != "undefined") {
-			var oldHandler = this.handlers[name];
-			this.handlers[name] = function(from, obj) {if (f.call(ctx, from, obj) !== false) oldHandler.call(ctx, from, obj);}
-		} else {
-			this.handlers[name] = function(from, obj) {return f.call(ctx, from, obj);};
-		}
-	},
-
-	delay: function(delay, f, ctx) {
-		this.network.exec(new NodeEvent(delay, this.id, f, ctx))
-	}
-}
-
-function Client() {
-	this._use = [];
-	this._init = false;
-}
-
-Client.prototype = {
-	setup: function(node) {
-		// run middleware
-		for (var i=0;i<this._use.length;i++) {
-			new this._use[i](node);
-		}
-
-		// run init functions
-		if (this._init)
-			this._init.call(node);
-	},
-
-	use: function(f) {
-		this._use.push(f);
-	},
-
-	init: function(callback) {
-		if (!this._init)
-			this._init = callback;
-		else {
-			var oldInit = this._init;
-			this._init = function() {oldInit.call(this); callback.call(this)};
-		}
-	},
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-function Consensus() {
-	this.store = {}; // key value store for objects themselves
-	this.n = 0;
-}
-
-function LocalizedState(consensus) {
-	this.consensus = consensus;
-	this.id = consensus.n++;
-}
-
-Consensus.prototype = {
-	add: function(key, obj) {
-		if (!(key in this.store))
-			this.store[key] = {obj:obj, states:[]};
-	},
-	obtain: function() {
-		return new LocalizedState(this);
-	},
-	rand: function() {
-		/*return String.fromCharCode(
-			Math.floor(Math.random() * 256),
-			Math.floor(Math.random() * 256),
-			Math.floor(Math.random() * 256),
-			Math.floor(Math.random() * 256),
-			Math.floor(Math.random() * 256),
-			Math.floor(Math.random() * 256),
-			Math.floor(Math.random() * 256),
-			Math.floor(Math.random() * 256),
-			Math.floor(Math.random() * 256),
-			Math.floor(Math.random() * 256),
-			Math.floor(Math.random() * 256),
-			Math.floor(Math.random() * 256),
-			Math.floor(Math.random() * 256),
-			Math.floor(Math.random() * 256),
-			Math.floor(Math.random() * 256)
-			)*/
-		return 'xxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
-		    var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
-		    return v.toString(16);
-		});
-	}
-};
-
-function ConsensusState() {
-	this.status = "none";
-
-	this.equals = function(v) { if ((this.status == "none") && (v.status == "none")) { return true; } return false;}
-}
-
-LocalizedState.prototype = {
-	// sets k's state to v
-	set: function(k, v) {
-		if (!(k in this.consensus.store)) {
-			this.consensus.add(k, {})
-		}
-
-		var states = this.consensus.store[k].states;
-		var del = false;
-		states.forEach(function(s) {
-			if (s.members.get(this.id))
-				del = s;
-		}, this)
-
-		if (del !== false) {
-			del.members.set(this.id, false);
-			if (del.members.count() == 0) {
-				states.splice(states.indexOf(del), 1);
-			}
-		}
-
-		var proc = false;
-
-		states.forEach(function(s) {
-			if (s.state.equals(v)) {
-				proc = s;
-			}
-		}, this)
-
-		if (proc !== false)
-			proc.members.set(this.id, true);
-		else {
-			var n = {state:v, members: new BitArray(1024)};
-			n.state.__proto__ = this.consensus.store[k].obj;
-			n.members.set(this.id, true);
-			states.push(n)
-		}
-	},
-	get: function(k) {
-		if (!(k in this.consensus.store)) {
-			this.consensus.add(k, {})
-		}
-
-		var states = this.consensus.store[k].states;
-		var get = false;
-		states.forEach(function(s) {
-			if (s.members.get(this.id)) {
-				get = s;
-			}
-		}, this)
-
-		if (get !== false)
-			return get.state;
-		else {
-			var gen = new ConsensusState();
-			this.set(k, gen);
-			return gen;
-		}
-	},
-	find: function(v) {
-		// TODO: improve efficiency of this by indexing states -> objects
-
-		var results = [];
-
-		for (k in this.consensus.store) {
-			var state = this.get(k);
-
-			if (state.equals(v)) {
-				results.push(state.__proto__);
-			}
-		}
-
-		return results;
-	},
-	create: function(obj) {
-		return obj.init(this.consensus);
-	},
-	rand: function() {
-		return this.consensus.rand();
-	}
-};
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-function Network() {
-	this.events = new Events(); // normal events
-	this.pevents = {}; // probablistic event buckets
-	if (typeof VISUALIZER != "undefined") {
-		this.visualizer = VISUALIZER;
-	} else {
-		this.visualizer = false;
-	}
-	this.now = 0;
-	this.maxrun = 0;
-
-	this.nodes = [];
-	this.nindex = 0;
-
-	this._shared = {};
-}
-
-Network.prototype = {
-	Client: Client,
-	// random data
-	rand: function(name) {
-		return Consensus.prototype.rand();
-	},
-	// grab a shared cache object
-	shared: function(name) {
-		if (typeof this._shared[name] == "undefined") {
-			this._shared[name] = new Consensus();
-		}
-
-		return this._shared[name].obtain();
-	},
-
-	log: function(str) {
-		if (this.visualizer)
-			this.visualizer.log(str)
-		else
-			console.log(str)
-	},
-
-	// registers probablistic event
-	pregister: function(label, p, nid, cb, ctx) {
-		if (typeof this.pevents[nid + "-" + label] == "undefined") {
-			this.pevents[nid + "-" + label] = new NodeProbabilisticTickEvent(p, cb, nid, ctx)
-			this.exec(this.pevents[nid + "-" + label], "probs")
-		}
-	},
-
-	// deregisters a probablistic event
-	depregister: function(label, nid) {
-		if (typeof this.pevents[nid + "-" + label] != "undefined") {
-			this.pevents[nid + "-" + label].ignore = true;
-			delete this.pevents[nid + "-" + label];
-		}
-	},
-
-	// sets the color of the node in the visualizer
-	setColor: function(id, color) {
-		if (typeof this.nodes[id] != "undefined")
-		if (this.visualizer) {
-			this.visualizer.setColor(this.nodes[id]._vid, color);
-		}
-	},
-
-	// could be used to show that network activity occurred between two nodes
-	setLinkActivity: function(from, to) {
-		if (typeof this.nodes[to] != "undefined")
-		if (typeof this.nodes[from] != "undefined")
-		if (this.visualizer) {
-			this.visualizer.setLinkActivity("n" + this.nodes[from]._vid + "-n" + this.nodes[to]._vid, this.now);
-			this.visualizer.setLinkActivity("n" + this.nodes[to]._vid + "-n" + this.nodes[from]._vid, this.now);
-		}
-	},
-
-	// places an event in the queue
-	exec: function(e, bucket) {
-		this.events.add(e.delay+this.now, e, bucket)
-	},
-
-	// connects two nodes in the visualizer
-	connect: function (a, b) {
-		if (this.visualizer) {
-			this.visualizer.connect(this.nodes[a]._vid, this.nodes[b]._vid, latency(this.nodes[a].id, this.nodes[b].id));
-		}
-	},
-
-	// disconnects two nodes in the visualizer
-	disconnect: function (a, b) {
-		if (this.visualizer) {
-			this.visualizer.disconnect(this.nodes[a]._vid, this.nodes[b]._vid);
-		}
-	},
-
-	// adds amt nodes using the node constructor parameter
-	add: function(amt, node) {
-		for (;amt>0;amt--) {
-			var state = new NodeState(node, this, this.nindex);
-			if (this.visualizer)
-				state._vid = this.visualizer.addNode();
-
-			this.nodes[this.nindex] = state;
-			this.nindex++;
-		}
-	},
-
-	// run buffer time (msec) worth of tasks
-	run: function(msec, next) {
-		this.maxrun = this.now + msec;
-
-		if (typeof(DELAY_RUN) != "undefined") {
-			// this is an async call
-			DELAY_RUN.net = this;
-			DELAY_RUN.cb = next;
-		} else {
-			this._run(msec)
-			if (next)
-				next.call(this);
-		}
-	},
-
-	_run: function(msec) {
-		if (this.now >= this.maxrun) {
-			if (DELAY_RUN) {
-				if (DELAY_RUN.cb) {
-					var cb = DELAY_RUN.cb;
-					DELAY_RUN.cb = false;
-					cb.call(this);
-				}
-			}
-			return;
-		}
-
-		var max = Math.min(this.now + msec, this.maxrun);
-
-		// actually run msec worth of shit
-		while (e = this.events.next(max)) {
-			this.now = e.time;
-			e.event.run(this)
-		}
-
-		this.now = max;
-	},
-
-	check: function(msec, f) {
-		this.exec(new NodeTickEvent(msec, f, this))
-	},
-
-	stop: function() {
-		this.maxrun = this.now;
-	}
-}
-
+if (typeof goog == "undefined") {
+	require('./goog/bootstrap/nodejs')
+	goog.require("goog.structs.PriorityQueue")
+}
+
+var BitArray = require("./bit-array");
+
+var topologySeed = Math.floor(Math.random() * 1000000000);
+
+function latency(a, b) {
+	var min = 10 + Math.abs(((a*topologySeed)^(b*topologySeed)) % 300);
+	var avgVariance = 15;
+
+	return Math.floor((Math.log(1-Math.random())/-1) * (avgVariance)) + min
+}
+
+/*
+	Events
+
+	This object is used to coordinate events that occur in the simulation. It is a proxy
+	for a priority queue.
+*/
+function Events() {
+	this.heapBuckets = {
+		"default":new goog.structs.PriorityQueue(),
+		"probs":new goog.structs.PriorityQueue()
+	};
+}
+
+Events.prototype = {
+	add: function(time, event, bucket) {
+		if (typeof bucket == "undefined")
+			bucket = "default"
+
+		this.heapBuckets[bucket].insert(time, event);
+	},
+
+	next: function(maxtime) {
+		var best = Number.POSITIVE_INFINITY;
+		var best_bucket = false;
+
+		for (var b in this.heapBuckets) {
+			var time = this.heapBuckets[b].peekKey();
+
+			if (typeof time == "undefined")
+				continue; // bucket is empty
+
+			if (time < best) {
+				best = time;
+				best_bucket = b;
+			}
+		}
+
+		if (!best_bucket)
+			return false;
+
+		if (best > maxtime)
+			return false;
+
+		return {time:best, event:this.heapBuckets[best_bucket].dequeue()};
+	}
+}
+
+/*
+	Interface:
+		run(network) - runs an event against the Network
+		delay - msec delay before the event should occur once it is committed to the network
+
+	NodeEvent: runs a function against a node's state
+	NodeMessageEvent: triggers a handler against a node's state, follows middleware paths
+	NodeTickEvent: a repetitive function ran against a node's state.
+		- if the function returns false, we do not run the tick again
+		- the return of this function can override the delay if it is a number
+	NodeProbabilisticTickEvent: a pool of events that can occur at any time, like mining
+*/
+
+function NodeEvent(delay, nid, f, ctx) {
+	this.delay = delay;
+
+	this.run = function(network) {
+		if (typeof ctx == "undefined")
+			ctx = network.nodes[nid]
+
+		f.call(ctx);
+	}
+}
+
+function NodeMessageEvent(from, nid, name, obj) {
+	this.delay = latency(from, nid);
+
+	this.run = function(network) {
+		network.setLinkActivity(from, nid)
+
+		network.nodes[nid].handle(from, name, obj)
+	}
+}
+
+function NodeTickEvent(delay, f, ctx) {
+	this.delay = delay;
+
+	this.run = function(network) {
+		var newDelay;
+		if ((newDelay = f.call(ctx)) !== false) {
+			if (typeof newDelay == "number")
+				this.delay = newDelay;
+
+			network.exec(this)
+		}
+	}
+}
+
+/****
+@probability: used to describe probability of event firing every msec
+@event: function called
+@ctx: function context
+
+NodeProbabilisticTickEvent.ignore is used to disable an event if it's
+never going to occur again, thus avoiding a seek and destroy on the 
+binary heap.
+****/
+function NodeProbabilisticTickEvent(probability, event, nid, ctx) {
+	// The event will occur in this.delay msec
+	this.delay = Math.floor(Math.log(1.0-Math.random())/-probability);
+	this.ignore = false;
+
+	this.run = function(network) {
+		if (this.ignore)
+			return false;
+
+		if (typeof ctx == "undefined")
+			ctx = network.nodes[nid]
+
+		// fire event
+		event.call(ctx)
+	}
+}
+
+/*
+	NodeState
+
+	Has a bunch of helper functions for the node.
+*/
+
+function NodeState(node, network, id) {
+	this.id = id;
+	this.network = network;
+	this.handlers = [];
+
+	node.setup(this);
+}
+
+NodeState.prototype = {
+	prob: function(label, p, f, ctx) {
+		this.network.pregister(label, p, this.id, f, ctx)
+	},
+
+	deprob: function(label) {
+		this.network.depregister(label, this.id)
+	},
+
+	setColor: function(color) {
+		this.network.setColor(this.id, color);
+	},
+
+	connect: function(remoteid) {
+		this.network.connect(this.id, remoteid);
+	},
+
+	disconnect: function(remoteid) {
+		this.network.disconnect(this.id, remoteid);
+	},
+
+	log: function(msg) {
+		var str = "[" + this.now() + "]: " + this.id + ": " + msg;
+
+		this.network.log(str)
+	},
+
+	now: function() {
+		return this.network.now;
+	},
+
+	tick: function(delay, f, ctx) {
+		if (typeof ctx == "undefined")
+			ctx = this;
+
+		this.network.exec(new NodeTickEvent(delay, f, ctx))
+	},
+
+	send: function(nid, name, obj) {
+		this.network.exec(new NodeMessageEvent(this.id, nid, name, obj))
+	},
+
+	handle: function(from, name, obj) {
+		if (typeof this.handlers[name] != "undefined") {
+			return this.handlers[name](from, obj)
+		}
+	},
+
+	on: function(name, f, ctx) {
+		if (typeof ctx == "undefined")
+			ctx = this;
+
+		if (typeof this.handlers[name] != "undefined") {
+			var oldHandler = this.handlers[name];
+			this.handlers[name] = function(from, obj) {if (f.call(ctx, from, obj) !== false) oldHandler.call(ctx, from, obj);}
+		} else {
+			this.handlers[name] = function(from, obj) {return f.call(ctx, from, obj);};
+		}
+	},
+
+	delay: function(delay, f, ctx) {
+		this.network.exec(new NodeEvent(delay, this.id, f, ctx))
+	}
+}
+
+function Client() {
+	this._use = [];
+	this._init = false;
+}
+
+Client.prototype = {
+	setup: function(node) {
+		// run middleware
+		for (var i=0;i<this._use.length;i++) {
+			new this._use[i](node);
+		}
+
+		// run init functions
+		if (this._init)
+			this._init.call(node);
+	},
+
+	use: function(f) {
+		this._use.push(f);
+	},
+
+	init: function(callback) {
+		if (!this._init)
+			this._init = callback;
+		else {
+			var oldInit = this._init;
+			this._init = function() {oldInit.call(this); callback.call(this)};
+		}
+	},
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+function Consensus() {
+	this.store = {}; // key value store for objects themselves
+	this.n = 0;
+}
+
+function LocalizedState(consensus) {
+	this.consensus = consensus;
+	this.id = consensus.n++;
+}
+
+Consensus.prototype = {
+	add: function(key, obj) {
+		if (!(key in this.store))
+			this.store[key] = {obj:obj, states:[]};
+	},
+	obtain: function() {
+		return new LocalizedState(this);
+	},
+	rand: function() {
+		/*return String.fromCharCode(
+			Math.floor(Math.random() * 256),
+			Math.floor(Math.random() * 256),
+			Math.floor(Math.random() * 256),
+			Math.floor(Math.random() * 256),
+			Math.floor(Math.random() * 256),
+			Math.floor(Math.random() * 256),
+			Math.floor(Math.random() * 256),
+			Math.floor(Math.random() * 256),
+			Math.floor(Math.random() * 256),
+			Math.floor(Math.random() * 256),
+			Math.floor(Math.random() * 256),
+			Math.floor(Math.random() * 256),
+			Math.floor(Math.random() * 256),
+			Math.floor(Math.random() * 256),
+			Math.floor(Math.random() * 256)
+			)*/
+		return 'xxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
+		    var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
+		    return v.toString(16);
+		});
+	}
+};
+
+function ConsensusState() {
+	this.status = "none";
+
+	this.equals = function(v) { if ((this.status == "none") && (v.status == "none")) { return true; } return false;}
+}
+
+LocalizedState.prototype = {
+	// sets k's state to v
+	set: function(k, v) {
+		if (!(k in this.consensus.store)) {
+			this.consensus.add(k, {})
+		}
+
+		var states = this.consensus.store[k].states;
+		var del = false;
+		states.forEach(function(s) {
+			if (s.members.get(this.id))
+				del = s;
+		}, this)
+
+		if (del !== false) {
+			del.members.set(this.id, false);
+			if (del.members.count() == 0) {
+				states.splice(states.indexOf(del), 1);
+			}
+		}
+
+		var proc = false;
+
+		states.forEach(function(s) {
+			if (s.state.equals(v)) {
+				proc = s;
+			}
+		}, this)
+
+		if (proc !== false)
+			proc.members.set(this.id, true);
+		else {
+			var n = {state:v, members: new BitArray(1024)};
+			n.state.__proto__ = this.consensus.store[k].obj;
+			n.members.set(this.id, true);
+			states.push(n)
+		}
+	},
+	get: function(k) {
+		if (!(k in this.consensus.store)) {
+			this.consensus.add(k, {})
+		}
+
+		var states = this.consensus.store[k].states;
+		var get = false;
+		states.forEach(function(s) {
+			if (s.members.get(this.id)) {
+				get = s;
+			}
+		}, this)
+
+		if (get !== false)
+			return get.state;
+		else {
+			var gen = new ConsensusState();
+			this.set(k, gen);
+			return gen;
+		}
+	},
+	find: function(v) {
+		// TODO: improve efficiency of this by indexing states -> objects
+
+		var results = [];
+
+		for (k in this.consensus.store) {
+			var state = this.get(k);
+
+			if (state.equals(v)) {
+				results.push(state.__proto__);
+			}
+		}
+
+		return results;
+	},
+	create: function(obj) {
+		return obj.init(this.consensus);
+	},
+	rand: function() {
+		return this.consensus.rand();
+	}
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+function Network() {
+	this.events = new Events(); // normal events
+	this.pevents = {}; // probablistic event buckets
+	if (typeof VISUALIZER != "undefined") {
+		this.visualizer = VISUALIZER;
+	} else {
+		this.visualizer = false;
+	}
+	this.now = 0;
+	this.maxrun = 0;
+
+	this.nodes = [];
+	this.nindex = 0;
+
+	this._shared = {};
+}
+
+Network.prototype = {
+	Client: Client,
+	// random data
+	rand: function(name) {
+		return Consensus.prototype.rand();
+	},
+	// grab a shared cache object
+	shared: function(name) {
+		if (typeof this._shared[name] == "undefined") {
+			this._shared[name] = new Consensus();
+		}
+
+		return this._shared[name].obtain();
+	},
+
+	log: function(str) {
+		if (this.visualizer)
+			this.visualizer.log(str)
+		else
+			console.log(str)
+	},
+
+	// registers probablistic event
+	pregister: function(label, p, nid, cb, ctx) {
+		if (typeof this.pevents[nid + "-" + label] == "undefined") {
+			this.pevents[nid + "-" + label] = new NodeProbabilisticTickEvent(p, cb, nid, ctx)
+			this.exec(this.pevents[nid + "-" + label], "probs")
+		}
+	},
+
+	// deregisters a probablistic event
+	depregister: function(label, nid) {
+		if (typeof this.pevents[nid + "-" + label] != "undefined") {
+			this.pevents[nid + "-" + label].ignore = true;
+			delete this.pevents[nid + "-" + label];
+		}
+	},
+
+	// sets the color of the node in the visualizer
+	setColor: function(id, color) {
+		if (typeof this.nodes[id] != "undefined")
+		if (this.visualizer) {
+			this.visualizer.setColor(this.nodes[id]._vid, color);
+		}
+	},
+
+	// could be used to show that network activity occurred between two nodes
+	setLinkActivity: function(from, to) {
+		if (typeof this.nodes[to] != "undefined")
+		if (typeof this.nodes[from] != "undefined")
+		if (this.visualizer) {
+			this.visualizer.setLinkActivity("n" + this.nodes[from]._vid + "-n" + this.nodes[to]._vid, this.now);
+			this.visualizer.setLinkActivity("n" + this.nodes[to]._vid + "-n" + this.nodes[from]._vid, this.now);
+		}
+	},
+
+	// places an event in the queue
+	exec: function(e, bucket) {
+		this.events.add(e.delay+this.now, e, bucket)
+	},
+
+	// connects two nodes in the visualizer
+	connect: function (a, b) {
+		if (this.visualizer) {
+			this.visualizer.connect(this.nodes[a]._vid, this.nodes[b]._vid, latency(this.nodes[a].id, this.nodes[b].id));
+		}
+	},
+
+	// disconnects two nodes in the visualizer
+	disconnect: function (a, b) {
+		if (this.visualizer) {
+			this.visualizer.disconnect(this.nodes[a]._vid, this.nodes[b]._vid);
+		}
+	},
+
+	// adds amt nodes using the node constructor parameter
+	add: function(amt, node) {
+		for (;amt>0;amt--) {
+			var state = new NodeState(node, this, this.nindex);
+			if (this.visualizer)
+				state._vid = this.visualizer.addNode();
+
+			this.nodes[this.nindex] = state;
+			this.nindex++;
+		}
+	},
+
+	// run buffer time (msec) worth of tasks
+	run: function(msec, next) {
+		this.maxrun = this.now + msec;
+
+		if (typeof(DELAY_RUN) != "undefined") {
+			// this is an async call
+			DELAY_RUN.net = this;
+			DELAY_RUN.cb = next;
+		} else {
+			this._run(msec)
+			if (next)
+				next.call(this);
+		}
+	},
+
+	_run: function(msec) {
+		if (this.now >= this.maxrun) {
+			if (DELAY_RUN) {
+				if (DELAY_RUN.cb) {
+					var cb = DELAY_RUN.cb;
+					DELAY_RUN.cb = false;
+					cb.call(this);
+				}
+			}
+			return;
+		}
+
+		var max = Math.min(this.now + msec, this.maxrun);
+
+		// actually run msec worth of shit
+		while (e = this.events.next(max)) {
+			this.now = e.time;
+			e.event.run(this)
+		}
+
+		this.now = max;
+	},
+
+	check: function(msec, f) {
+		this.exec(new NodeTickEvent(msec, f, this))
+	},
+
+	stop: function() {
+		this.maxrun = this.now;
+	}
+}
+
 module.exports = new Network();
\ No newline at end of file
diff --git a/sim/peermgr.js b/sim/TinyNets/public_html/peermgr.js
old mode 100755
new mode 100644
similarity index 96%
rename from sim/peermgr.js
rename to sim/TinyNets/public_html/peermgr.js
index 76219223b2ef4e82bd9adde93932fdd3c089a9a7..6902aec24c833e888a4183417d106fcf9d795e5b
--- a/sim/peermgr.js
+++ b/sim/TinyNets/public_html/peermgr.js
@@ -1,313 +1,313 @@
-/*
-The PeerMgr is the inter-client behavior middleware for establishing connections
-with other peers, thus forming a network.
-
-(This peer manager is not intended to accurately mimic bitcoin yet.)
-
-Current behavior: every 1 second it checks to see if it has 'maxpeers'. If not, it attempts
-either to connect to an archived addr, or get addresses from other nodes it has contacted.
-Initially, the only archived addr is the bootstrap node, 0. Once the node has received
-maxpeers, it stops ticking.
-*/
-
-function PeerState(id, lastmessage) {
-	this.id = id;
-	this.lastmessage = lastmessage;
-	this.active = false;
-	this.locked = true;
-	this.msgqueue = [];
-}
-
-function PeerMgr(self) {
-	// attach to nodestate 'peers' property
-	// self.peers = this;
-	self.peermgr = this;
-
-	this.freeze = false;
-	this.ticking = false;
-	this.peers = {}; // current established or attempted connections
-	this.numpeers = 0; // the number of peers we have
-	this.maxpeers = 8; // the max number of peers we can have
-	if (self.id != 0)
-		this.nodearchive = [new PeerState(0, self.now())]; // a node archived, initialized with a bootstrap node
-	else
-		this.nodearchive = []
-
-	var peerTick = function() {
-		if (!this.freeze && (this.numpeers < this.maxpeers)) {
-			// we need more peers
-
-			// let's try connecting to a peer in our nodearchive, if there are any
-			if (this.nodearchive.length) {
-				var p = this.nodearchive.shift();
-				this.nodearchive.push(p);
-
-				// try connecting to this node, fails if we're already trying/connected
-				this.connect(p);
-			}
-
-			// if we have (active) connections, ask them for new peers
-			if (this.numpeers) {
-				var randomPeer = this.peers[Object.keys(this.peers)[Math.floor(Math.random() * Object.keys(this.peers).length)]]
-
-				if (randomPeer.active) {
-					this.getpeers(randomPeer.id)
-				}
-			}
-
-			if (self.now() > 1000 * 1000) // after 1000 seconds, let's tick every 5 seconds instead
-				return 5000;
-		} else {
-			self.peermgr.ticking = false;
-			return false; // no more ticking necessary
-		}
-	}
-
-	var startTicking = function() {
-		if (!self.peermgr.ticking) {
-			self.peermgr.ticking = true;
-
-			self.tick(1000, peerTick, self.peermgr);
-		}
-	}
-
-	this.numActive = function() {
-		var n = 0;
-		for (var p in this.peers) {
-			if (this.peers[p].active) {
-				n++;
-			}
-		}
-		return n;
-	}
-
-	this.send = function(to, name, msg) {
-		if (this.peers[to].active) {
-			if (this.peers[to].locked) {
-				this.peers[to].msgqueue.push({name:name,obj:msg})
-			} else {
-				self.send(this.peers[to].id, "__peermsg", {name:name,obj:msg})
-			}
-		}
-	}
-
-	this.each = function(cb) {
-		for (var p in this.peers) {
-			if (this.peers[p].active)
-				cb.call(self, p)
-		}
-	}
-
-	// sends a message to all active peers
-	this.broadcast = function(name, msg) {
-		for (var p in this.peers) {
-			this.send(p, name, msg)
-		}
-	}
-
-	// request peers from a remote node
-	this.getpeers = function(p) {
-		self.send(p, 'getpeers', {});
-	}
-
-	// send a portion of our archived node list
-	this.sendpeers = function(p) {
-		var someNodes = this.nodearchive.slice(0, 15)
-		if (someNodes.length == 0) {
-			var randomPeer = this.peers[Object.keys(this.peers)[Math.floor(Math.random() * Object.keys(this.peers).length)]]
-			if (randomPeer.active)
-				someNodes = [randomPeer]
-		}
-
-		self.send(p, 'peerlist', someNodes);
-	}
-
-	// connect to a remote node (if we haven't already tried)
-	this.connect = function(p) {
-		if (self.id == p.id)
-			return; // can't connect to ourselves!
-
-		if (typeof this.peers[p.id] == "undefined") {
-			this.peers[p.id] = p;
-			this.numpeers += 1;
-			self.send(p.id, 'connect', {})
-		}
-	}
-
-	// disconnect from a remote node
-	this.disconnect = function(p) {
-		if (typeof this.peers[p] != "undefined") {
-			var peer = this.peers[p];
-			delete this.peers[p];
-
-			//if (peer.active) {
-				self.send(p, 'disconnect', {})
-				self.disconnect(p);
-				startTicking();
-			//}
-
-			this.nodearchive.push(peer);
-			this.numpeers -= 1;
-			self.handle(p, "peermgr:disconnect", p)
-		}
-	}
-
-	// accept a remote node's connection
-	this.accept = function(p) {
-		p.locked = true; // wait for an ack
-		self.send(p.id, 'accept', {})
-	}
-
-	// reject a remote node's connection
-	this.reject = function(p) {
-		var someNodes = this.nodearchive.slice(0, 15)
-		if (someNodes.length == 0) {
-			var randomPeer = this.peers[Object.keys(this.peers)[Math.floor(Math.random() * Object.keys(this.peers).length)]]
-			if (randomPeer.active)
-				someNodes = [this.randomPeer]
-		}
-
-		self.send(p.id, 'reject', someNodes)
-	}
-
-	this.onAck = function(from, o) {
-		if (typeof this.peers[from] != "undefined") {
-			this.peers[from].locked = false;
-			this.peers[from].lastmessage = self.now()
-
-			if (this.peers[from].msgqueue.length > 0) {
-				var domsg = this.peers[from].msgqueue.shift();
-				this.peers[from].locked = true;
-				self.send(this.peers[from].id, "__peermsg", {name:domsg.name,obj:domsg.obj})
-			}
-		}
-	}
-
-	// processes a received message from another peer
-	this.onReceive = function(from, o) {
-		if (typeof this.peers[from] != "undefined" && this.peers[from].active) {
-			self.send(from, 'ack', {})
-			self.handle(from, o.name, o.obj)
-			this.peers[from].lastmessage = self.now();
-		}
-	}
-
-	// receive a peerlist message
-	this.onPeerlist = function(from, obj) {
-		// are we connected to this peer?
-		if (this.peers[from] != "undefined") {
-			// add these peers to our nodearchive
-			// if we don't have them already
-
-			for (var i=0;i<obj.length;i++) {
-				var candidate = obj[i];
-
-				// remove redundant existing nodearchive objects
-				for (var k=0;k<this.nodearchive.length;k++) {
-					if (this.nodearchive[k].id == candidate.id) {
-						this.nodearchive.splice(k, 1);
-					}
-				}
-
-				this.nodearchive.push(new PeerState(candidate.id, self.now()))
-			}
-		}
-	}
-
-	// receive a getpeers message
-	this.onGetpeers = function(from, obj) {
-		// are we connected to this peer?
-		if (this.peers[from] != "undefined") {
-			this.sendpeers(from)
-		}
-	}
-
-	// receive a reject message
-	this.onReject = function(from, obj) {
-		if (typeof this.peers[from] != "undefined") {
-			this.onPeerlist(from, obj) // process rejection peerlist
-			this.disconnect(from) // cya
-		}
-	}
-
-	// receive an accept message
-	this.onAccept = function(from, obj) {
-		if (typeof this.peers[from] != "undefined") {
-			// remove them from our nodearchive
-			for (var i=0;i<this.nodearchive.length;i++) {
-				if (this.nodearchive[i].id == from) {
-					this.nodearchive.splice(i, 1)
-				}
-			}
-
-			// set connection active
-			this.peers[from].lastmessage = self.now();
-			this.peers[from].active = true;
-
-			self.send(from, 'ack', {})
-
-			// notify Network of connection
-			self.connect(from);
-
-			self.handle(from, "peermgr:connect", from)
-		}
-	}
-
-	// receive a disconnect message
-	this.onDisconnect = function(from, obj) {
-		this.disconnect(from)
-	}
-
-	this.onConnect = function(from, obj) {
-		// are you already trying to connect?
-		if (typeof this.peers[from] != "undefined")
-			return; // do nothing
-
-		if (this.numpeers < this.maxpeers) {
-			// sure, we'll accept you. we need a peer.
-
-			// are we already connected to you?
-			this.peers[from] = new PeerState(from, self.now())
-			this.numpeers += 1;
-			this.onAccept(from, obj);
-			this.accept(this.peers[from])
-
-			return;
-		}
-
-		// otherwise, reject this node.
-
-		// remove node from nodearchive in any redundant locations
-		for (var i=0;i<this.nodearchive.length;i++) {
-			if (this.nodearchive[i].id == from) {
-				this.nodearchive.splice(i, 1)
-			}
-		}
-
-		var rejectPeer = new PeerState(from, self.now());
-
-		// add back to nodearchive in the front
-		this.nodearchive.push(rejectPeer)
-
-		// send node a rejection message
-		this.reject(rejectPeer);
-	}
-
-	//
-	// attach to the node
-	//
-
-	// tick that runs every 1 second
-	//startTicking();
-
-	self.on("connect", this.onConnect, this);
-	self.on("accept", this.onAccept, this);
-	self.on("reject", this.onReject, this);
-	self.on("disconnect", this.onDisconnect, this);
-	self.on("peerlist", this.onPeerlist, this);
-	self.on("getpeers", this.onGetpeers, this);
-	self.on("ack", this.onAck, this);
-	self.on("__peermsg", this.onReceive, this);
-}
-
+/*
+The PeerMgr is the inter-client behavior middleware for establishing connections
+with other peers, thus forming a network.
+
+(This peer manager is not intended to accurately mimic bitcoin yet.)
+
+Current behavior: every 1 second it checks to see if it has 'maxpeers'. If not, it attempts
+either to connect to an archived addr, or get addresses from other nodes it has contacted.
+Initially, the only archived addr is the bootstrap node, 0. Once the node has received
+maxpeers, it stops ticking.
+*/
+
+function PeerState(id, lastmessage) {
+	this.id = id;
+	this.lastmessage = lastmessage;
+	this.active = false;
+	this.locked = true;
+	this.msgqueue = [];
+}
+
+function PeerMgr(self) {
+	// attach to nodestate 'peers' property
+	// self.peers = this;
+	self.peermgr = this;
+
+	this.freeze = false;
+	this.ticking = false;
+	this.peers = {}; // current established or attempted connections
+	this.numpeers = 0; // the number of peers we have
+	this.maxpeers = 8; // the max number of peers we can have
+	if (self.id != 0)
+		this.nodearchive = [new PeerState(0, self.now())]; // a node archived, initialized with a bootstrap node
+	else
+		this.nodearchive = []
+
+	var peerTick = function() {
+		if (!this.freeze && (this.numpeers < this.maxpeers)) {
+			// we need more peers
+
+			// let's try connecting to a peer in our nodearchive, if there are any
+			if (this.nodearchive.length) {
+				var p = this.nodearchive.shift();
+				this.nodearchive.push(p);
+
+				// try connecting to this node, fails if we're already trying/connected
+				this.connect(p);
+			}
+
+			// if we have (active) connections, ask them for new peers
+			if (this.numpeers) {
+				var randomPeer = this.peers[Object.keys(this.peers)[Math.floor(Math.random() * Object.keys(this.peers).length)]]
+
+				if (randomPeer.active) {
+					this.getpeers(randomPeer.id)
+				}
+			}
+
+			if (self.now() > 1000 * 1000) // after 1000 seconds, let's tick every 5 seconds instead
+				return 5000;
+		} else {
+			self.peermgr.ticking = false;
+			return false; // no more ticking necessary
+		}
+	}
+
+	var startTicking = function() {
+		if (!self.peermgr.ticking) {
+			self.peermgr.ticking = true;
+
+			self.tick(1000, peerTick, self.peermgr);
+		}
+	}
+
+	this.numActive = function() {
+		var n = 0;
+		for (var p in this.peers) {
+			if (this.peers[p].active) {
+				n++;
+			}
+		}
+		return n;
+	}
+
+	this.send = function(to, name, msg) {
+		if (this.peers[to].active) {
+			if (this.peers[to].locked) {
+				this.peers[to].msgqueue.push({name:name,obj:msg})
+			} else {
+				self.send(this.peers[to].id, "__peermsg", {name:name,obj:msg})
+			}
+		}
+	}
+
+	this.each = function(cb) {
+		for (var p in this.peers) {
+			if (this.peers[p].active)
+				cb.call(self, p)
+		}
+	}
+
+	// sends a message to all active peers
+	this.broadcast = function(name, msg) {
+		for (var p in this.peers) {
+			this.send(p, name, msg)
+		}
+	}
+
+	// request peers from a remote node
+	this.getpeers = function(p) {
+		self.send(p, 'getpeers', {});
+	}
+
+	// send a portion of our archived node list
+	this.sendpeers = function(p) {
+		var someNodes = this.nodearchive.slice(0, 15)
+		if (someNodes.length == 0) {
+			var randomPeer = this.peers[Object.keys(this.peers)[Math.floor(Math.random() * Object.keys(this.peers).length)]]
+			if (randomPeer.active)
+				someNodes = [randomPeer]
+		}
+
+		self.send(p, 'peerlist', someNodes);
+	}
+
+	// connect to a remote node (if we haven't already tried)
+	this.connect = function(p) {
+		if (self.id == p.id)
+			return; // can't connect to ourselves!
+
+		if (typeof this.peers[p.id] == "undefined") {
+			this.peers[p.id] = p;
+			this.numpeers += 1;
+			self.send(p.id, 'connect', {})
+		}
+	}
+
+	// disconnect from a remote node
+	this.disconnect = function(p) {
+		if (typeof this.peers[p] != "undefined") {
+			var peer = this.peers[p];
+			delete this.peers[p];
+
+			//if (peer.active) {
+				self.send(p, 'disconnect', {})
+				self.disconnect(p);
+				startTicking();
+			//}
+
+			this.nodearchive.push(peer);
+			this.numpeers -= 1;
+			self.handle(p, "peermgr:disconnect", p)
+		}
+	}
+
+	// accept a remote node's connection
+	this.accept = function(p) {
+		p.locked = true; // wait for an ack
+		self.send(p.id, 'accept', {})
+	}
+
+	// reject a remote node's connection
+	this.reject = function(p) {
+		var someNodes = this.nodearchive.slice(0, 15)
+		if (someNodes.length == 0) {
+			var randomPeer = this.peers[Object.keys(this.peers)[Math.floor(Math.random() * Object.keys(this.peers).length)]]
+			if (randomPeer.active)
+				someNodes = [this.randomPeer]
+		}
+
+		self.send(p.id, 'reject', someNodes)
+	}
+
+	this.onAck = function(from, o) {
+		if (typeof this.peers[from] != "undefined") {
+			this.peers[from].locked = false;
+			this.peers[from].lastmessage = self.now()
+
+			if (this.peers[from].msgqueue.length > 0) {
+				var domsg = this.peers[from].msgqueue.shift();
+				this.peers[from].locked = true;
+				self.send(this.peers[from].id, "__peermsg", {name:domsg.name,obj:domsg.obj})
+			}
+		}
+	}
+
+	// processes a received message from another peer
+	this.onReceive = function(from, o) {
+		if (typeof this.peers[from] != "undefined" && this.peers[from].active) {
+			self.send(from, 'ack', {})
+			self.handle(from, o.name, o.obj)
+			this.peers[from].lastmessage = self.now();
+		}
+	}
+
+	// receive a peerlist message
+	this.onPeerlist = function(from, obj) {
+		// are we connected to this peer?
+		if (this.peers[from] != "undefined") {
+			// add these peers to our nodearchive
+			// if we don't have them already
+
+			for (var i=0;i<obj.length;i++) {
+				var candidate = obj[i];
+
+				// remove redundant existing nodearchive objects
+				for (var k=0;k<this.nodearchive.length;k++) {
+					if (this.nodearchive[k].id == candidate.id) {
+						this.nodearchive.splice(k, 1);
+					}
+				}
+
+				this.nodearchive.push(new PeerState(candidate.id, self.now()))
+			}
+		}
+	}
+
+	// receive a getpeers message
+	this.onGetpeers = function(from, obj) {
+		// are we connected to this peer?
+		if (this.peers[from] != "undefined") {
+			this.sendpeers(from)
+		}
+	}
+
+	// receive a reject message
+	this.onReject = function(from, obj) {
+		if (typeof this.peers[from] != "undefined") {
+			this.onPeerlist(from, obj) // process rejection peerlist
+			this.disconnect(from) // cya
+		}
+	}
+
+	// receive an accept message
+	this.onAccept = function(from, obj) {
+		if (typeof this.peers[from] != "undefined") {
+			// remove them from our nodearchive
+			for (var i=0;i<this.nodearchive.length;i++) {
+				if (this.nodearchive[i].id == from) {
+					this.nodearchive.splice(i, 1)
+				}
+			}
+
+			// set connection active
+			this.peers[from].lastmessage = self.now();
+			this.peers[from].active = true;
+
+			self.send(from, 'ack', {})
+
+			// notify Network of connection
+			self.connect(from);
+
+			self.handle(from, "peermgr:connect", from)
+		}
+	}
+
+	// receive a disconnect message
+	this.onDisconnect = function(from, obj) {
+		this.disconnect(from)
+	}
+
+	this.onConnect = function(from, obj) {
+		// are you already trying to connect?
+		if (typeof this.peers[from] != "undefined")
+			return; // do nothing
+
+		if (this.numpeers < this.maxpeers) {
+			// sure, we'll accept you. we need a peer.
+
+			// are we already connected to you?
+			this.peers[from] = new PeerState(from, self.now())
+			this.numpeers += 1;
+			this.onAccept(from, obj);
+			this.accept(this.peers[from])
+
+			return;
+		}
+
+		// otherwise, reject this node.
+
+		// remove node from nodearchive in any redundant locations
+		for (var i=0;i<this.nodearchive.length;i++) {
+			if (this.nodearchive[i].id == from) {
+				this.nodearchive.splice(i, 1)
+			}
+		}
+
+		var rejectPeer = new PeerState(from, self.now());
+
+		// add back to nodearchive in the front
+		this.nodearchive.push(rejectPeer)
+
+		// send node a rejection message
+		this.reject(rejectPeer);
+	}
+
+	//
+	// attach to the node
+	//
+
+	// tick that runs every 1 second
+	//startTicking();
+
+	self.on("connect", this.onConnect, this);
+	self.on("accept", this.onAccept, this);
+	self.on("reject", this.onReject, this);
+	self.on("disconnect", this.onDisconnect, this);
+	self.on("peerlist", this.onPeerlist, this);
+	self.on("getpeers", this.onGetpeers, this);
+	self.on("ack", this.onAck, this);
+	self.on("__peermsg", this.onReceive, this);
+}
+
 module.exports = PeerMgr;
\ No newline at end of file
diff --git a/sim/require.js b/sim/TinyNets/public_html/require.js
old mode 100755
new mode 100644
similarity index 98%
rename from sim/require.js
rename to sim/TinyNets/public_html/require.js
index 9d070199ffd97e77cfe0b5d552f7a8fff48fb615..ed4eb1a468b68556b65f5e5f0a7b328bf99971d8
--- a/sim/require.js
+++ b/sim/TinyNets/public_html/require.js
@@ -1,35 +1,35 @@
-// found on stackoverflow somewhere
-// run chrome with  --allow-file-access-from-files so this works in file://
-function require(url){
-    if (url.toLowerCase().substr(-3)!=='.js') url+='.js'; // to allow loading without js suffix;
-    if (!require.cache) require.cache=[]; //init cache
-    var exports=require.cache[url]; //get from cache
-    if (!exports) { //not cached
-            try {
-                exports={};
-                var X=new XMLHttpRequest();
-                X.open("GET", url, 0); // sync
-                X.send();
-                if (X.status && X.status !== 200)  throw new Error(X.statusText);
-                var source = X.responseText;
-                // fix (if saved form for Chrome Dev Tools)
-                if (source.substr(0,10)==="(function("){ 
-                    var moduleStart = source.indexOf('{');
-                    var moduleEnd = source.lastIndexOf('})');
-                    var CDTcomment = source.indexOf('//@ ');
-                    if (CDTcomment>-1 && CDTcomment<moduleStart+6) moduleStart = source.indexOf('\n',CDTcomment);
-                    source = source.slice(moduleStart+1,moduleEnd-1); 
-                } 
-                // fix, add comment to show source on Chrome Dev Tools
-                source="//@ sourceURL="+window.location.origin+url+"\n" + source;
-                //------
-                var module = { id: url, uri: url, exports:exports }; //according to node.js modules 
-                var anonFn = new Function("require", "exports", "module", source); //create a Fn with module code, and 3 params: require, exports & module
-                anonFn(require, exports, module); // call the Fn, Execute the module
-                require.cache[url]  = exports = module.exports; //cache obj exported by module
-            } catch (err) {
-                throw new Error("Error loading module "+url+": "+err);
-            }
-    }
-    return exports; //require returns object exported by module
+// found on stackoverflow somewhere
+// run chrome with  --allow-file-access-from-files so this works in file://
+function require(url){
+    if (url.toLowerCase().substr(-3)!=='.js') url+='.js'; // to allow loading without js suffix;
+    if (!require.cache) require.cache=[]; //init cache
+    var exports=require.cache[url]; //get from cache
+    if (!exports) { //not cached
+            try {
+                exports={};
+                var X=new XMLHttpRequest();
+                X.open("GET", url, 0); // sync
+                X.send();
+                if (X.status && X.status !== 200)  throw new Error(X.statusText);
+                var source = X.responseText;
+                // fix (if saved form for Chrome Dev Tools)
+                if (source.substr(0,10)==="(function("){ 
+                    var moduleStart = source.indexOf('{');
+                    var moduleEnd = source.lastIndexOf('})');
+                    var CDTcomment = source.indexOf('//@ ');
+                    if (CDTcomment>-1 && CDTcomment<moduleStart+6) moduleStart = source.indexOf('\n',CDTcomment);
+                    source = source.slice(moduleStart+1,moduleEnd-1); 
+                } 
+                // fix, add comment to show source on Chrome Dev Tools
+                source="//@ sourceURL="+window.location.origin+url+"\n" + source;
+                //------
+                var module = { id: url, uri: url, exports:exports }; //according to node.js modules 
+                var anonFn = new Function("require", "exports", "module", source); //create a Fn with module code, and 3 params: require, exports & module
+                anonFn(require, exports, module); // call the Fn, Execute the module
+                require.cache[url]  = exports = module.exports; //cache obj exported by module
+            } catch (err) {
+                throw new Error("Error loading module "+url+": "+err);
+            }
+    }
+    return exports; //require returns object exported by module
 }
\ No newline at end of file
diff --git a/sim/sim-example-alert.js b/sim/TinyNets/public_html/sim-example-alert.js
old mode 100755
new mode 100644
similarity index 95%
rename from sim/sim-example-alert.js
rename to sim/TinyNets/public_html/sim-example-alert.js
index 110f385d45d5c826ec45b66b427dbd61217f23f0..e1f4ffb5eb4a42a5eef0e3f79f1574e52cc65c9a
--- a/sim/sim-example-alert.js
+++ b/sim/TinyNets/public_html/sim-example-alert.js
@@ -1,55 +1,55 @@
-/*
-	Example: Alert Message
-
-	An alert message needs to be broadcasted to all nodes as fast as possible!
-
-	Let's calculate how long it takes the message to be received by all nodes.
-*/
-
-
-var net = require("./network"),
-    peermgr = require("./peermgr"),
-	client = new net.Node()
-
-client.use(peermgr)
-
-client.init(function() {
-	this.alertflag = false;
-
-	if (this.id == 0) {
-		this.delay(20000, function() {
-			this.log("dispatching alert")
-			// give the network about 20 seconds so everybody is connected
-
-			this.alertflag = true;
-			this.setColor("red")
-
-			this.peermgr.broadcast("alert")
-		})
-	}
-
-	this.on("alert", function() {
-		if (this.alertflag)
-			return;
-
-		this.alertflag = true;
-		this.setColor("red")
-		this.peermgr.broadcast("alert")
-	})
-})
-
-net.add(100, client)
-net.check(20, function() {
-	var aware = 0;
-	net.nodes.forEach(function(n) {
-		if (n.alertflag) {
-			aware++;
-		}
-	})
-
-	if (aware == net.nodes.length) {
-		net.visualizer.log(net.now + ": ALL NODES HAVE RECEIVED ALERT MESSAGE");
-		net.stop();
-	}
-})
+/*
+	Example: Alert Message
+
+	An alert message needs to be broadcasted to all nodes as fast as possible!
+
+	Let's calculate how long it takes the message to be received by all nodes.
+*/
+
+
+var net = require("./network"),
+    peermgr = require("./peermgr"),
+	client = new net.Node()
+
+client.use(peermgr)
+
+client.init(function() {
+	this.alertflag = false;
+
+	if (this.id == 0) {
+		this.delay(20000, function() {
+			this.log("dispatching alert")
+			// give the network about 20 seconds so everybody is connected
+
+			this.alertflag = true;
+			this.setColor("red")
+
+			this.peermgr.broadcast("alert")
+		})
+	}
+
+	this.on("alert", function() {
+		if (this.alertflag)
+			return;
+
+		this.alertflag = true;
+		this.setColor("red")
+		this.peermgr.broadcast("alert")
+	})
+})
+
+net.add(100, client)
+net.check(20, function() {
+	var aware = 0;
+	net.nodes.forEach(function(n) {
+		if (n.alertflag) {
+			aware++;
+		}
+	})
+
+	if (aware == net.nodes.length) {
+		net.visualizer.log(net.now + ": ALL NODES HAVE RECEIVED ALERT MESSAGE");
+		net.stop();
+	}
+})
 net.run(Infinity)
\ No newline at end of file
diff --git a/sim/sim-selfish.js b/sim/TinyNets/public_html/sim-selfish.js
similarity index 100%
rename from sim/sim-selfish.js
rename to sim/TinyNets/public_html/sim-selfish.js
diff --git a/sim/sim.js b/sim/TinyNets/public_html/sim.js
old mode 100755
new mode 100644
similarity index 50%
rename from sim/sim.js
rename to sim/TinyNets/public_html/sim.js
index 88dd984ce052b2a097c5960422bd21b3f603535b..5ca8b09e834b8a683afa3876c685315adc287431
--- a/sim/sim.js
+++ b/sim/TinyNets/public_html/sim.js
@@ -1,147 +1,241 @@
-var net = require("./network"),
-	manager = require('./manager');
-
-const startupDelay = 100;
-const connectDelay = 100;
-const bufferCheckDelay = 1000;
-const heartbeatPeriod = 400;
-
-// INITIALIZE NETWORK TOPOLOGY HERE
-var initTopology = [
-	[1,2],      // 0
-	[0,3],      // 1
-        [0,4,5],    // 2
-        [1,4],      // 3
-        [3,2],      // 4
-        [2]         // 5
-];
-
-// Don't touch this code
-
-var clients = [];
-for (let i = 0; i < initTopology.length; i++) {
-	c = new net.Client();
-	c.use(manager);
-	clients.push(c);
-}
-
-for (let i = 0; i < initTopology.length; i++) {
-	clients[i].init(function() {
-		this.delay(startupDelay, function() {
-			this.manager.setup(initTopology[i].length);
-		});
-		this.delay(500, function() {
-			this.manager.printPorts();
-		});
-		this.tick(bufferCheckDelay, function() {
-			this.manager.checkBuffer();
-		});
-		this.tick(heartbeatPeriod, function() {
-			this.manager.heartbeat();
-		});
-                this.tick(2*heartbeatPeriod, function() {
-                        this.manager.takePulse();
-                });
-	});
-	for (let j = 0; j < initTopology[i].length; j++) {
-		if (initTopology[i][j] == -1) {
-			continue;
-		}
-
-		clients[i].init(function() {
-			this.delay(startupDelay+connectDelay, function() {
-				this.manager.connect(j, initTopology[i][j]);
-			});
-		});
-	}
-}
-
-//----------------------------------------------------------------------------//
-// PUT CUSTOM CODE HERE:
-sendPacket(0,4,1,"Hello Four!",1000);
-
-// To test link failure, uncomment one. To test node failure, uncomment both.
-//disconnect(0,1,2,0,6000);
-//disconnect(2,1,4,1,6000);
-
-// To test how network reacts to heavy traffic at a desired node, uncomment.
-//sendPacket(5,2,1,"Distraction 0!",6000);
-//sendPacket(5,2,1,"Distraction 1!",6000);
-//sendPacket(5,2,1,"Distraction 2!",6000);
-//sendPacket(5,2,1,"Distraction 3!",6000);
-//sendPacket(5,2,1,"Distraction 4!",6000);
-//sendPacket(5,2,1,"Distraction 5!",6000);
-//sendPacket(5,2,1,"Distraction 6!",6000);
-//sendPacket(5,2,1,"Distraction 7!",6000);
-//sendPacket(5,2,1,"Distraction 8!",6000);
-
-sendPacket(4,0,1,"I love you, One!",8000);
-
-
-//Don't add stuff below this:
-//----------------------------------------------------------------------------//
-
-for (let i = 0; i < initTopology.length; i++) {
-	net.add(1, clients[i]);
-}
-net.run(100 * 1000); // runs for 100 seconds
-
-
-
-function send(from, port, message, delay, periodic=false) {
-	if (periodic) {
-		clients[from].init(function() {
-			this.tick(delay, function() {
-				this.manager.send(port, message);
-			});
-		});
-	} else {
-		clients[from].init(function() {
-			this.delay(delay, function() {
-				this.manager.send(port, message);
-			});
-		});
-	}
-}
-
-function sendPacket(from, dest, size, data, delay, periodic=false) {
-	if (periodic) {
-		clients[from].init(function() {
-			this.tick(delay, function() {
-				this.manager.sendPacket(252, dest, -1, undefined, size, data, -1);
-			});
-		});
-	} else {
-		clients[from].init(function() {
-			this.delay(delay, function() {
-				this.manager.sendPacket(252, dest, -1, undefined, size, data, -1);
-			});
-		});
-	}
-}
-
-function connect(a, aPort, b, bPort, delay) {
-	clients[a].init(function() {
-		this.delay(delay, function() {
-			this.manager.connect(aPort, b);
-		});	
-	});
-	clients[b].init(function() {
-		this.delay(delay, function() {
-			this.manager.connect(bPort, a);
-		});
-	});
-}
-
-function disconnect(a, aPort, b, bPort, delay) {
-	clients[a].init(function() {
-		this.delay(delay, function() {
-			this.manager.disconnect(aPort);
-		});
-	});
-	clients[b].init(function() {
-		this.delay(delay, function() {
-			this.manager.disconnect(bPort);
-		});
-	});
+var net = require("./network"),
+	manager = require('./manager');
+
+const startupDelay = 100;
+const connectDelay = 100;
+const bufferCheckDelay = 1000;
+const heartbeatPeriod = 400;
+
+// INITIALIZE NETWORK TOPOLOGY HERE
+var initTopology = [
+	[1,2,3,5,6,9],		// 0
+	[0,3,5,6,9,10],		// 1
+	[0,3,6,8,9,10,11],		// 2
+	[0,1,2,4,10],		// 3
+	[3,5,12],		// 4
+	[0,1,4,6,8,9,12,13,14],		// 5
+	[0,1,2,5,11],		// 6
+	[9,10,13,14],		// 7
+	[2,5,13,17],		// 8
+	[0,1,2,5,7,12,15,16],		// 9
+	[1,2,3,7,12,15,17,19],		// 10
+	[2,6,14,19],		// 11
+	[4,5,9,10,15,20,21],		// 12
+	[5,7,8,15,16,18,19],		// 13
+	[5,7,11,19,20,22,23],		// 14
+	[9,10,12,13,19,22],		// 15
+	[9,13,17,18,21,24,25],		// 16
+	[8,10,16,18,19,20,21,22,25],		// 17
+	[13,16,17,20,21,24,25],		// 18
+	[10,11,13,14,15,17,20,21,22,24,27,28],		// 19
+	[12,14,17,18,19,21,24,27,28,29],		// 20
+	[12,16,17,18,19,20,24,25,29,30],		// 21
+	[14,15,17,19,24,25],		// 22
+	[14,29,31],		// 23
+	[16,18,19,20,21,22,26,28,29,30,32],		// 24
+	[16,17,18,21,22,26,27,28],		// 25
+	[24,25,27,30,35],		// 26
+	[19,20,25,26,29,30,31,32,35,36],		// 27
+	[19,20,24,25,29,30,37],		// 28
+	[20,21,23,24,27,28,30,32,33,37],		// 29
+	[21,24,26,27,28,29,36,37],		// 30
+	[23,27,33,34,36,38],		// 31
+	[24,27,29,36,38],		// 32
+	[29,31,34,36,37,38,40,42],		// 33
+	[31,33,38,40,42],		// 34
+	[26,27,39,40,41,43,44],		// 35
+	[27,30,31,32,33,38,39,41,44],		// 36
+	[28,29,30,33,39,40,41],		// 37
+	[31,32,33,34,36,40,42,47],		// 38
+	[35,36,37,41,42,43,45,46,48],		// 39
+	[33,34,35,37,38,42,43],		// 40
+	[35,36,37,39,42,45,46],		// 41
+	[33,34,38,39,40,41,43,50,51],		// 42
+	[35,39,40,42,46,48,49,52],		// 43
+	[35,36,49,50,51],		// 44
+	[39,41,46,49,53,54],		// 45
+	[39,41,43,45,47,48,49,50,52,53,54],		// 46
+	[38,46,51,54,55,56],		// 47
+	[39,43,46,49,50,53,54,55,57],		// 48
+	[43,44,45,46,48,51,52,55,57],		// 49
+	[42,44,46,48,55],		// 50
+	[42,44,47,49,58,60],		// 51
+	[43,46,49,53,57,59],		// 52
+	[45,46,48,52,54,55,60,61],		// 53
+	[45,46,47,48,53,58,59,60,62,63],		// 54
+	[47,48,49,50,53,56,57,59,63],		// 55
+	[47,55,59,60,62],		// 56
+	[48,49,52,55,66],		// 57
+	[51,54,59,62],		// 58
+	[52,54,55,56,58,63,64],		// 59
+	[51,53,54,56,61,63,64,65,67,69],		// 60
+	[53,60,66,67,68],		// 61
+	[54,56,58,63,64,68,71],		// 62
+	[54,55,59,60,62,65,67,68,69,70,71,72],		// 63
+	[59,60,62,66,68,69],		// 64
+	[60,63,68,69,71],		// 65
+	[57,61,64,73,74,75],		// 66
+	[60,61,63,68,73,75,76],		// 67
+	[61,62,63,64,65,67,69,70,71,72,74],		// 68
+	[60,63,64,65,68,75],		// 69
+	[63,68,71,76,77],		// 70
+	[62,63,65,68,70,75,76,77],		// 71
+	[63,68,73,75,76,77,78,79,80,81],		// 72
+	[66,67,72,76],		// 73
+	[66,68,77,78],		// 74
+	[66,67,69,71,72,80,81,83,84],		// 75
+	[67,70,71,72,73,77,79,83],		// 76
+	[70,71,72,74,76,78,81,83,84,85,86],		// 77
+	[72,74,77,81,82,83,85,86],		// 78
+	[72,76,80,81,84,86],		// 79
+	[72,75,79,82,83,86,87],		// 80
+	[72,75,77,78,79,82,83,84,85,86,87,88],		// 81
+	[78,80,81,84,88,89,91],		// 82
+	[75,76,77,78,80,81,85,88,89],		// 83
+	[75,77,79,81,82,88,90,91],		// 84
+	[77,78,81,83,88,90,91,93],		// 85
+	[77,78,79,80,81,92,95],		// 86
+	[80,81,92,93,94],		// 87
+	[81,82,83,84,85,89,90,97],		// 88
+	[82,83,88,93,94,95,96],		// 89
+	[84,85,88,91,92,95,97,99],		// 90
+	[82,84,85,90,95,96,98,99],		// 91
+	[86,87,90,93,94,95,96,98],		// 92
+	[85,87,89,92,96,97],		// 93
+	[87,89,92,95,96,97,98],		// 94
+	[86,89,90,91,92,94,99],		// 95
+	[89,91,92,93,94,98,99],		// 96
+	[88,90,93,94,99],		// 97
+	[91,92,94,96,99],		// 98
+	[90,91,95,96,97,98]		// 99
+];
+
+// Don't touch this code
+
+var clients = [];
+for (let i = 0; i < initTopology.length; i++) {
+	c = new net.Client();
+	c.use(manager);
+	clients.push(c);
+}
+
+for (let i = 0; i < initTopology.length; i++) {
+	clients[i].init(function() {
+		this.delay(startupDelay, function() {
+			this.manager.setup(initTopology[i].length);
+		});
+		this.delay(500, function() {
+			this.manager.printPorts();
+		});
+		this.tick(bufferCheckDelay, function() {
+			this.manager.checkBuffer();
+		});
+		this.tick(heartbeatPeriod, function() {
+			this.manager.heartbeat();
+		});
+                this.tick(2*heartbeatPeriod, function() {
+                        this.manager.takePulse();
+                });
+	});
+	for (let j = 0; j < initTopology[i].length; j++) {
+		if (initTopology[i][j] == -1) {
+			continue;
+		}
+
+		clients[i].init(function() {
+			this.delay(startupDelay+connectDelay, function() {
+				this.manager.connect(j, initTopology[i][j]);
+			});
+		});
+	}
+}
+
+//----------------------------------------------------------------------------//
+// PUT CUSTOM CODE HERE:
+sendPacket(0,99,1,"Hello!",1000);
+
+// To test link failure, uncomment one. To test node failure, uncomment both.
+//disconnect(0,1,2,0,6000);
+//disconnect(2,1,4,1,6000);
+
+// To test how network reacts to heavy traffic at a desired node, uncomment.
+//sendPacket(5,2,1,"Distraction 0!",6000);
+//sendPacket(5,2,1,"Distraction 1!",6000);
+//sendPacket(5,2,1,"Distraction 2!",6000);
+//sendPacket(5,2,1,"Distraction 3!",6000);
+//sendPacket(5,2,1,"Distraction 4!",6000);
+//sendPacket(5,2,1,"Distraction 5!",6000);
+//sendPacket(5,2,1,"Distraction 6!",6000);
+//sendPacket(5,2,1,"Distraction 7!",6000);
+//sendPacket(5,2,1,"Distraction 8!",6000);
+
+//sendPacket(4,0,1,"I love you, One!",8000);
+
+
+//Don't add stuff below this:
+//----------------------------------------------------------------------------//
+
+for (let i = 0; i < initTopology.length; i++) {
+	net.add(1, clients[i]);
+}
+net.run(100 * 1000); // runs for 100 seconds
+
+
+
+function send(from, port, message, delay, periodic=false) {
+	if (periodic) {
+		clients[from].init(function() {
+			this.tick(delay, function() {
+				this.manager.send(port, message);
+			});
+		});
+	} else {
+		clients[from].init(function() {
+			this.delay(delay, function() {
+				this.manager.send(port, message);
+			});
+		});
+	}
+}
+
+function sendPacket(from, dest, size, data, delay, periodic=false) {
+	if (periodic) {
+		clients[from].init(function() {
+			this.tick(delay, function() {
+				this.manager.sendPacket(252, dest, -1, undefined, size, data, -1);
+			});
+		});
+	} else {
+		clients[from].init(function() {
+			this.delay(delay, function() {
+				this.manager.sendPacket(252, dest, -1, undefined, size, data, -1);
+			});
+		});
+	}
+}
+
+function connect(a, aPort, b, bPort, delay) {
+	clients[a].init(function() {
+		this.delay(delay, function() {
+			this.manager.connect(aPort, b);
+		});	
+	});
+	clients[b].init(function() {
+		this.delay(delay, function() {
+			this.manager.connect(bPort, a);
+		});
+	});
+}
+
+function disconnect(a, aPort, b, bPort, delay) {
+	clients[a].init(function() {
+		this.delay(delay, function() {
+			this.manager.disconnect(aPort);
+		});
+	});
+	clients[b].init(function() {
+		this.delay(delay, function() {
+			this.manager.disconnect(bPort);
+		});
+	});
 }
\ No newline at end of file
diff --git a/sim/random_networks.m b/sim/random_networks.m
new file mode 100644
index 0000000000000000000000000000000000000000..a71e1501b133100b062102f710f45493ee24004f
--- /dev/null
+++ b/sim/random_networks.m
@@ -0,0 +1,68 @@
+function random_networks(n,max_out_degree,max_length)
+%% Code modified from:
+% Copyright (c) 2010, huxp ??
+% 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
+% 
+% 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.
+
+rng(0)
+edge_list = zeros(0,2);
+r=0;
+out_arc=zeros(max_out_degree,2);
+for i=1:n-1
+    end_node=i+unidrnd(max_length,1,max(unidrnd(max_out_degree),1));
+    end_node=end_node(end_node<=n);
+    if isempty(end_node)
+        end_node=n;
+    end
+    end_node = unique(end_node, 'first');
+    l_end_node=length(end_node);
+    out_arc(1:l_end_node,1)=i;
+    out_arc(1:l_end_node,2)=end_node;
+    edge_list(r+1:r+l_end_node,:) = out_arc(1:l_end_node,:);
+    r=r+l_end_node;
+end
+
+%% Original code
+topology = cell(max(max(edge_list)),1);
+for i = 1:length(edge_list)
+    topology{edge_list(i,1)} = [topology{edge_list(i,1)},edge_list(i,2)];
+    topology{edge_list(i,2)} = [topology{edge_list(i,2)},edge_list(i,1)];
+end
+
+fh = fopen('js_code.txt','w');
+fprintf(fh,'var initTopology = [\n');
+for i = 1:numel(topology)
+    fprintf(fh,'\t[%d',topology{i}(1)-1);
+    for j = 2:numel(topology{i})
+        fprintf(fh,',%d',topology{i}(j)-1);
+    end
+    fprintf(fh,']');
+    if i ~= length(topology)
+        fprintf(fh,',');
+    end
+    fprintf(fh,'\t\t// %d\n',i-1);
+end
+fprintf(fh,'];');
+fclose(fh);
+end
\ No newline at end of file