text: ;(function(e,t,n){function i(n,s){if(!t[n]){if(!e[n]){var o=typeof require=="function"&&require;if(!s&&o)return o(n,!0);if(r)return r(n,!0);throw new Error("Cannot find module '"+n+"'")}var u=t[n]={exports:{}};e[n][0].call(u.exports,function(t){var r=e[n][1][t];return i(r?r:t)},u,u.exports)}return t[n].exports}var r=typeof require=="function"&&require;for(var s=0;s<n.length;s++)i(n[s]);return i})({1:[function(require,module,exports){
  
  //this exports all the verlet methods globally, so that the demos work.
  
  require("./verlet-polyfill");
  var VerletDraw = require('./verlet-draw')
  var VerletJS = require('./verlet')
  var constraint = require('./constraint')
  								 require('./objects') //patches VerletJS.prototype (bad)
  window.Vec2 = require('./structures/Vec2')
  window.VerletJS = VerletJS
  window.VerletDraw = VerletDraw;
  
  window.Particle = VerletJS.Particle
  
  for(var i in constraint){
  	window[i] = constraint[i]
  }
  
  },{"./constraint":5,"./objects":6,"./structures/Vec2":7,"./verlet":4,"./verlet-draw":3,"./verlet-polyfill":2}],2:[function(require,module,exports){
  if(!Math.sign){
    Math.sign = function(x){
      if( +x === x ) { // check if a number was given
        return (x === 0) ? x : (x > 0) ? 1 : -1;
      }
      return NaN;
    }
  }
  
  if(!Math.quadratic){
    //x = (-b +- b*b - 4ac )/(2a)
    Math.quadratic = function(a,b,c){
      var ret = b*b - 4*a*c;
      if(ret < 0) return false;
      if(ret == 0) return [-b/(2*a)];
      a *= 2;
      ret = Math.sqrt(ret)/a;
      b *= -1/a
      return [b + ret, b - ret];
    }
  }
  
  if(!Math.lawCos){
    //x = (-b +- b*b - 4ac )/(2a)
    Math.lawCos = function(a,b,c){
      return Math.acos(
        (-a*a + b*b + c*c)/
        (2*b*c)
      );
    }
  }
  
  },{}],3:[function(require,module,exports){
  
  window.requestAnimFrame = window.requestAnimationFrame
  || window.webkitRequestAnimationFrame
  || window.mozRequestAnimationFrame
  || window.oRequestAnimationFrame
  || window.msRequestAnimationFrame
  || function(callback) {
    window.setTimeout(callback, 1000 / 60);
  };
  var VerletJS = require("./verlet.js");
  module.exports = VerletDraw;
  
  function VerletDraw(width, height, canvas, physics) {
    this.width = width;
    this.height = height;
    this.canvas = canvas;
    this.ctx = canvas.getContext("2d");
    this.mouse = new Vec2(0,0);
    this.mouseDown = false;
    this.draggedEntity = null;
    this.selectionRadius = 20;
    this.highlightColor = "#4f545c";
    this.physics = (!physics)?new VerletJS(width,height):physics;
  
    var _this = this;
  
    this.physics.logic = function(){
      // handle dragging of entities
      if (_this.draggedEntity)
        _this.draggedEntity.pos.set(_this.mouse);
    }
  
  
    // prevent context menu
    this.canvas.oncontextmenu = function(e) {
      e.preventDefault();
    };
  
    this.canvas.onmousedown = function(e) {
      _this.mouseDown = true;
      var nearest = _this.physics.nearestEntity(_this.mouse,_this.selectionRadius);;
      if (nearest) {
        _this.draggedEntity = nearest;
        console.log(nearest.pos);
      }
    };
  
    this.canvas.onmouseup = function(e) {
      _this.mouseDown = false;
      _this.draggedEntity = null;
    };
  
    this.canvas.onmousemove = function(e) {
      var rect = _this.canvas.getBoundingClientRect();
      _this.mouse.x = e.clientX - rect.left;
      _this.mouse.y = e.clientY - rect.top;
    };
  
  }
  
  
  VerletDraw.prototype.draw = function() {
    var i, c;
  
    this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
    var composites = this.physics.composites;
    for (c in composites) {
      // draw constraints
      if (composites[c].drawConstraints) {
        composites[c].drawConstraints(this.ctx, composites[c]);
      } else {
        var constraints = composites[c].constraints;
        for (i in constraints)
          constraints[i].draw(this.ctx);
      }
  
      // draw particles
      if (composites[c].drawParticles) {
        composites[c].drawParticles(this.ctx, composites[c]);
      } else {
        var particles = composites[c].particles;
        for (i in particles)
          particles[i].draw(this.ctx);
      }
    }
  
    // highlight nearest / dragged entity
    var nearest = this.draggedEntity || this.physics.nearestEntity(this.mouse,this.selectionRadius);
    if (nearest) {
      this.ctx.beginPath();
      this.ctx.arc(nearest.pos.x, nearest.pos.y, 8, 0, 2*Math.PI);
      this.ctx.strokeStyle = this.highlightColor;
      this.ctx.stroke();
    }
  }
  
  },{"./verlet.js":4}],6:[function(require,module,exports){
  
  /*
  Copyright 2013 Sub Protocol and other contributors
  http://subprotocol.com/
  
  Permission is hereby granted, free of charge, to any person obtaining
  a copy of this software and associated documentation files (the
  "Software"), to deal in the Software without restriction, including
  without limitation the rights to use, copy, modify, merge, publish,
  distribute, sublicense, and/or sell copies of the Software, and to
  permit persons to whom the Software is furnished to do so, subject to
  the following conditions:
  
  The above copyright notice and this permission notice shall be
  included in all copies or substantial portions of the Software.
  
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
  
  // generic verlet entities
  
  var VerletJS = require('./verlet')
  var Particle = VerletJS.Particle
  var constraints = require('./constraint')
  var DistanceConstraint = constraints.DistanceConstraint
  
  VerletJS.prototype.point = function(pos) {
  	var composite = new this.Composite();
  	composite.particles.push(new Particle(pos));
  	this.composites.push(composite);
  	return composite;
  }
  
  VerletJS.prototype.lineSegments = function(vertices, stiffness, circle) {
  	var i;
  
  	var composite = new this.Composite();
  
  	for (i in vertices) {
  		composite.particles.push(new Particle(vertices[i]));
  		if (i > 0)
  			composite.constraints.push(
  				new DistanceConstraint(
  					composite.particles[i],
  					composite.particles[i-1],
  					stiffness
  				)
  			);
  	}
  	if(circle){
  		composite.constraints.push(
  			new DistanceConstraint(
  				composite.particles[composite.particles.length-1],
  				composite.particles[0],
  				stiffness
  			)
  		)
  	}
  
  	this.composites.push(composite);
  	return composite;
  }
  
  VerletJS.prototype.cloth = function(origin, width, height, segments, pinMod, stiffness) {
  
  	var composite = new this.Composite();
  
  	var xStride = width/segments;
  	var yStride = height/segments;
  
  	var x,y;
  	for (y=0;y<segments;++y) {
  		for (x=0;x<segments;++x) {
  			var px = origin.x + x*xStride - width/2 + xStride/2;
  			var py = origin.y + y*yStride - height/2 + yStride/2;
  			composite.particles.push(new Particle(new Vec2(px, py)));
  
  			if (x > 0){
  				composite.constraints.push(
  					new DistanceConstraint(
  						composite.particles[y*segments+x],
  						composite.particles[y*segments+x-1],
  						stiffness
  					)
  				);
  			}
  
  			if (y > 0){
  				composite.constraints.push(
  					new DistanceConstraint(
  						composite.particles[y*segments+x],
  						composite.particles[(y-1)*segments+x],
  						stiffness
  					)
  				);
  			}
  		}
  	}
  
  	for (x=0;x<segments;++x) {
  		if (x%pinMod == 0)
  		composite.pin(x);
  	}
  
  	this.composites.push(composite);
  	return composite;
  }
  
  VerletJS.prototype.tire = function(origin, radius, segments, spokeStiffness, treadStiffness) {
  	var stride = (2*Math.PI)/segments;
  	var i;
  
  	var composite = new this.Composite();
  
  	// particles
  	for (i=0;i<segments;++i) {
  		var theta = i*stride;
  		composite.particles.push(new Particle(new Vec2(origin.x + Math.cos(theta)*radius, origin.y + Math.sin(theta)*radius)));
  	}
  
  	var center = new Particle(origin);
  	composite.particles.push(center);
  
  	// constraints
  	for (i=0;i<segments;++i) {
  		composite.constraints.push(
  			new DistanceConstraint(
  				composite.particles[i],
  				composite.particles[(i+1)%segments],
  				treadStiffness
  			)
  		);
  		composite.constraints.push(
  			new DistanceConstraint(
  				composite.particles[i],
  				center,
  				spokeStiffness
  			)
  		);
  		composite.constraints.push(
  			new DistanceConstraint(
  				composite.particles[i],
  				composite.particles[(i+5)%segments],
  				treadStiffness
  			)
  		);
  	}
  
  	this.composites.push(composite);
  	return composite;
  }
  
  },{"./constraint":5,"./verlet":4}],4:[function(require,module,exports){
  
  /*
  Copyright 2013 Sub Protocol and other contributors
  http://subprotocol.com/
  
  Permission is hereby granted, free of charge, to any person obtaining
  a copy of this software and associated documentation files (the
  "Software"), to deal in the Software without restriction, including
  without limitation the rights to use, copy, modify, merge, publish,
  distribute, sublicense, and/or sell copies of the Software, and to
  permit persons to whom the Software is furnished to do so, subject to
  the following conditions:
  
  The above copyright notice and this permission notice shall be
  included in all copies or substantial portions of the Software.
  
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
  
  var Vec2 = require('./structures/Vec2');
  var Collision = require("./collision/collision");
  
  exports = module.exports = VerletJS;
  var Particle = exports.Particle = require("./structures/Particle");
  var Composite = exports.Composite = require("./structures/Composite");
  exports.Composite = Composite;
  
  
  function VerletJS(width, height) {
  	this.width = width;
  	this.height = height;
  
  	this.bounds = function (particle) {
  		if (particle.pos.y > this.height-1)
  			particle.pos.y = this.height-1;
  
  		if (particle.pos.x < 0)
  			particle.pos.x = 0;
  
  		if (particle.pos.x > this.width-1)
  			particle.pos.x = this.width-1;
  	};
  
  	// simulation params
  	this.gravity = new Vec2(0,0.2);
  	this.friction = 0.99;
  	this.groundFriction = 0.8;
  
  	// holds composite entities
  	this.composites = [];
  }
  
  VerletJS.prototype.Composite = Composite;
  
  VerletJS.prototype.logic = function(){
  	throw new Error("Logic hasn't been set");
  };
  
  VerletJS.prototype.frame = function(step) {
  	var i, j, c, particles;
  
  	for (c in this.composites) {
  		particles = this.composites[c].particles;
  		for (i in particles) {
  			// save last good state
  			particles[i].lastPos.set(particles[i].pos);
  
  			// gravity
  			particles[i].pos.add(this.gravity);
  
  			if (particles[i].pos.y >= this.height-1 && particles[i].vel.length2() > 0.000001) {
  				particles[i].vel.scale(this.groundFriction);
  			}
  
  			// inertia
  			particles[i].pos.add(particles[i].vel.scale(this.friction));
  
  
  		}
  	}
  
  	// relax
  	var stepCoef = 1/step;
  	for (c in this.composites) {
  		var constraints = this.composites[c].constraints;
  		for (i=0;i<step;++i)
  			for (j in constraints)
  				constraints[j].relax(stepCoef);
  	}
  
  	// bounds checking
  	for (c in this.composites) {
  		particles = this.composites[c].particles;
  		this.composites[c].aabb.clear();
  		for (i in particles){
  
  			this.bounds(particles[i]);
  			// calculate velocity
  			particles[i].vel
  			.set(particles[i].pos)
  			.sub(particles[i].lastPos);
  			// ground friction
  			this.composites[c].aabb.digestPoint(particles[i].pos);
  		}
  	}
  	Collision(this.composites,step);
  	this.logic();
  };
  
  
  VerletJS.prototype.nearestEntity = function(target_vec2,radius) {
  	var c, i;
  	var d2Nearest = 0;
  	var entity = null;
  	var constraintsNearest = null;
  
  	// find nearest point
  	for (c in this.composites) {
  		var particles = this.composites[c].particles;
  		for (i in particles) {
  			var d2 = particles[i].pos.dist2(target_vec2);
  			if (d2 <= radius*radius && (entity === null || d2 < d2Nearest)) {
  				entity = particles[i];
  				constraintsNearest = this.composites[c].constraints;
  				d2Nearest = d2;
  			}
  		}
  	}
  
  	// search for pinned constraints for this entity
  	for (i in constraintsNearest)
  		if (constraintsNearest[i] instanceof PinConstraint && constraintsNearest[i].a == entity)
  			entity = constraintsNearest[i];
  
  	return entity;
  };
  
  },{"./collision/collision":8,"./structures/Composite":10,"./structures/Particle":9,"./structures/Vec2":7}],5:[function(require,module,exports){
  
  /*
  Copyright 2013 Sub Protocol and other contributors
  http://subprotocol.com/
  
  Permission is hereby granted, free of charge, to any person obtaining
  a copy of this software and associated documentation files (the
  "Software"), to deal in the Software without restriction, including
  without limitation the rights to use, copy, modify, merge, publish,
  distribute, sublicense, and/or sell copies of the Software, and to
  permit persons to whom the Software is furnished to do so, subject to
  the following conditions:
  
  The above copyright notice and this permission notice shall be
  included in all copies or substantial portions of the Software.
  
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
  
  // DistanceConstraint -- constrains to initial distance
  // PinConstraint -- constrains to static/fixed point
  // AngleConstraint -- constrains 3 particles to an angle
  
  var Vec2 = require("./structures/Vec2")
  
  exports.DistanceConstraint = require("./constraints/DistanceConstraint");
  exports.PinConstraint = require("./constraints/PinConstraint");
  exports.AngleConstraint = require("./constraints/AngleConstraint");
  exports.MidpointAreaConstraint = require("./constraints/AreaConstraint");
  exports.ScaledAreaConstraint = require("./constraints/InflateAreaConstraint");
  
  },{"./constraints/AngleConstraint":13,"./constraints/AreaConstraint":14,"./constraints/DistanceConstraint":11,"./constraints/InflateAreaConstraint":15,"./constraints/PinConstraint":12,"./structures/Vec2":7}],11:[function(require,module,exports){
  function DistanceConstraint(a, b, stiffness, distance /*optional*/) {
    this.a = a;
    this.b = b;
    this.distance = typeof distance != "undefined" ? distance : a.pos.clone().sub(b.pos).length();
    this.stiffness = stiffness;
  }
  
  DistanceConstraint.prototype.relax = function(stepCoef) {
    var normal = this.a.pos.clone().sub(this.b.pos);
    var m = normal.length2();
    normal.scale(((this.distance*this.distance - m)/m)*this.stiffness*stepCoef);
    this.a.pos.add(normal);
    this.b.pos.sub(normal);
  }
  
  DistanceConstraint.prototype.draw = function(ctx) {
    ctx.beginPath();
    ctx.moveTo(this.a.pos.x, this.a.pos.y);
    ctx.lineTo(this.b.pos.x, this.b.pos.y);
    ctx.strokeStyle = "#d8dde2";
    ctx.stroke();
  }
  
  module.exports = DistanceConstraint;
  
  },{}],13:[function(require,module,exports){
  function AngleConstraint(a, b, c, stiffness) {
    this.a = a;
    this.b = b;
    this.c = c;
    this.angle = this.b.pos.angle2(this.a.pos, this.c.pos);
    this.stiffness = stiffness;
  }
  
  AngleConstraint.prototype.relax = function(stepCoef) {
    var angle = this.b.pos.angle2(this.a.pos, this.c.pos);
    var diff = angle - this.angle;
  
    if (diff <= -Math.PI)
      diff += 2*Math.PI;
    else if (diff >= Math.PI)
      diff -= 2*Math.PI;
  
      diff *= stepCoef*this.stiffness;
  
      this.a.pos.rotate(this.b.pos, diff);
      this.c.pos.rotate(this.b.pos, -diff);
      this.b.pos.rotate(this.a.pos, diff);
      this.b.pos.rotate(this.c.pos, -diff);
    }
  
    AngleConstraint.prototype.draw = function(ctx) {
      ctx.beginPath();
      ctx.moveTo(this.a.pos.x, this.a.pos.y);
      ctx.lineTo(this.b.pos.x, this.b.pos.y);
      ctx.lineTo(this.c.pos.x, this.c.pos.y);
      var tmp = ctx.lineWidth;
      ctx.lineWidth = 5;
      ctx.strokeStyle = "rgba(255,255,0,0.2)";
      ctx.stroke();
      ctx.lineWidth = tmp;
    }
  
    module.exports = AngleConstraint;
  
  },{}],7:[function(require,module,exports){
  
  /*
  Copyright 2013 Sub Protocol and other contributors
  http://subprotocol.com/
  
  Permission is hereby granted, free of charge, to any person obtaining
  a copy of this software and associated documentation files (the
  "Software"), to deal in the Software without restriction, including
  without limitation the rights to use, copy, modify, merge, publish,
  distribute, sublicense, and/or sell copies of the Software, and to
  permit persons to whom the Software is furnished to do so, subject to
  the following conditions:
  
  The above copyright notice and this permission notice shall be
  included in all copies or substantial portions of the Software.
  
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
  
  // A simple 2-dimensional vector implementation
  
  module.exports = Vec2;
  
  function Vec2(x, y) {
  	this.x = x || 0;
  	this.y = y || 0;
  	var _this = this;
  	Object.defineProperty(this,"asArray",{
  		get:function(){
  			return [_this.x,_this.y];
  		}
  	});
  }
  var temp;
  temp = require("./to-value");
  
  for(var i in temp){
  	Vec2.prototype[i] = temp[i];
  }
  
  temp = require("./no-arg");
  
  for(var i in temp){
  	Vec2.prototype[i] = temp[i];
  }
  
  temp = require("./operations");
  
  for(var i in temp){
  	Vec2.prototype[i] = temp[i];
  }
  
  
  Vec2.prototype.clone = function(){
  	return new Vec2(this.x,this.y);
  };
  
  Vec2.prototype.normal = function() {
  	var m = Math.sqrt(this.x*this.x + this.y*this.y);
  	return new Vec2(this.x/m, this.y/m);
  };
  
  Vec2.prototype.equals = function(v) {
  	return this.x == v.x && this.y == v.y;
  };
  
  Vec2.prototype.epsilonEquals = function(v, epsilon) {
  	return Math.abs(this.x - v.x) <= epsilon && Math.abs(this.y - v.y) <= epsilon;
  };
  
  Vec2.prototype.isNaN = function(){
  	if(isNaN(this.x)) return true;
  	if(isNaN(this.y)) return true;
  	return false;
  };
  
  Vec2.prototype.toString = function() {
  	return "(" + this.x + ", " + this.y + ")";
  };
  
  Vec2.prototype.toArray = function() {
  	return [this.x,this.y];
  };
  
  },{"./no-arg":17,"./operations":18,"./to-value":16}],16:[function(require,module,exports){
  
  var v = module.exports;
  
  v.length = function() {
  	return Math.sqrt(this.x*this.x + this.y*this.y);
  };
  
  v.length2 = function() {
  	return this.x*this.x + this.y*this.y;
  };
  
  v.slope = function(){
  	return this.y / this.x;
  };
  
  v.sum = function(){
  	return this.y + this.x;
  };
  
  v.dist = function(v) {
  	return Math.sqrt(this.dist2(v));
  };
  
  v.dist2 = function(v) {
  	var x = v.x - this.x;
  	var y = v.y - this.y;
  	return x*x + y*y;
  };
  
  v.dot = function(v) {
  	return this.x*v.x + this.y*v.y;
  };
  
  v.cross = function(v){
  	return this.x * v.y - this.y * v.x;
  };
  
  v.angle = function(vl,vr) {
  	if(vr) return this.angle2(vl,vr);
  	if(vl) return this.angle1(vl);
  	return Math.atan2(this.x,this.y);
  };
  
  v.angle1 = function(v) {
  	return Math.atan2(this.x*v.y-this.y*v.x,this.x*v.x+this.y*v.y);
  };
  
  v.angle2 = function(vLeft, vRight) {
  	return vLeft.clone().sub(this).angle(vRight.clone().sub(this));
  };
  
  },{}],17:[function(require,module,exports){
  var v = module.exports;
  
  v.zero = function(){
  	this.x = 0;
  	this.y = 0;
  	return this;
  };
  
  v.posinf = function(){
  	this.x = Number.POSITIVE_INFINITY;
  	this.y = Number.POSITIVE_INFINITY;
  	return this;
  };
  
  v.neginf = function(){
  	this.x = Number.NEGATIVE_INFINITY;
  	this.y = Number.NEGATIVE_INFINITY;
  	return this;
  };
  
  v.normalize = function(){
  	var len = this.length();
  	this.x /= len;
  	this.y /= len;
  	return this;
  };
  
  v.signum = function(){
  	this.x = this.x>0?1:this.x<0?-1:0;
  	this.y = this.y>0?1:this.y<0?-1:0;
  	return this;
  };
  
  v.swap = function() {
  	var temp = this.x;
  	this.x = this.y;
  	this.y = temp;
  	return this;
  };
  
  v.abs = function(){
    this.x = Math.abs(this.x);
    this.y = Math.abs(this.y);
    return this;
  };
  
  },{}],18:[function(require,module,exports){
  var v = module.exports;
  
  v.add = function(v) {
  	this.x += v.x;
  	this.y += v.y;
  	return this;
  };
  
  v.sub = function(v){
  	this.x -= v.x;
  	this.y -= v.y;
  	return this;
  };
  
  v.mul = function(v) {
  	if(typeof v == "number"){
  		return this.scale(v);
  	}
  	this.x *= v.x;
  	this.y *= v.y;
  	return this;
  };
  
  v.div = function(v) {
  	if(typeof v == "number"){
  		return this.scale(1/v);
  	}
  	this.x /= v.x;
  	this.y /= v.y;
  	return this;
  };
  
  v.scale = function(coef) {
  	this.x *= coef;
  	this.y *= coef;
  	return this;
  };
  
  v.scaleI = function(coef) {
  	this.x /= coef;
  	this.y /= coef;
  	return this;
  };
  
  
  v.pow = function(num){
  	this.x = Math.pow(this.x,num);
  	this.y = Math.pow(this.y,num);
  	return this;
  };
  
  
  v.rotate = function(origin, theta) {
  	var x = this.x - origin.x;
  	var y = this.y - origin.y;
  	this.x = x*Math.cos(theta) - y*Math.sin(theta) + origin.x;
  	this.y = x*Math.sin(theta) + y*Math.cos(theta) + origin.y;
  	return this;
  };
  
  v.min = function(v){
  	this.x = Math.min(this.x, v.x);
  	this.y = Math.min(this.y, v.y);
  	return this;
  };
  
  v.mid = function(v){
  	this.x = (this.x+v.x)/2;
  	this.y = (this.y+v.y)/2;
  	return this;
  };
  
  v.max = function(v){
  	this.x = Math.max(this.x, v.x);
  	this.y = Math.max(this.y, v.y);
  	return this;
  };
  
  v.set = function(v,y) {
    if(typeof y != "undefined"){
      this.x = v;
    	this.y = y;
    }else{
      this.x = v.x;
    	this.y = v.y;
    }
  	return this;
  };
  
  },{}],10:[function(require,module,exports){
  var AABB = require("./AABB");
  
  function Composite() {
    this.particles = [];
    this.constraints = [];
    this.aabb = new AABB();
  
    this.drawParticles = null;
    this.drawConstraints = null;
  }
  
  Composite.prototype.pin = function(index, pos) {
    pos = pos || this.particles[index].pos;
    var pc = new PinConstraint(this.particles[index], pos);
    this.constraints.push(pc);
    return pc;
  };
  
  module.exports = Composite;
  
  },{"./AABB":19}],9:[function(require,module,exports){
  var Vec2 = require("./Vec2")
  
  function Particle(pos) {
    this.pos = (new Vec2()).set(pos);
    this.lastPos = (new Vec2()).set(pos);
    this.vel = new Vec2();
  }
  
  Particle.prototype.draw = function(ctx) {
    ctx.beginPath();
    ctx.arc(this.pos.x, this.pos.y, 2, 0, 2*Math.PI);
    ctx.fillStyle = "#2dad8f";
    ctx.fill();
  }
  
  
  module.exports = Particle;
  
  },{"./Vec2":7}],12:[function(require,module,exports){
  var Vec2 = require("../structures/Vec2")
  
  function PinConstraint(a, pos) {
    this.a = a;
    this.pos = (new Vec2()).set(pos);
  }
  
  PinConstraint.prototype.relax = function(stepCoef) {
    this.a.pos.set(this.pos);
  }
  
  PinConstraint.prototype.draw = function(ctx) {
    ctx.beginPath();
    ctx.arc(this.pos.x, this.pos.y, 6, 0, 2*Math.PI);
    ctx.fillStyle = "rgba(0,153,255,0.1)";
    ctx.fill();
  }
  
  module.exports = PinConstraint;
  
  },{"../structures/Vec2":7}],14:[function(require,module,exports){
  var Vec2 = require("../structures/Vec2");
  var Triangle = require("../structures/Triangle");
  var Polygon = require("../structures/Polygon");
  var AABB = require("../structures/AABB")
  
  
  function AreaConstraint(points, stiffness) {
    if(Array.isArray(points)){
      //nothing
    }else{
      points = Array.prototype.slice.call(arguments,0);
      stiffness = points.pop();
    }
    if(points.length < 3){
      throw new Error("need at least three points in args or as an array to retain an area");
    }
    this.points = Polygon(points);
    this.area = this.points.getArea();
    this.storedarea = 0;
    this.storedmid = 0;
    this.storedaabb = new AABB();
    if(!this.area || this.area == 0){
      throw new Error("cannot calculate a nonexistant area");
    }
    this.stiffness = stiffness;
  }
  
  AreaConstraint.prototype.relax = function(stepCoef) {
    var area = 0;//the current area
    var mid = new Vec2();
    var l = this.points.length;
    this.points.forThree(function(prev,curr,next){
      area += curr.cross(next);
      mid.add(curr.clone().scale(1/l))
    })
    if(area <= 0){
      alert("negative area");
      throw new Error("negative area");
    }
  
    //I have the two areas
    var diff = Math.sqrt((
      this.area* //The desired area
      (this.stiffness*stepCoef)
      +(1-this.stiffness*stepCoef)
      *area
    )/area);
  
    //I want to have all points to either push away from the mid or towards the mid
    //The extremity is dependent on the distance
    //Get the distance between mid and point
    //make the distance the appropriate proportion
    this.storedarea = 0;
    this.storedmid = new Vec2();
  
  
    var _this = this;
    var eq = false
    var curr_array = [];
    this.points.forThree(function(prev,curr,next,i){
      var ok = true;
      /*
      if(curr.equals(next)){
        eq = prev;
        curr_array.push(curr);
        return;
      }
      if(eq){
        prev = eq;
        eq = false;
        curr_array.push(curr)
  
      }
      */
      var tri = new Triangle(prev,curr,next);
      if(tri.isConcave()){
        if(tri.hasPoint(_this.storedmid)){
          problem = true;
        }
        var intersections = _this.points.getIntersects(prev,curr,i);
        if(intersections.length > 0){
          //alert("you may get a negative area here");
          ok = false;
        }
      }
      if(ok){}
      /*
      if(curr_array.length){
        while(curr_array.length){
          _this.storedmid.add(
            curr_array.pop().sub(mid).scale(diff).add(mid)
            .clone().scale(1/l)
          );
        }
      }else{
      */
        _this.storedmid.add(
          curr.sub(mid).scale(diff).add(mid)
          .clone().scale(1/l)
        );
  //    }
  
      if(curr != _this.points[0]){
        _this.storedarea += prev.cross(curr);
      }
      _this.storedaabb.digestPoint(curr);
    })
  }
  AreaConstraint.prototype.draw = function(ctx) {
    var diff = Math.floor(Math.min(255,255*this.area/this.storedarea));
    var inv = Math.floor(Math.min(255,255*this.storedarea/this.area));
    ctx.beginPath();
    ctx.moveTo(this.points[0].x, this.points[0].y);
    var _this = this;
    var problem = false;
    var intersects = [];
    var eq = false;
    this.points.forThree(function(prev,curr,next,i){
      /*
      if(curr.equals(next)){
        eq = prev
        return;
      }
      if(eq){
        prev = eq;
        eq = false;
      }
      */
      var tri = new Triangle(prev,curr,next);
      if(tri.isConcave()){
        if(tri.hasPoint(_this.storedmid)){
          problem = true;
        }
      }
      var intersections = _this.points.getIntersects(prev,curr,i);
      if(intersections.length > 0){
        //        alert("you may get a negative area here");
        intersects = intersects.concat(intersections);
      }
      ctx.lineTo(curr.x,curr.y);
    })
  
    var g = (diff < inv)?diff:inv;
    ctx.closePath();
    ctx.fillStyle="rgba("+diff+","+g+","+inv+",0.6)";
    ctx.fill();
  
  
    for(var i=intersects.length;i--;){
      ctx.beginPath();
      ctx.arc(
        intersects[i].x,
        intersects[i].y,
        8, 0, 2 * Math.PI, false
      );
      ctx.fillStyle = "#FF8300";
      ctx.fill();
    };
  
    var tri = this.points.getDelaney();
    for(i = tri.length; i; ) {
      ctx.beginPath();
      --i; ctx.moveTo(this.points[tri[i]].x, this.points[tri[i]].y);
      --i; ctx.lineTo(this.points[tri[i]].x, this.points[tri[i]].y);
      --i; ctx.lineTo(this.points[tri[i]].x, this.points[tri[i]].y);
      ctx.closePath();
      ctx.stroke();
    }
  
    ctx.beginPath();
    ctx.arc(
      this.storedmid.x,
      this.storedmid.y,
      2, 0, 2 * Math.PI, false
    );
    ctx.fillStyle = problem?"#FF0000":"#00FF00";
    ctx.fill();
  }
  
  module.exports = AreaConstraint;
  
  
  //finding half the area of a circle
  // A = pi * r^2
  // A/2 = pi/2 * r^2
  // dA = pi/d * r^2
  // we know current area
  // we know desired area
  // (dA/cA) * cA = (dA/cA) * pi * r^2
  // we're looking for the change in r that corresponds to change in A
  // sqrt(A/pi) = r
  
  //new_r = (circle_r/sqrt(Area))
  
  
  // we find the porportion between cur and desired
  // multiply current distance by that porportion
  
  //	diff = 1/Math.sqrt(diff);
  //	diff *= stepCoef*this.stiffness;
  /*
  This code will not work properly since pushing outward may not work for certian
  concave polygons
  
  What is needed is to find a single multiplier that the distance between each point
  can be multiplied by to give the area desired
  
  I good example is something such as
  
  There are a few issues here
  1) backwards points
  - The moment it intersects, we get negative area
  2) Intersections around midpoint
  - the moment it intersects around the midpoint, it will go haywire
  - Can we detect if the angle passes over the midpoint?
  -should we compensate for that?
  3) The midpoint pushing outward concept actually enforces angle
  -It causes angles to generally want to be equalateral
  4) Concave till ignoring midpoint
  5) midpoint is technically at the bottom despite most of the area being up top
  -This problem is where we are calculating the midpoint based of angle points
  -Instead of basing it off all points (line segments are points technically)
  -sampling points off each segment will give an innaccurate calculation
  -after finding total perimiter, is it possible to base the amount of influence
  -off of length?
  
  
  */
  
  },{"../structures/AABB":19,"../structures/Polygon":21,"../structures/Triangle":20,"../structures/Vec2":7}],15:[function(require,module,exports){
  var Vec2 = require("../structures/Vec2");
  var Line = require("../structures/Line");
  var Triangle = require("../structures/Triangle");
  var Polygon = require("../structures/Polygon");
  var AABB = require("../structures/AABB")
  
  
  function AreaConstraint(points, stiffness) {
    if(Array.isArray(points)){
      //nothing
    }else{
      points = Array.prototype.slice.call(arguments,0);
      stiffness = points.pop();
    }
    if(points.length < 3){
      throw new Error("need at least three points in args or as an array to retain an area");
    }
    this.points = Polygon(points);
    this.area = this.points.getArea();
    this.storedarea = 0;
    this.storedmid = 0;
    this.storedaabb = new AABB();
    if(!this.area || this.area == 0){
      throw new Error("cannot calculate a nonexistant area");
    }
    this.stiffness = stiffness;
  }
  
  AreaConstraint.prototype.relax = function(stepCoef) {
    var area = 0;//the current area
    var mid = new Vec2();
  
    var l = this.points.length;
    this.points.forThree(function(prev,curr,next){
      area += curr.cross(next);
      mid.add(curr.clone().scale(1/l))
      //perimeter += curr.dist(next);
    })
    if(area <= 0){
      alert("negative area");
      throw new Error("negative area");
    }
  
    //I have the two areas
    var diff = (
      this.area* //The desired area
      (this.stiffness*stepCoef)
      +(1-this.stiffness*stepCoef)
      *area
    )/area;
  
    var _this = this;
    var eq = false
    var lastcurr = this.points[this.points.length-1];
    var lastnext = this.points[0].clone();
    var _prev = this.points[this.points.length-1];
    var nm = new Vec2();
    this.points.forThree(function(prev,curr,next,i){
      var nl = curr.clone();
      curr.sub(_prev).scale(diff).add(prev);
      nm.add(curr.clone().scale(1/l))
      _prev = nl;
    })
    while(l--){
      this.points[l].sub(nm).add(mid);
    }
    this.storedarea = area*diff;
    this.storedmid = mid;
  }
  AreaConstraint.prototype.draw = function(ctx) {
    var diff = Math.floor(Math.min(255,255*this.area/this.storedarea));
    var inv = Math.floor(Math.min(255,255*this.storedarea/this.area));
    var _this = this;
    var problem = false;
    var intersects = [];
    var eq = false;
    var effectivepoints = [];
    //fill
    var l = this.points.length-1;
    ctx.beginPath();
    ctx.moveTo(this.points[l].x, this.points[l].y);
    while(l--){
      ctx.lineTo(this.points[l].x,this.points[l].y);
    }
    var g = (diff < inv)?diff:inv;
    ctx.closePath();
    ctx.fillStyle="rgba("+diff+","+g+","+inv+",0.6)";
    ctx.fill();
    //delaney
    /*
    var tri = this.points.getDelaney();
    for(i = tri.length; i; ) {
      ctx.beginPath();
      --i; ctx.moveTo(this.points[tri[i]].x, this.points[tri[i]].y);
      --i; ctx.lineTo(this.points[tri[i]].x, this.points[tri[i]].y);
      --i; ctx.lineTo(this.points[tri[i]].x, this.points[tri[i]].y);
      ctx.closePath();
      ctx.stroke();
    }
    */
  
  
    //draw perimiter
    ctx.lineWidth = 4;
    this.points.forThree(function(prev,curr,next,i){
      if(curr.equals(next)){
        eq = eq||prev
        return;
      }
      if(eq){
        prev = eq;
        eq = false;
      }
      effectivepoints.push(curr);
      var tri = new Triangle(prev,curr,next);
  
      var mp = tri.getConcaveBisector();
  
      var badarea = false;
      if( tri.CA.pointIsLeftOrTop(mp.B) == tri.CA.pointIsLeftOrTop(tri.B)){
        ctx.strokeStyle = "#FFFF00";
        if(tri.hasPoint(_this.storedmid)){
          problem = true;
        }
      }else{
        ctx.strokeStyle = "#FF00FF";
        if(tri.partialArea < 0){
          badarea = true;
        }
      }
      var intersections = _this.points.intersectsLine(new Line(prev,curr),i);
      if(intersections.length > 0){
        //        alert("you may get a negative area here");
        intersects = intersects.concat(intersections);
      }
      ctx.beginPath();
      ctx.moveTo((prev.x+curr.x)/2, (prev.y+curr.y)/2);
      ctx.lineTo(curr.x,curr.y);
      ctx.lineTo((next.x+curr.x)/2, (next.y+curr.y)/2);
      ctx.stroke();
    })
    ctx.lineWidth = 1;
  
    //intersects
    for(var i=intersects.length;i--;){
      ctx.beginPath();
      ctx.arc(
        intersects[i].x,
        intersects[i].y,
        8, 0, 2 * Math.PI, false
      );
      ctx.fillStyle = "#FF8300";
      ctx.fill();
    };
  
    //midpoint
    ctx.beginPath();
    ctx.arc(
      this.storedmid.x,
      this.storedmid.y,
      2, 0, 2 * Math.PI, false
    );
    ctx.fillStyle = problem?"#FF0000":"#00FF00";
    ctx.fill();
  }
  
  module.exports = AreaConstraint;
  
  /*
  A = Pir^2
  P = 2Pir
  P/2Pi = r
  A = Pi*(P/(2Pi))^2
  A = Pi/Pi^2 * P/2
  A = P/2Pi
  
  A = w*h
  A/w = h
  P = 2w+2h
  P/2 = w+h
  P/2 - w = h
  A = w*(P/2 - w)
  A = wP/2 - w^2
  P = 2w + 2A/w
  
  A = 1/2 * b * h
  a/Sin(A) = b/Sin(b) = c/Sin(b)
  b = find max side
  c/Sin(90) = h/Sin(A)
  Sin(A)*c/Sin(90) = h
  
  A = 1/2 * b * Sin(A)*c/Sin(90)
  P = a + b + c
  
  So we know Area
  -we know angles
  Now we need to figure out the distances
  
  a/Sin(A) = b/Sin(B) = c/Sin(C)
  
  A = Sin(A)* Sin(C) * b^2 / (Sin(B)*Sin(90))
  */
  
  },{"../structures/AABB":19,"../structures/Line":22,"../structures/Polygon":21,"../structures/Triangle":20,"../structures/Vec2":7}],23:[function(require,module,exports){
  /*
  
    The High level of this explanation is
  
    1) Each particle is defined as
      (position + velocity*time)
  
    2) Using this, I can create a linear equation from two particles where...
      m = (positionA.y + velocityA.y*time) - (positionB.y + velocityB.y*time)
        / (positionA.x + velocityA.x*time) - (positionB.x + velocityB.x*time)
      and
      b = (positionA.y + velocityA.y*time) - (positionA.x + velocityA.x*time)*m
  
    3) Since I'm tring to find the exact time where a point is on a line, the equation
        becomes
      y = mx + b
      (positionP.y + velocityP.y*time) = m*(positionP.x + velocityP.x*time) + b
  
    4) From here its about simplifying the equation until I get something solvable for time
      I soon learned that the equation becomes a quadratic equation
      a*time^2 + b*time + c
    4a)
      as a result I can solve all the issue with
      (-b (+||-) (b^2 - 4*a*c)^(1/2) ) / (2*a)
    4b) if a = 0, then the equation becomes even simpler
      time = -c/b
    4c) if b is 0 and a is 0, we have nothing.
  
    5) However, The times I'm looking for are specific.
    5a) The time should be negative. I don't want to predict the future, I want to fix the past
    5b) The time cannot be larger than the current timestep. If it is, we are looking too far back
    5c) there may be a possibility that there are two times that fit our description.
      as a result, we want to find the one that happened first. A simply Math.min works
  
    6) Return the value!
  
  */
  
  
  module.exports.getImpacts = function(susP, lineA, lineB){
  
    var vPsubvA = susP.vel.clone().sub(lineA.vel);
    var vAsubvB = lineA.vel.clone().sub(lineB.vel);
    var pPsubpA = susP.pos.clone().sub(lineA.pos);
    var pAsubpB = lineA.pos.clone().sub(lineB.pos);
  
    var a = vPsubvA.cross(vAsubvB);
    var b = vPsubvA.cross(pAsubpB) + pPsubpA.cross(vAsubvB);
    var c = pPsubpA.cross(pAsubpB);
  
    if(a === 0){
      //no need for quadratic
      if(b === 0) return false;
      return [-c/b];
    }
    var squared = Math.pow(b,2) - 4*a*c;
    if(squared < 0){
      return false;
    }
  
    if(squared === 0){
      return [-b/(2*a)];
    }
    var minus = (-b - Math.sqrt(squared))/(2*a);
    var plus = (-b + Math.sqrt(squared))/(2*a);
  
  
  
    return [minus,plus];
  };
  
  module.exports.restrict = function(times, timestep){
    var ret = false;
    var l = times.length;
    while(l--){
      if(times[l] > 0) continue;
      if(times[l] < -timestep) continue;
      ret = Math.min(ret,times[l]);
    }
    return ret;
  };
  
  
  /*
  y = m*x+b
  m = (
  (time*velA.y + posA.y) - (time*velB.y + posB.y)
  /
  (time*velA.x + posA.x) - (time*velB.x + posB.x)
  )
  m = (
  time*(velA.y - velB.y) + (posA.y - posB.y)
  /
  time*(velA.x - velB.x) + (posA.x - posB.x)
  )
  b = y - m*x
  
  b = (time*velA.y + posA.y) - m*(time*velA.x + posA.x)
  
  y = mx + (time*velA.y + posA.y) - m*(time*velA.x + posA.x)
  y = m*(x - (time*velA.x + posA.x)) + (time*velA.y + posA.y)
  (y - (time*velA.y + posA.y))*( time*(velA.x - velB.x) + (posA.x - posB.x) )
  =
  (x - (time*velA.x + posA.x))*( time*(velA.y - velB.y) + (posA.y - posB.y) )
  
  net = (time*vel + pos)
  
  solve for time where x = (time*velP.x + posP.x) and y = (time*velP.y + posP.y)
  ((time*velP.y + posP.y) - (time*velA.y + posA.y))
  *( time*(velA.x - velB.x) + (posA.x - posB.x) )
  =
  ((time*velP.x + posP.x) - (time*velA.x + posA.x))
  *( time*(velA.y - velB.y) + (posA.y - posB.y) )
  
  ( time*(velP.y - velA.y) + (posP.y - posA.y) )
  *( time*(velA.x - velB.x) + (posA.x - posB.x) )
  =
  ( time*(velP.x - velA.x) + (posP.x - posA.x) )
  *( time*(velA.y - velB.y) + (posA.y - posB.y) )
  
  ( time*time*(velP.y - velA.y)*(velA.x - velB.x))
  + time*(velP.y - velA.y)*(posA.x - posB.x)
  + time*(velA.x - velB.x)*(posP.y - posA.y)
  + (posP.y - posA.y)*(posA.x - posB.x)
  )
  =
  ( time*time*(velP.x - velA.x)*(velA.y - velB.y)
  + time*(velP.x - velA.x)*(posA.y - posB.y)
  + time*(velA.y - velB.y)*(posP.x - posA.x)
  + (posP.x - posA.x)*(posA.y - posB.y)
  )
  0
  =
  time*time(
  (velP.x - velA.x)*(velA.y - velB.y)
  - (velP.y - velA.y)*(velA.x - velB.x)
  )
  + time*(
  (velP.x - velA.x)*(posA.y - posB.y)
  + (velA.y - velB.y)*(posP.x - posA.x)
  - (velP.y - velA.y)*(posA.x - posB.x)
  - (velA.x - velB.x)*(posP.y - posA.y)
  )
  + (posP.x - posA.x)*(posA.y - posB.y)
  - (posP.y - posA.y)*(posA.x - posB.x)
  
  0
  =
  time*time(
  (velP.x - velA.x)*(velA.y - velB.y)
  - (velP.y - velA.y)*(velA.x - velB.x)
  ) //cross
  + time*(
  (velP.x - velA.x)*(posA.y - posB.y)
  - (velP.y - velA.y)*(posA.x - posB.x)
  //cross
  + (posP.x - posA.x)*(velA.y - velB.y)
  - (posP.y - posA.y)*(velA.x - velB.x)
  //cross
  )
  + (posP.x - posA.x)*(posA.y - posB.y)
  - (posP.y - posA.y)*(posA.x - posB.x)
  //cross
  */
  
  },{}],24:[function(require,module,exports){
  var Vel = require("./velocities.js");
  
  
  function getMassAtPoint(a,b,p){
  //  console.log("need to get the net mass behind the line");
    /*
      This can be based off liquid dynamics
      This can also be based off baseball bats
      This cannot be based off an average mass since the mass is actually the entire line
      We will be doing baseball bat...
    */
    var td = a.pos.dist(b.pos);
    //So the situation is like this
    //The further away p is from the center point
    //-the less mass a single side will have
    //The Closer it is
    //It will make no difference
    var diff = p.pos.dist(a.pos)/td;
    var m = 0;
    m += getParticleMass(a)*(diff > 0.5)?1-diff:1;
    m += getParticleMass(b)*(diff < 0.5?diff:1);
    return m;
  }
  
  function getElasticityAtPoint(a,b,p){
  //  console.log("need to get the net elasticity on the point");
    var ad = a.pos.dist(p.pos);
    var bd = b.pos.dist(p.pos);
    return getParticleElasticity(a)*bd/(ad+bd) + getParticleElasticity(b) * ad/ (ad+bd);
  }
  
  
  function getParticleMass(p){
  //  console.log("need to get the net mass behind the particle");
    return 1;
  }
  
  function getParticleElasticity(p){
  //  console.log("need to get the net elasticity behind the particle");
    return 0;
  }
  
  
  function collide(p,lp,slope){
    //Thank you http://www.euclideanspace.com/physics/dynamics/collision/twod/
    var e = (p.elasticity+lp.elasticity)/2;
    var ni = (1+e)*(p.mass*lp.mass)/(p.mass + lp.mass);
    ni = slope.mul(p.vel.clone().sub(lp.vel).dot(slope)).mul(ni);
  
    p.vel.sub(ni.div(p.mass));
    lp.vel.sub(ni.div(lp.mass));
  }
  
  function getLiquidMassAtPoint(p,container){
  
  }
  
  function distributeVelocities(p,a,b,time){
  //  var vels = Vel.getVelocities(a,b,time);
    a.pos.add(a.vel.clone().scale(time));
    b.pos.add(b.vel.clone().scale(time));
    p.pos.add(p.vel.clone().scale(time));
    p.mass= getParticleMass(p);
    p.elasticity = getParticleElasticity(p);
    var lp = {
      pos:  p.pos.clone(),
      vel:  Vel.getVelocityAtPoint(a,b,p),
      mass: getMassAtPoint(a,b,p),
      elasticity:getElasticityAtPoint(a,b,p)
    };
    var dir = getDirection(a,b,p,time);
  //  console.log(dir);
  
    collide(p,lp,dir);
  
    Vel.getVelocitiesFromPoint(a,b,lp);
    a.pos.sub(a.vel.clone().scale(time));
    b.pos.sub(b.vel.clone().scale(time));
    p.pos.sub(p.vel.clone().scale(time));
  
  //  console.log(a,b,p);
  
  }
  
  function getDirection(a,b,p,time){
    var dir = a.pos.clone().sub(b.pos).swap();
    var op = p.pos.clone().sub(b.pos).sub(p.vel.clone());
    if(dir.mul(-1,1).dist(op) > dir.mul(-1,-1).dist(op)){
      return dir.normalize();
    }
    return dir.mul(-1,-1).normalize();
  }
  
  module.exports.distributeVelocities = distributeVelocities;
  
  },{"./velocities.js":25}],19:[function(require,module,exports){
  var Vec2 = require("./Vec2");
  var Line = require("./Line");
  
  function AABB (points){
    this.max = new Vec2().neginf();
    this.min = new Vec2().posinf();
    if(points){
      var l;
      if(arguments.length > 1){
        l = arguments.length;
        while(l--){this.digestPoint(arguments[l]);}
      }else{
        l = points.length;
        while(l--){this.digestPoint(points[l]);}
      }
    }
  }
  
  AABB.prototype.toArray = function(){
    return this.min.toArray().concat(this.max.toArray());
  };
  
  AABB.prototype.clear = function(){
    this.max.neginf();
    this.min.posinf();
  };
  
  AABB.prototype.digestPoint = function(point){
    this.max.max(point);
    this.min.min(point);
  };
  
  AABB.prototype.intersectsAABB = function(oAABB){
    if(this.min.x >= oAABB.max.x) return false;
    if(this.min.y >= oAABB.max.y) return false;
    if(oAABB.min.x >= this.max.x) return false;
    if(oAABB.min.y >= this.max.y) return false;
    return true;
  };
  
  AABB.prototype.sub = function(oAABB){
    this.min.max(oAABB.min);
    this.max.min(oAABB.max);
    return this;
  };
  
  
  AABB.prototype.getSuspects =function(particles){
    var lines = [];
    var inside = [];
    var done = [];
    var l = particles.length;
    var len = l;
    var xboo = false, yboo = false;
    var temp, ari, ll;
    while(l--){
      xboo = (  particles[l].pos.x <= this.max.x &&
                particles[l].pos.x >= this.min.x );
      yboo = (  particles[l].pos.y <= this.max.y &&
                particles[l].pos.y >= this.min.y );
      if(!xboo && !yboo) continue;
      if(xboo && yboo){
        inside.push(l);
      }
      ari = [[(l+len-1)%len,l], [l, (l+1)%len]];
      ll = 2;
      while(ll--){
        if(done.indexOf(ari[ll].join("|")) !== -1) continue;
        done.push(ari[ll].join("|"));
        var p1 = particles[ari[ll][0]].pos;
        var p2 = particles[ari[ll][1]].pos;
        if(this.containsPoint(p1) || this.containsPoint(p2)){
          lines.push(ari[ll]);
          continue;
        }
        temp = new AABB(p1, p2);
        if(!this.intersectsAABB(temp)) continue;
        temp = new Line(p1,p2);
        if(!this.intersectsLine(temp)) continue;
        lines.push(ari[ll]);
      }
    }
    return {inside:inside, lines:lines};
  };
  
  
  AABB.prototype.containsPoint = function(point){
    if(point.x > this.max.x) return false;
    if(point.y > this.max.y) return false;
    if(point.x < this.min.x) return false;
    if(point.y < this.min.y) return false;
    return true;
  };
  
  AABB.prototype.intersectsLine = function(line){
    var tline = new Line(this.max, new Vec2(this.min.x,this.max.y));
    var p = tline.intersectsLineSegment(line);
    if(p && this.containsPoint(p)) return true;
    tline = new Line(this.max, new Vec2(this.max.x,this.min.y));
    p = tline.intersectsLineSegment(line);
    if(p && this.containsPoint(p)) return true;
    tline = new Line(this.min, new Vec2(this.max.x,this.min.y));
    p = tline.intersectsLineSegment(line);
    if(p && this.containsPoint(p)) return true;
    tline = new Line(this.min, new Vec2(this.min.x,this.max.y));
    p = tline.intersectsLineSegment(line);
    if(p && this.containsPoint(p)) return true;
    return false;
  };
  
  
  AABB.prototype.intersectsCircle = function(c){
    if(c.containsPoint(this.max)) return true;
    if(c.containsPoint(this.min)) return true;
    if(c.containsPoint(new Vec2(this.min.x,this.max.y))) return true;
    if(c.containsPoint(new Vec2(this.max.x,this.min.y))) return true;
    return false;
  };
  
  module.exports = AABB;
  
  },{"./Line":22,"./Vec2":7}],25:[function(require,module,exports){
  
  function getVelocities(A1,B1,time){
    //Getting the midpoint between the points before velocities
    var M1 = A1.pos.clone().mid(B1.pos);
    //Getting the "angle" before vels, if one is 0, we need to divide the other
    var Ang1 = A1.pos.clone().sub(B1.pos);
    //Getting the distance before vels
    var D1 = A1.pos.dist(B1.pos);
  
    //Getting the positions after velocities
    var A2 = A1.pos.clone().add(A1.vel.clone().scale(time));
    var B2 = B1.pos.clone().add(B1.vel.clone().scale(time));
    //Getting the midpoint between the points after velocities
    var M2 = A2.clone().mid(B2);
    //Getting the "angle" after vels
    var Ang2 = A2.clone().sub(B2);
    //Getting the distance after vels
    var D2 = A2.dist(B2);
  
  
    //Linear Velocity is the difference between the midpoints
    var linearvel = M2.clone().sub(M1);
  
    //Expanding Velocity is the velocity that is parrallel to the line
    //Rotational velocity is the velocity that is perpendicular to the line
  
    var A1_er_Vel = A1.vel.clone().sub(linearvel);
    var B1_er_Vel = B1.vel.clone().sub(linearvel);
  
  
  
    //expansion velocity is the difference between the distances
    var expandvel = 0;
    //Use law of cosigns to find the angular velocity?
    var rotatevel = 0;
  
    if(Math.abs(Ang1.angle() - Ang2.angle()) > 0.0001){
      //we only worry about rotational vels if the slopes are different
      //If it was real rotational velocity, this would not fly
      //The Angle we're looking for is opposite of the distance between the new point and old
      //The radius is the other two lengths
      //I am aware this is not correct
      rotatevel = Math.acos(1 - Math.pow(A2.dist(A1),2) / (Math.pow(D2,2)/2));
    }
    if(rotatevel === 0){
      if(Math.abs(D2 - D1) > 0.000001){
        //Normalized in resp00ect to A and M
        //expansion velocity is the difference between the distances
        expandvel = A1.pos.clone().sub(M1).div(D1).abs().mul(D2-D1);
      }
      //We don't need to worry about Expansive velocities if no change in rotation and distance
    }else{
      console.log("we have an angle?");
      //technically expansive velocities are higly dependent on rotational
      //But in reality, if there is a "rotational" vel
      //there will be a expansive vel since "rotational" vel's actually cut through
      //The radius because all velocities are linear
    }
  
  
    return {
      cache:{
        before:{a:A1,b:B1,m:M1,ang:Ang1,d:D1},
        after:{a:A2,b:B2,m:M2,ang:Ang2,d:D2}
      },
      linearvel: linearvel,
      expandvel: expandvel,
      rotatevel: rotatevel
    };
  }
  
  /*
    net_vel.x*distance = parrallel_magnitude*net_slope.x +
                      -1*perpendicular_magnitude*net_slope.y
  
    net_vel.y*distance = parrallel_magnitude*net_slope.y +
                      + perpendicular_magnitude*net_slope.x
  */
  function getParallelVelocity(net_vel,net_slope){
    var dist = net_slope.length();
    //  var per = (net_slope.x*par - net_vel.x*dist)/net_slope.y;
    //  var par*net_slope.y = net_vel.y*dist - net_slope.x*per
    //  var par*net_slope.y = net_vel.y*dist - net_slope.x*(net_slope.x*par - net_vel.x*dist)/net_slope.y
    //  var par*net_slope.y = net_vel.y*dist - net_slope.x/net_slope.y*(net_slope.x*par - net_vel.x*dist)
    //  var par*net_slope.y = net_vel.y*dist - net_slope.x/net_slope.y*net_slope.x*par + net_slope.x/net_slope.y*net_vel.x*dist
    //  var par*net_slope.y + net_slope.x/net_slope.y*net_slope.x*par = net_vel.y*dist + net_slope.x/net_slope.y*net_vel.x*dist
    //  var par(net_slope.y + net_slope.x*net_slope.x/net_slope.y) = net_vel.y*dist + net_slope.x/net_slope.y*net_vel.x*dist
    //  var par(net_slope.y + net_slope.x*net_slope.x/net_slope.y) = net_vel.y*dist + net_vel.x*dist*net_slope.x/net_slope.y
    //  var par(net_slope.y + net_slope.x*net_slope.x/net_slope.y) = dist*(net_vel.y + net_vel.x*net_slope.x/net_slope.y)
    //  var par = dist*(net_vel.y + net_vel.x*net_slope.x/net_slope.y)/(net_slope.y + net_slope.x*net_slope.x/net_slope.y)
    //  var par = dist*net_slop.y(net_vel.y + net_vel.x*net_slope.x/net_slope.y)/(net_slope.y*net_slope.y + net_slope.y*net_slope.x*net_slope.x/net_slope.y)
    //  var par = dist*(net_vel.y*net_slop.y + net_vel.x*net_slope.x)/(net_slope.y*net_slope.y + net_slope.x*net_slope.x)
    //  var par = dist*(net_vel.y*net_slop.y + net_vel.x*net_slope.x)/(net_slope.y^2 + net_slope.x^2)
  
  }
  
  /*
  net_vel.x*distance = parrallel_magnitude*net_slope.x +
                    -1*perpendicular_magnitude*net_slope.y
  
  net_vel.y*distance = parrallel_magnitude*net_slope.y +
                    + perpendicular_magnitude*net_slope.x
  */
  
  function getPerpendicularVelocity(net_vel,net_slope){
    var dist = net_slope.length();
  //  var par = (net_vel.x*dist + net_slope.y*per)/net_slope.x;
  //  var net_slope.x*per = net_vel.y*dist - net_slope.y*par;
  //  var net_slope.x*per = net_vel.y*dist - net_slope.y*(net_vel.x*dist + net_slope.y*per)/net_slope.x;
  //  var net_slope.x*per = net_vel.y*dist - net_slope.y/net_slope.x*(net_vel.x*dist + net_slope.y*per);
  //  var net_slope.x*per = net_vel.y*dist - net_vel.x*dist*net_slope.y/net_slope.x - net_slope.y*per*net_slope.y/net_slope.x;
  //  var net_slope.x*per + net_slope.y*per*net_slope.y/net_slope.x = net_vel.y*dist - net_vel.x*dist*net_slope.y/net_slope.x;
  //  var per*(net_slope.x + net_slope.y*net_slope.y/net_slope.x) = net_vel.y*dist - net_vel.x*dist*net_slope.y/net_slope.x;
  //  var per*net_slope.x*(net_slope.x + net_slope.y*net_slope.y/net_slope.x) = net_vel.y*dist*net_slope.x - net_vel.x*dist*net_slope.y;
  //  var per*(net_slope.x*net_slope.x + net_slope.y*net_slope.y) = net_vel.y*dist*net_slope.x - net_vel.x*dist*net_slope.y;
  //  var per = (net_vel.y*dist*net_slope.x - net_vel.x*dist*net_slope.y)/(net_slope.x*net_slope.x + net_slope.y*net_slope.y);
  //  var per = dist*(net_vel.y*net_slope.x - net_vel.x*net_slope.y)/(net_slope.x^2 + net_slope.y^2);
  
  }
  
  
  function getNetVelocityAtPoint(P1,vels){
    var M1 = vels.cache.before.m;
    var PD1 = P1.dist(M1);
    var D1 = vels.cache.before.d;
    var vel = vels.linearvel.clone();
    if(vels.rotatevel === 0){
      if(vels.expandvel === 0) return vel;
      return vel.add(vels.expandvel.mul(P1.clone().sub(M1).signum())*PD1*2/D1);
    }
  }
  
  function getVelocityAtPoint(A,B,P){
    var ad = A.pos.dist(P.pos);
    var bd = B.pos.dist(P.pos);
    return A.vel.clone().mul(bd).div(ad+bd).add(B.vel.clone().mul(ad).div(ad+bd));
  }
  
  function getVelocitiesFromPoint(A,B,P){
    var ad = A.pos.dist(P.pos);
    var bd = B.pos.dist(P.pos);
    var nd = ad+bd;
    //
  //  A = (ad+bd)*(P - B.vel.clone().mul(ad).div(ad+bd))/bd;
  //  B = (ad+bd)*(P - A.vel.clone().mul(bd).div(ad+bd))/ad;
  
    A.vel.mul(ad).div(nd).add(P.vel.mul(bd).div(nd));
    B.vel.mul(bd).div(nd).add(P.vel.mul(ad).div(nd));
  }
  
  
  module.exports.getVelocityAtPoint = getVelocityAtPoint;
  module.exports.getVelocitiesFromPoint = getVelocitiesFromPoint;
  module.exports.getNetVelocityAtPoint = getNetVelocityAtPoint;
  module.exports.getVelocities = getVelocities;
  
  /*
    We have the angle of the Line between point A and B
    we must then understand how much of the velocity at point A is
      -perpendicular
      -parrallel
  
    Parrellel line's definition assumes
      -The angle between the two lines are 0 or 180
      -the slope of the lines are equal
      -the vector's of the line can be
        - (-x, -slope*x) or (x, slope*x)
        - (-y/slope, -y) or (y/slope, y)
  
    Perpendicular line's definition assumes
      -The angle between the two lines are 90 or 270
      -The slope of the lines are -1*(x/y)
      -The vector's of the line can be
        - (-slope*x, -x) or (slope*x, x)
        - (-y, -y/slope) or (y, y/slope)
  
    f(net_vel) = parrallel_magnitude*normal_slope + perpendicular_magnitude*normal_slope
  
    normal_slope = net_slope/distance
  
    f(net_vel)  = parrallel_magnitude*net_slope/distance
                + perpendicular_magnitude*net_slope_swapped/distance
  
    net_vel = parrallel_magnitude*net_slope/distance
            + perpendicular_magnitude*net_slope_swapped/distance
  
    net_vel*distance = parrallel_magnitude*net_slope
                      + perpendicular_magnitude*-1*net_slope_swapped
  
  
    net_vel.x*distance = parrallel_magnitude*net_slope.x +
                      + perpendicular_magnitude*-1*net_slope.y
  
    net_vel.y*distance = parrallel_magnitude*net_slope.y +
                      + perpendicular_magnitude*net_slope.x
  
    perpendicular_magnitude = (net_vel.y*distance - parrallel_magnitude*net_slope.y)/net_slope.x
  
    net_vel.x*distance  =
      parrallel_magnitude*net_slope.x -
      net_slope.y*(net_vel.y*distance - parrallel_magnitude*net_slope.y)/net_slope.x
  
    net_vel.x*distance  =
      parrallel_magnitude*net_slope.x -
      net_slope.y/net_slope.x*(net_vel.y*distance - parrallel_magnitude*net_slope.y)
  
    net_vel.x*distance  =
      parrallel_magnitude*net_slope.x -
      net_slope.y/net_slope.x*net_vel.y*distance
      + net_slope.y/net_slope.x*parrallel_magnitude*net_slope.y
  
      net_vel.x*distance + net_slope.y/net_slope.x*net_vel.y*distance
    =
      parrallel_magnitude(net_slope.x + net_slope.y*net_slope.y/net_slope.x)
  
      parrallel_magnitude
    =
      net_vel.x*distance + net_slope.y/net_slope.x*net_vel.y*distance
      /(net_slope.x - + net_slope.y*net_slope.y/net_slope.x)
  
  
    parrallel_magnitude = (net_vel.y*distance - perpendicular_magnitude*net_slope.x)
    /net_slope.y
  
    net_vel.x*distance = (net_vel.y*distance - perpendicular_magnitude*net_slope.x)
                      /net_slope.y
                      + perpendicular_magnitude*-1*net_slope.y
  
    net_vel.x*distance =
      net_vel.y*distance/net_slope.y
      - perpendicular_magnitude*net_slope.x/net_slope.y
      + perpendicular_magnitude*-1*net_slope.y
  
    net_vel.x*distance - net_vel.y*distance/net_slope.y =
    -1*(net_slope.x/net_slope.y + net_slope.y)
    * perpendicular_magnitude
  
    perpendicular_magnitude =
      (net_vel.x*distance - net_vel.y*distance/net_slope.y)
      / -1*(net_slope.x/net_slope.y + net_slope.y)
  
    perpendicular_magnitude =
      distance*(net_vel.x - net_vel.y/net_slope.y)
      / (-1*(net_slope.x/net_slope.y + net_slope.y))
  
  
    perpendicular_magnitude =
      distance*(net_vel.x - net_vel.y/net_slope.y)
      / (-1*(net_slope.x/net_slope.y + net_slope.y))
  
  
    parrallel_magnitude =
      (
        net_vel.y*distance -
        (
          distance*(net_vel.x - net_vel.y/net_slope.y)
          / (-1*(net_slope.x/net_slope.y + net_slope.y))
        )*net_slope.x
      )/net_slope.y
  
    parrallel_magnitude =
      distance*(
        net_vel.y -
        (
          (net_vel.x - net_vel.y/net_slope.y)
          / (-1*(net_slope.x/net_slope.y + net_slope.y))
        )*net_slope.x
      )/net_slope.y
  
  
  
  */
  
  },{}],8:[function(require,module,exports){
  var AABB = require("../structures/AABB");
  var Line = require("../structures/Line");
  var boxIntersect = require("box-intersect");
  var Time = require("./time");
  var Momentum = require("./momentum");
  
  
  function toExport(composites,step){
    var l = composites.length;
    var aabbs = new Array(l);
    while(l--){
      aabbs[l] = composites[l].aabb.toArray();
    }
    var intersects = boxIntersect(aabbs);
    if(!(l = intersects.length)) return;
    while(l--){
      handleSuspects(
        composites[intersects[l][0]],
        composites[intersects[l][1]],
        step
      );
    }
  }
  
  function handleSuspects(compositeA, compositeB, timestep){
    var l, ll, i;
  
    var manifold = compositeA.aabb.sub(compositeB.aabb);
  
    var suspectsA = manifold.getSuspects(compositeA.particles);
    var suspectsB = manifold.getSuspects(compositeB.particles);
    if(suspectsA.lines.length === 0 || suspectsB.lines.length === 0){
      return false;
    }
    if(suspectsA.inside.length === 0 && suspectsB.inside.length === 0){
      return false;
    }
    l = suspectsA.inside.length;
    while(l--){
      ll = suspectsB.lines.length;
      while(ll--){
        runCollision(
          compositeA.particles[suspectsA.inside[l]], //the point
          compositeB.particles[suspectsB.lines[ll][0]], //a of the line
          compositeB.particles[suspectsB.lines[ll][1]],  //b of the line
          timestep
        );
      }
    }
    l = suspectsB.inside.length;
    while(l--){
      ll = suspectsA.lines.length;
      while(ll--){
        runCollision(
          compositeB.particles[suspectsB.inside[l]], //the point
          compositeA.particles[suspectsA.lines[ll][0]], //a of the line
          compositeA.particles[suspectsA.lines[ll][1]],  //b of the line
          timestep
        );
      }
    }
    // console.log("collision solved");
  }
  
  
  
  
  function runCollision(p,a,b,timestep){
  
    //this finds the time difference in which they first intersect
    var res = Time.getImpacts(p, a, b);
    if(!res) return false;
    res = Time.restrict(res,timestep);
    if(!res) return false;
  
    res /= timestep;
  
    Momentum.distributeVelocities(p,a,b,res);
  }
  
  
  
  module.exports = toExport;
  
  },{"../structures/AABB":19,"../structures/Line":22,"./momentum":24,"./time":23,"box-intersect":26}],21:[function(require,module,exports){
  function Polygon(oPoints){
    var l = oPoints.length;
    var i = l;
    var points = Array(i);
    while (i--) {
      points[l-i-1] = oPoints[i].pos||oPoints[i];
    }
    for(var i in Polygon.prototype){
      Object.defineProperty(points,i,{
        enumerable: false,
        value: Polygon.prototype[i].bind(points)
      });
    }
    return points;
  }
  
  Polygon.prototype.clone = function(){
    var points = this.slice(0);
    for(var i in Polygon.prototype){
      Object.defineProperty(points,i,{
        enumerable: false,
        value:Polygon.prototype[i].bind(points)
      });
    }
    return points;
  }
  
  Polygon.prototype.forThree = function(fn,skip){
    var l = this.length;
    var i = l - (skip||0);
    while(i--){
      var prev = (i+1)%l;//((i == 0)?l:i) -1
      var curr = i;
      var next = (i+l-1)%l; //i == l-1?0:i+1
      fn.call(this,this[prev],this[curr],this[next], curr);
    }
  }
  
  var cachable = require("./cacheable");
  for(var i in cachable){
    Polygon.prototype[i] = cachable[i]
  }
  var intersects = require("./intersects");
  for(var i in intersects){
    Polygon.prototype[i] = intersects[i]
  }
  
  module.exports = Polygon;
  
  },{"./cacheable":27,"./intersects":28}],22:[function(require,module,exports){
  var Vec2 = require("../Vec2");
  
  
  function Line(A,B){
    if(A.equals(B))
      throw new Error("cannot construct line when A == B");
    this.A = A;
    this.B = B;
  
    this.angledSlope = A.clone().sub(B).normalize();
    this.slope = this.angledSlope.scale(
      Math.sign(this.angledSlope.x)||Math.sign(this.angledSlope.y)
    );
    this.inv_slope = (this.slope.y == 0)?false:this.slope.x/this.slope.y;
    this.true_slope = (this.slope.x == 0)?false:this.slope.y/this.slope.x;
    this.yint = (this.true_slope !== false)?-this.true_slope*A.x + A.y:false;
    this.xint = (this.inv_slope !== false)?-this.inv_slope*A.y + A.x:false;
  
    this.mid = A.clone().mid(B);
    this.length2 = A.dist2(B);
    this.length = Math.sqrt(this.length2);
    this.cross = A.cross(B);
  }
  
  Line.prototype.toString = function(){
    return "limits:["+A+","+B+"]," +
    "intercepts:("+this.yint+","+thisxint+")";
    "slope:("+this.slope+"), ";
  }
  
  var interesctions = require("./intersects.js");
  
  for(var i in interesctions){
    Line.prototype[i] = interesctions[i];
  }
  var eq = require("./questions.js");
  
  for(var i in eq){
    Line.prototype[i] = eq[i];
  }
  
  //This should be in cacheable
  Line.prototype.perpendicularBisector = function(){
    var mid = this.mid;
    var A = this.A.clone().sub(mid).swap();
    var B = A.clone();
    A.y *= -1
    B.x *= -1;
    A.add(mid);
    B.add(mid);
    return new Line(A,B);
  }
  
  Line.prototype.getYValue = function(x){
    if(!this.slope.x) return false;
    return  x*this.true_slope + this.yint;
  };
  
  Line.prototype.getXValue = function(y){
    if(!this.slope.y) return false;
    return  y*this.inv_slope + this.xint;
  };
  
  
  module.exports = Line;
  
  },{"../Vec2":7,"./intersects.js":29,"./questions.js":30}],30:[function(require,module,exports){
  var Line = {};
  
  Line.equals = function(line){
    return this.A.equals(line.A)
    && this.B.equals(line.B);
  }
  
  Line.epsilonEquals = function(line, epsilon) {
    return this.A.epsilonEquals(line.A,epsilon)
    && this.B.epsilonEquals(line.B,epsilon);
  }
  
  Line.equalSlope = function(line) {
    return this.slope.equals(line.slope)
    && (this.xint)?this.xint == line.xint
    :this.yint == line.yint;
  }
  
  Line.epsilonEqualSlope = function(line, epsilon) {
    return this.slope.epsilonEquals(line.slope,epsilon)
    && (this.xint)?Math.abs(this.xint - line.xint) <= epsilon
    :Math.abs(this.yint - line.yint) <= epsilon
  }
  
  Line.equalMagnitude = function(line) {
    return this.slope.equals(line.slope)
    && this.length == line.length
  }
  
  Line.epsilonEqualMagnitude = function(line, epsilon) {
    return this.slope.epsilonEquals(line.slope,epsilon)
    && Math.abs(this.length - line.length) <= epsilon
  }
  
  
  module.exports =  Line;
  
  },{}],20:[function(require,module,exports){
  var Vec2 = require("../Vec2");
  var Line = require("../Line");
  
  
  function Triangle(A,B,C){
    if(A.equals(B) || B.equals(C) || C.equals(A))
      throw new Error("cannot create triangle when two points are the same")
    this.A = A;
    this.B = B;
    this.C = C;
    this.AB = new Line(A,B);
    this.BC = new Line(B,C);
    this.CA = new Line(C,A);
    this.ABC = Math.lawCos(this.CA.length, this.AB.length, this.BC.length);
    this.BCA = Math.asin(Math.sin(this.ABC)*this.CA.length/this.AB.length);
    this.CAB = Math.asin(Math.sin(this.ABC)*this.BC.length/this.AB.length);
    this.perimiter = this.AB.length + this.BC.length + this.CA.length
    this.partialArea = this.AB.cross + this.BC.cross + this.CA.cross
    this.area = Math.abs(this.partialArea);
  }
  
  
  var interesctions = require("./intersects.js");
  
  for(var i in interesctions){
    Triangle.prototype[i] = interesctions[i];
  }
  
  var questions = require("./questions.js");
  
  for(var i in questions){
    Triangle.prototype[i] = questions[i];
  }
  
  var cacheable = require("./cacheable.js");
  
  Triangle.prototype.getConcaveBisector = cacheable.getConcaveBisector;
  
  
  module.exports = Triangle;
  
  },{"../Line":22,"../Vec2":7,"./cacheable.js":33,"./intersects.js":31,"./questions.js":32}],31:[function(require,module,exports){
  var Triangle = {};
  
  Triangle.hasPoint = function(point){
    //http://www.blackpawn.com/texts/pointinpoly/
    // Compute vectors
    var v0 = this.C.clone().sub(this.B);
    var v1 = this.A.clone().sub(this.B);
    var v2 = point.clone().sub(this.B);
  
    // Compute dot products
    var dot00 = v0.dot(v0);
    var dot01 = v0.dot(v1);
    var dot02 = v0.dot(v2);
    var dot11 = v1.dot(v1);
    var dot12 = v1.dot(v2);
  
    // Compute barycentric coordinates
    var invDenom = 1 / (dot00 * dot11 - dot01 * dot01)
    var u = (dot11 * dot02 - dot01 * dot12) * invDenom
    var v = (dot00 * dot12 - dot01 * dot02) * invDenom
  
    // Check if point is in triangle
    return (u >= 0) && (v >= 0) && (u + v < 1)
  }
  
  module.exports = Triangle;
  
  },{}],32:[function(require,module,exports){
  
  var Triangle = {};
  
  var sqrt2 = Math.pow(2,1/2);
  
  Triangle.isConcave = function(a,b,c){
    //rotate the points around B to make B and A parrallel to the X axis
    //If the line BC is negative, it is Concave
    //If the line BC is positive, it is Convex
    var ac = new Line(a,c);
    //  A should always be rotated -PI/2
    return ac.pointIsLeftOrTop(ac.perpendicularBisector().A)
      == ac.pointIsLeftOrTop(b);
    // return Math.sign(p.x) == Math.sign(b.x) && Math.sign(p.y) == Math.sign(b.y);
  }
  
  Triangle.anglePrimer = function(){
    return this.CA.length - sqrt2*(this.AB.length+this.BC.length)/2;
  }
  
  Triangle.isAcute = function(){
    return this.anglePrimer() < 0;
  }
  
  Triangle.isObtuse = function(){
    return this.anglePrimer() > 0;
  }
  
  Triangle.isRight = function(){
    return this.anglePrimer() == 0;
  }
  
  Triangle.equals = function(tri){
    return this.A.equals(tri.A)
    && this.B.equals(tri.B)
    && this.C.equals(tri.C);
  }
  
  Triangle.epsilonEquals = function(tri, epsilon) {
    return this.A.epsilonEquals(tri.A,epsilon)
    && this.B.epsilonEquals(tri.B,epsilon)
    && this.C.epsilonEquals(tri.C,epsilon);
  }
  
  Triangle.equalShape = function(tri) {
    return this.area == tri.area && this.perimiter == tri.perimiter
  }
  
  Triangle.epsilonEqualShape = function(tri,epsilon) {
    return Math.abs(this.area - tri.area)/27 <= epsilon
    && Math.abs(this.perimiter - tri.perimiter)/9 <= epsilon;
  }
  
  Triangle.equalAngles = function(tri) {
    var keys = ["ABC","BCA", "CAB"];
    var i = 3;
    var j;
    while(i--){
      j = 3;
      while(j--){
        if(this[keys[i]] == tri[keys[i]]) break;
      }
      if(j < 0) return false;
    }
    return true;
  }
  
  
  module.exports = Triangle;
  
  },{}],33:[function(require,module,exports){
  var Triangle = {};
  
  Triangle.getConcaveBisector = function(){
    return this.CA.perpendicularBisector();
  }
  Triangle.AB = function(){
    return new Line(this.A,this.B);
  }
  Triangle.BC = function(){
    return new Line(B,C);
  }
  Triangle.CA = function(){
    return new Line(C,A);
  }
  Triangle.ABC = function(){
    return Math.lawCos(this.CA.length, this.AB.length, this.BC.length);
  }
  Triangle.BCA = function(){
    return Math.asin(Math.sin(this.ABC)*this.CA.length/this.AB.length);
  }
  Triangle.CAB = function(){
    return Math.asin(Math.sin(this.ABC)*this.BC.length/this.AB.length);
  }
  Triangle.perimiter = function(){
    return this.AB.length + this.BC.length + this.CA.length
  }
  Triangle.partialArea = function(){
    return this.AB.cross + this.BC.cross + this.CA.cross
  }
  Triangle.area = function(){
    return Math.abs(this.partialArea);
  }
  
  module.exports = Triangle;
  
  },{}],29:[function(require,module,exports){
  var Vec2 = require("../Vec2");
  var Line = {};
  
  Line.intersectsLine = function(lineB){
    var lineA = this;
    if(lineA.slope.equals(lineB.slope)) return false;
  
    var intersect = new Vec2();
    //lineA should take care of any special conditions
    if(lineA.slope.x === 0 || lineB.slope.x === 0){
      if(lineA.slope.y === 0 || lineB.slope.y === 0){
        return new Vec2(
          (lineA.slope.x === 0)?lineA.xint:lineB.xint,
          (lineA.slope.y === 0)?lineA.yint:lineB.yint
        );
      }
      //I don't care which one is which 0
      //calculate in respect to X
      intersect.y = (lineA.xint-lineB.xint)/(lineB.inv_slope-lineA.inv_slope);
      intersect.x = lineA.inv_slope*intersect.y + lineA.xint;
    }else{
      intersect.x = (lineA.yint-lineB.yint)/(lineB.true_slope-lineA.true_slope);
      intersect.y = lineA.true_slope*intersect.x + lineA.yint;
    }
    return intersect;
  }
  
  Line.intersectsLineSegment = function(line){
    var intersect = this.intersectsLine(line);
    if(!intersect) return false;
    if(!(new Vec2().posinf().min(this.A).min(this.B).max(intersect).equals(intersect)))
      return false;
    if(!(new Vec2().neginf().max(this.A).max(this.B).min(intersect).equals(intersect)))
      return false;
    if(!(new Vec2().posinf().min(line.A).min(line.B).max(intersect).equals(intersect)))
      return false;
    if(!(new Vec2().neginf().max(line.A).max(line.B).min(intersect).equals(intersect)))
      return false;
    return intersect;
  }
  
  Line.pointIsLeftOrTop = function(p){
    //get slopes of the lines
    //see if a ray cast from 0,0 intersects it
    return this.B.clone().sub(this.A).cross(p.clone().sub(this.A)) < 0;
  };
  
  Line.intersectsPoint = function(p){
    if(!this.slope.x) return this.xint == p.x;
    return p.y == p.x*this.slope.slope() + this.yint;
  };
  
  module.exports = Line;
  
  },{"../Vec2":7}],26:[function(require,module,exports){
  'use strict'
  
  module.exports = boxIntersectWrapper
  
  var pool = require('typedarray-pool')
  var sweep = require('./lib/sweep')
  var boxIntersectIter = require('./lib/intersect')
  
  function boxEmpty(d, box) {
    for(var j=0; j<d; ++j) {
      if(!(box[j] <= box[j+d])) {
        return true
      }
    }
    return false
  }
  
  //Unpack boxes into a flat typed array, remove empty boxes
  function convertBoxes(boxes, d, data, ids) {
    var ptr = 0
    var count = 0
    for(var i=0, n=boxes.length; i<n; ++i) {
      var b = boxes[i]
      if(boxEmpty(d, b)) {
        continue
      }
      for(var j=0; j<2*d; ++j) {
        data[ptr++] = b[j]
      }
      ids[count++] = i
    }
    return count
  }
  
  //Perform type conversions, check bounds
  function boxIntersect(red, blue, visit, full) {
    var n = red.length
    var m = blue.length
  
    //If either array is empty, then we can skip this whole thing
    if(n <= 0 || m <= 0) {
      return
    }
  
    //Compute dimension, if it is 0 then we skip
    var d = (red[0].length)>>>1
    if(d <= 0) {
      return
    }
  
    var retval
  
    //Convert red boxes
    var redList  = pool.mallocDouble(2*d*n)
    var redIds   = pool.mallocInt32(n)
    n = convertBoxes(red, d, redList, redIds)
  
    if(n > 0) {
      if(d === 1 && full) {
        //Special case: 1d complete
        sweep.init(n)
        retval = sweep.sweepComplete(
          d, visit, 
          0, n, redList, redIds,
          0, n, redList, redIds)
      } else {
  
        //Convert blue boxes
        var blueList = pool.mallocDouble(2*d*m)
        var blueIds  = pool.mallocInt32(m)
        m = convertBoxes(blue, d, blueList, blueIds)
  
        if(m > 0) {
          sweep.init(n+m)
  
          if(d === 1) {
            //Special case: 1d bipartite
            retval = sweep.sweepBipartite(
              d, visit, 
              0, n, redList,  redIds,
              0, m, blueList, blueIds)
          } else {
            //General case:  d>1
            retval = boxIntersectIter(
              d, visit,    full,
              n, redList,  redIds,
              m, blueList, blueIds)
          }
  
          pool.free(blueList)
          pool.free(blueIds)
        }
      }
  
      pool.free(redList)
      pool.free(redIds)
    }
  
    return retval
  }
  
  //User-friendly wrapper, handle full input and no-visitor cases
  function boxIntersectWrapper(arg0, arg1, arg2) {
    var result
    switch(arguments.length) {
      case 1:
        result = []
        boxIntersect(arg0, arg0, function(i,j) {
          result.push([i, j])
        }, true)
        return result
      case 2:
        if(typeof arg1 === 'function') {
          var visit = arg1
          return boxIntersect(arg0, arg0, visit, true)
        } else {
          result = []
          boxIntersect(arg0, arg1, function(i,j) {
            result.push([i, j])
          }, false)
          return result
        }
      case 3:
        return boxIntersect(arg0, arg1, arg2, false)
      default:
        throw new Error('box-intersect: Invalid arguments')
    }
  }
  },{"./lib/intersect":35,"./lib/sweep":34,"typedarray-pool":36}],27:[function(require,module,exports){
  var Vec2 = require("../Vec2");
  
  
  var Polygon = {};
  
  Polygon.getMidPoint = function(){
    var l = this.length;
    var mid = new Vec2();
    for(var i=this.length;i--;){
      mid.add(this[i].clone().scale(1/l));
    };
    return mid;
  }
  
  Polygon.getArea = function(){
    var net = 0;
    //http://www.wikihow.com/Calculate-the-Area-of-a-Polygon
    this.forThree(function(a,b,c){
      net += b.cross(c);
    })
    return net;
  }
  
  Polygon.getAABB = function(){
    var max = new Vec2(Number.NEGATIVE_INFINITY,Number.NEGATIVE_INFINITY);
    var min = new Vec2(Number.POSITIVE_INFINITY,Number.POSITIVE_INFINITY);
    for(var i=this.length;i--;){
      max.max(this[i]);
      min.min(this[i]);
    }
    return {max:max,min:min};
  }
  
  module.exports = Polygon
  
  },{"../Vec2":7}],28:[function(require,module,exports){
  var AABB = require("../AABB")
  var Line = require("../Line");
  var Polygon = {};
  
  Polygon.intersectsLine = function(line,skip){
    //creating smaller aabbs
    //We're going to detect intersection by slope
    //however, the point of intersection may be outside of the of the possible area
    //as a result we're creating a smaller aabb thats the maxes and minimums of the current area
  
    var tAABB = new AABB(line.A,line.B);
  
    var intersections = [];
  
    this.forThree(function(oprev,ocurr,onext){
      if(line.A == ocurr) return;
      if(line.B == oprev) return;
      if(oprev == line.A) return;
      var oAABB = new AABB(oprev,ocurr);
  
      if(!tAABB.intersectsAABB(oAABB)) return;
  
      //I would like to cache the oprev->ocurr line if possible
      //I would also prefer searching only for lines with the appropiate AABBs
      var intersect = line.intersectsLine(new Line(oprev,ocurr));
      if(!intersect) return;
  
      var netAABB = {
        max: oAABB.max.min(tAABB.max),
        min: oAABB.min.max(tAABB.min)
      };
      //If intersect point isn't between the two points, this isn't for us.
      if(!tAABB.containsPoint(intersect)) return;
  
      intersections.push(intersect);
  
    },skip);
    return intersections;
  }
  module.exports = Polygon;
  
  },{"../AABB":19,"../Line":22}],37:[function(require,module,exports){
  'use strict';
  
  //This code is extracted from ndarray-sort
  //It is inlined here as a temporary workaround
  
  module.exports = wrapper;
  
  var INSERT_SORT_CUTOFF = 32
  
  function wrapper(data, n0) {
    if (n0 <= 4*INSERT_SORT_CUTOFF) {
      insertionSort(0, n0 - 1, data);
    } else {
      quickSort(0, n0 - 1, data);
    }
  }
  
  function insertionSort(left, right, data) {
    var ptr = 2*(left+1)
    for(var i=left+1; i<=right; ++i) {
      var a = data[ptr++]
      var b = data[ptr++]
      var j = i
      var jptr = ptr-2
      while(j-- > left) {
        var x = data[jptr-2]
        var y = data[jptr-1]
        if(x < a) {
          break
        } else if(x === a && y < b) {
          break
        }
        data[jptr]   = x
        data[jptr+1] = y
        jptr -= 2
      }
      data[jptr]   = a
      data[jptr+1] = b
    }
  }
  
  function swap(i, j, data) {
    i *= 2
    j *= 2
    var x = data[i]
    var y = data[i+1]
    data[i] = data[j]
    data[i+1] = data[j+1]
    data[j] = x
    data[j+1] = y
  }
  
  function move(i, j, data) {
    i *= 2
    j *= 2
    data[i] = data[j]
    data[i+1] = data[j+1]
  }
  
  function rotate(i, j, k, data) {
    i *= 2
    j *= 2
    k *= 2
    var x = data[i]
    var y = data[i+1]
    data[i] = data[j]
    data[i+1] = data[j+1]
    data[j] = data[k]
    data[j+1] = data[k+1]
    data[k] = x
    data[k+1] = y
  }
  
  function shufflePivot(i, j, px, py, data) {
    i *= 2
    j *= 2
    data[i] = data[j]
    data[j] = px
    data[i+1] = data[j+1]
    data[j+1] = py
  }
  
  function compare(i, j, data) {
    i *= 2
    j *= 2
    var x = data[i],
        y = data[j]
    if(x < y) {
      return false
    } else if(x === y) {
      return data[i+1] > data[j+1]
    }
    return true
  }
  
  function comparePivot(i, y, b, data) {
    i *= 2
    var x = data[i]
    if(x < y) {
      return true
    } else if(x === y) {
      return data[i+1] < b
    }
    return false
  }
  
  function quickSort(left, right, data) {
    var sixth = (right - left + 1) / 6 | 0, 
        index1 = left + sixth, 
        index5 = right - sixth, 
        index3 = left + right >> 1, 
        index2 = index3 - sixth, 
        index4 = index3 + sixth, 
        el1 = index1, 
        el2 = index2, 
        el3 = index3, 
        el4 = index4, 
        el5 = index5, 
        less = left + 1, 
        great = right - 1, 
        tmp = 0
    if(compare(el1, el2, data)) {
      tmp = el1
      el1 = el2
      el2 = tmp
    }
    if(compare(el4, el5, data)) {
      tmp = el4
      el4 = el5
      el5 = tmp
    }
    if(compare(el1, el3, data)) {
      tmp = el1
      el1 = el3
      el3 = tmp
    }
    if(compare(el2, el3, data)) {
      tmp = el2
      el2 = el3
      el3 = tmp
    }
    if(compare(el1, el4, data)) {
      tmp = el1
      el1 = el4
      el4 = tmp
    }
    if(compare(el3, el4, data)) {
      tmp = el3
      el3 = el4
      el4 = tmp
    }
    if(compare(el2, el5, data)) {
      tmp = el2
      el2 = el5
      el5 = tmp
    }
    if(compare(el2, el3, data)) {
      tmp = el2
      el2 = el3
      el3 = tmp
    }
    if(compare(el4, el5, data)) {
      tmp = el4
      el4 = el5
      el5 = tmp
    }
  
    var pivot1X = data[2*el2]
    var pivot1Y = data[2*el2+1]
    var pivot2X = data[2*el4]
    var pivot2Y = data[2*el4+1]
  
    var ptr0 = 2 * el1;
    var ptr2 = 2 * el3;
    var ptr4 = 2 * el5;
    var ptr5 = 2 * index1;
    var ptr6 = 2 * index3;
    var ptr7 = 2 * index5;
    for (var i1 = 0; i1 < 2; ++i1) {
      var x = data[ptr0+i1];
      var y = data[ptr2+i1];
      var z = data[ptr4+i1];
      data[ptr5+i1] = x;
      data[ptr6+i1] = y;
      data[ptr7+i1] = z;
    }
  
    move(index2, left, data)
    move(index4, right, data)
    for (var k = less; k <= great; ++k) {
      if (comparePivot(k, pivot1X, pivot1Y, data)) {
        if (k !== less) {
          swap(k, less, data)
        }
        ++less;
      } else {
        if (!comparePivot(k, pivot2X, pivot2Y, data)) {
          while (true) {
            if (!comparePivot(great, pivot2X, pivot2Y, data)) {
              if (--great < k) {
                break;
              }
              continue;
            } else {
              if (comparePivot(great, pivot1X, pivot1Y, data)) {
                rotate(k, less, great, data)
                ++less;
                --great;
              } else {
                swap(k, great, data)
                --great;
              }
              break;
            }
          }
        }
      }
    }
    shufflePivot(left, less-1, pivot1X, pivot1Y, data)
    shufflePivot(right, great+1, pivot2X, pivot2Y, data)
    if (less - 2 - left <= INSERT_SORT_CUTOFF) {
      insertionSort(left, less - 2, data);
    } else {
      quickSort(left, less - 2, data);
    }
    if (right - (great + 2) <= INSERT_SORT_CUTOFF) {
      insertionSort(great + 2, right, data);
    } else {
      quickSort(great + 2, right, data);
    }
    if (great - less <= INSERT_SORT_CUTOFF) {
      insertionSort(less, great, data);
    } else {
      quickSort(less, great, data);
    }
  }
  },{}],38:[function(require,module,exports){
  'use strict'
  
  var DIMENSION   = 'd'
  var AXIS        = 'ax'
  var VISIT       = 'vv'
  var FLIP        = 'fp'
  
  var ELEM_SIZE   = 'es'
  
  var RED_START   = 'rs'
  var RED_END     = 're'
  var RED_BOXES   = 'rb'
  var RED_INDEX   = 'ri'
  var RED_PTR     = 'rp'
  
  var BLUE_START  = 'bs'
  var BLUE_END    = 'be'
  var BLUE_BOXES  = 'bb'
  var BLUE_INDEX  = 'bi'
  var BLUE_PTR    = 'bp'
  
  var RETVAL      = 'rv'
  
  var INNER_LABEL = 'Q'
  
  var ARGS = [
    DIMENSION,
    AXIS,
    VISIT,
    RED_START,
    RED_END,
    RED_BOXES,
    RED_INDEX,
    BLUE_START,
    BLUE_END,
    BLUE_BOXES,
    BLUE_INDEX
  ]
  
  function generateBruteForce(redMajor, flip, full) {
    var funcName = 'bruteForce' + 
      (redMajor ? 'Red' : 'Blue') + 
      (flip ? 'Flip' : '') +
      (full ? 'Full' : '')
  
    var code = ['function ', funcName, '(', ARGS.join(), '){',
      'var ', ELEM_SIZE, '=2*', DIMENSION, ';']
  
    var redLoop = 
      'for(var i=' + RED_START + ',' + RED_PTR + '=' + ELEM_SIZE + '*' + RED_START + ';' +
          'i<' + RED_END +';' +
          '++i,' + RED_PTR + '+=' + ELEM_SIZE + '){' +
          'var x0=' + RED_BOXES + '[' + AXIS + '+' + RED_PTR + '],' +
              'x1=' + RED_BOXES + '[' + AXIS + '+' + RED_PTR + '+' + DIMENSION + '],' +
              'xi=' + RED_INDEX + '[i];'
  
    var blueLoop = 
      'for(var j=' + BLUE_START + ',' + BLUE_PTR + '=' + ELEM_SIZE + '*' + BLUE_START + ';' +
          'j<' + BLUE_END + ';' +
          '++j,' + BLUE_PTR + '+=' + ELEM_SIZE + '){' +
          'var y0=' + BLUE_BOXES + '[' + AXIS + '+' + BLUE_PTR + '],' +
              (full ? 'y1=' + BLUE_BOXES + '[' + AXIS + '+' + BLUE_PTR + '+' + DIMENSION + '],' : '') +
              'yi=' + BLUE_INDEX + '[j];'
  
    if(redMajor) {
      code.push(redLoop, INNER_LABEL, ':', blueLoop)
    } else {
      code.push(blueLoop, INNER_LABEL, ':', redLoop)
    }
  
    if(full) {
      code.push('if(y1<x0||x1<y0)continue;')
    } else if(flip) {
      code.push('if(y0<=x0||x1<y0)continue;')
    } else {
      code.push('if(y0<x0||x1<y0)continue;')
    }
  
    code.push('for(var k='+AXIS+'+1;k<'+DIMENSION+';++k){'+
      'var r0='+RED_BOXES+'[k+'+RED_PTR+'],'+
          'r1='+RED_BOXES+'[k+'+DIMENSION+'+'+RED_PTR+'],'+
          'b0='+BLUE_BOXES+'[k+'+BLUE_PTR+'],'+
          'b1='+BLUE_BOXES+'[k+'+DIMENSION+'+'+BLUE_PTR+'];'+
        'if(r1<b0||b1<r0)continue ' + INNER_LABEL + ';}' +
        'var ' + RETVAL + '=' + VISIT + '(')
  
    if(flip) {
      code.push('yi,xi')
    } else {
      code.push('xi,yi')
    }
  
    code.push(');if(' + RETVAL + '!==void 0)return ' + RETVAL + ';}}}')
  
    return {
      name: funcName, 
      code: code.join('')
    }
  }
  
  function bruteForcePlanner(full) {
    var funcName = 'bruteForce' + (full ? 'Full' : 'Partial')
    var prefix = []
    var fargs = ARGS.slice()
    if(!full) {
      fargs.splice(3, 0, FLIP)
    }
  
    var code = ['function ' + funcName + '(' + fargs.join() + '){']
  
    function invoke(redMajor, flip) {
      var res = generateBruteForce(redMajor, flip, full)
      prefix.push(res.code)
      code.push('return ' + res.name + '(' + ARGS.join() + ');')
    }
  
    code.push('if(' + RED_END + '-' + RED_START + '>' +
                      BLUE_END + '-' + BLUE_START + '){')
  
    if(full) {
      invoke(true, false)
      code.push('}else{')
      invoke(false, false)
    } else {
      code.push('if(' + FLIP + '){')
      invoke(true, true)
      code.push('}else{')
      invoke(true, false)
      code.push('}}else{if(' + FLIP + '){')
      invoke(false, true)
      code.push('}else{')
      invoke(false, false)
      code.push('}')
    }
    code.push('}}return ' + funcName)
  
    var codeStr = prefix.join('') + code.join('')
    var proc = new Function(codeStr)
    return proc()
  }
  
  
  exports.partial = bruteForcePlanner(false)
  exports.full    = bruteForcePlanner(true)
  },{}],39:[function(require,module,exports){
  'use strict'
  
  module.exports = genPartition
  
  var code = 'for(var j=2*a,k=j*c,l=k,m=c,n=b,o=a+b,p=c;d>p;++p,k+=j){var _;if($)if(m===p)m+=1,l+=j;else{for(var s=0;j>s;++s){var t=e[k+s];e[k+s]=e[l],e[l++]=t}var u=f[p];f[p]=f[m],f[m++]=u}}return m'
  
  function genPartition(predicate, args) {
    var fargs ='abcdef'.split('').concat(args)
    var reads = []
    if(predicate.indexOf('lo') >= 0) {
      reads.push('lo=e[k+n]')
    }
    if(predicate.indexOf('hi') >= 0) {
      reads.push('hi=e[k+o]')
    }
    fargs.push(
      code.replace('_', reads.join())
          .replace('$', predicate))
    return Function.apply(void 0, fargs)
  }
  },{}],34:[function(require,module,exports){
  (function(){'use strict'
  
  module.exports = {
    init:           sqInit,
    sweepBipartite: sweepBipartite,
    sweepComplete:  sweepComplete,
    scanBipartite:  scanBipartite,
    scanComplete:   scanComplete
  }
  
  var pool  = require('typedarray-pool')
  var bits  = require('bit-twiddle')
  var isort = require('./sort')
  
  //Flag for blue
  var BLUE_FLAG = (1<<28)
  
  //1D sweep event queue stuff (use pool to save space)
  var INIT_CAPACITY      = 1024
  var RED_SWEEP_QUEUE    = pool.mallocInt32(INIT_CAPACITY)
  var RED_SWEEP_INDEX    = pool.mallocInt32(INIT_CAPACITY)
  var BLUE_SWEEP_QUEUE   = pool.mallocInt32(INIT_CAPACITY)
  var BLUE_SWEEP_INDEX   = pool.mallocInt32(INIT_CAPACITY)
  var COMMON_SWEEP_QUEUE = pool.mallocInt32(INIT_CAPACITY)
  var COMMON_SWEEP_INDEX = pool.mallocInt32(INIT_CAPACITY)
  var SWEEP_EVENTS       = pool.mallocDouble(INIT_CAPACITY * 8)
  
  //Reserves memory for the 1D sweep data structures
  function sqInit(count) {
    var rcount = bits.nextPow2(count)
    if(RED_SWEEP_QUEUE.length < rcount) {
      pool.free(RED_SWEEP_QUEUE)
      RED_SWEEP_QUEUE = pool.mallocInt32(rcount)
    }
    if(RED_SWEEP_INDEX.length < rcount) {
      pool.free(RED_SWEEP_INDEX)
      RED_SWEEP_INDEX = pool.mallocInt32(rcount)
    }
    if(BLUE_SWEEP_QUEUE.length < rcount) {
      pool.free(BLUE_SWEEP_QUEUE)
      BLUE_SWEEP_QUEUE = pool.mallocInt32(rcount)
    }
    if(BLUE_SWEEP_INDEX.length < rcount) {
      pool.free(BLUE_SWEEP_INDEX)
      BLUE_SWEEP_INDEX = pool.mallocInt32(rcount)
    }
    if(COMMON_SWEEP_QUEUE.length < rcount) {
      pool.free(COMMON_SWEEP_QUEUE)
      COMMON_SWEEP_QUEUE = pool.mallocInt32(rcount)
    }
    if(COMMON_SWEEP_INDEX.length < rcount) {
      pool.free(COMMON_SWEEP_INDEX)
      COMMON_SWEEP_INDEX = pool.mallocInt32(rcount)
    }
    var eventLength = 8 * rcount
    if(SWEEP_EVENTS.length < eventLength) {
      pool.free(SWEEP_EVENTS)
      SWEEP_EVENTS = pool.mallocDouble(eventLength)
    }
  }
  
  //Remove an item from the active queue in O(1)
  function sqPop(queue, index, count, item) {
    var idx = index[item]
    var top = queue[count-1]
    queue[idx] = top
    index[top] = idx
  }
  
  //Insert an item into the active queue in O(1)
  function sqPush(queue, index, count, item) {
    queue[count] = item
    index[item]  = count
  }
  
  //Recursion base case: use 1D sweep algorithm
  function sweepBipartite(
      d, visit,
      redStart,  redEnd, red, redIndex,
      blueStart, blueEnd, blue, blueIndex) {
  
    //store events as pairs [coordinate, idx]
    //
    //  red create:  -(idx+1)
    //  red destroy: idx
    //  blue create: -(idx+BLUE_FLAG)
    //  blue destroy: idx+BLUE_FLAG
    //
    var ptr      = 0
    var elemSize = 2*d
    var istart   = d-1
    var iend     = elemSize-1
  
    for(var i=redStart; i<redEnd; ++i) {
      var idx = redIndex[i]
      var redOffset = elemSize*i
      SWEEP_EVENTS[ptr++] = red[redOffset+istart]
      SWEEP_EVENTS[ptr++] = -(idx+1)
      SWEEP_EVENTS[ptr++] = red[redOffset+iend]
      SWEEP_EVENTS[ptr++] = idx
    }
  
    for(var i=blueStart; i<blueEnd; ++i) {
      var idx = blueIndex[i]+BLUE_FLAG
      var blueOffset = elemSize*i
      SWEEP_EVENTS[ptr++] = blue[blueOffset+istart]
      SWEEP_EVENTS[ptr++] = -idx
      SWEEP_EVENTS[ptr++] = blue[blueOffset+iend]
      SWEEP_EVENTS[ptr++] = idx
    }
  
    //process events from left->right
    var n = ptr >>> 1
    isort(SWEEP_EVENTS, n)
    
    var redActive  = 0
    var blueActive = 0
    for(var i=0; i<n; ++i) {
      var e = SWEEP_EVENTS[2*i+1]|0
      if(e >= BLUE_FLAG) {
        //blue destroy event
        e = (e-BLUE_FLAG)|0
        sqPop(BLUE_SWEEP_QUEUE, BLUE_SWEEP_INDEX, blueActive--, e)
      } else if(e >= 0) {
        //red destroy event
        sqPop(RED_SWEEP_QUEUE, RED_SWEEP_INDEX, redActive--, e)
      } else if(e <= -BLUE_FLAG) {
        //blue create event
        e = (-e-BLUE_FLAG)|0
        for(var j=0; j<redActive; ++j) {
          var retval = visit(RED_SWEEP_QUEUE[j], e)
          if(retval !== void 0) {
            return retval
          }
        }
        sqPush(BLUE_SWEEP_QUEUE, BLUE_SWEEP_INDEX, blueActive++, e)
      } else {
        //red create event
        e = (-e-1)|0
        for(var j=0; j<blueActive; ++j) {
          var retval = visit(e, BLUE_SWEEP_QUEUE[j])
          if(retval !== void 0) {
            return retval
          }
        }
        sqPush(RED_SWEEP_QUEUE, RED_SWEEP_INDEX, redActive++, e)
      }
    }
  }
  
  //Complete sweep
  function sweepComplete(d, visit, 
    redStart, redEnd, red, redIndex,
    blueStart, blueEnd, blue, blueIndex) {
  
    var ptr      = 0
    var elemSize = 2*d
    var istart   = d-1
    var iend     = elemSize-1
  
    for(var i=redStart; i<redEnd; ++i) {
      var idx = (redIndex[i]+1)<<1
      var redOffset = elemSize*i
      SWEEP_EVENTS[ptr++] = red[redOffset+istart]
      SWEEP_EVENTS[ptr++] = -idx
      SWEEP_EVENTS[ptr++] = red[redOffset+iend]
      SWEEP_EVENTS[ptr++] = idx
    }
  
    for(var i=blueStart; i<blueEnd; ++i) {
      var idx = (blueIndex[i]+1)<<1
      var blueOffset = elemSize*i
      SWEEP_EVENTS[ptr++] = blue[blueOffset+istart]
      SWEEP_EVENTS[ptr++] = (-idx)|1
      SWEEP_EVENTS[ptr++] = blue[blueOffset+iend]
      SWEEP_EVENTS[ptr++] = idx|1
    }
  
    //process events from left->right
    var n = ptr >>> 1
    isort(SWEEP_EVENTS, n)
    
    var redActive    = 0
    var blueActive   = 0
    var commonActive = 0
    for(var i=0; i<n; ++i) {
      var e     = SWEEP_EVENTS[2*i+1]|0
      var color = e&1
      if(i < n-1 && (e>>1) === (SWEEP_EVENTS[2*i+3]>>1)) {
        color = 2
        i += 1
      }
      
      if(e < 0) {
        //Create event
        var id = -(e>>1) - 1
  
        //Intersect with common
        for(var j=0; j<commonActive; ++j) {
          var retval = visit(COMMON_SWEEP_QUEUE[j], id)
          if(retval !== void 0) {
            return retval
          }
        }
  
        if(color !== 0) {
          //Intersect with red
          for(var j=0; j<redActive; ++j) {
            var retval = visit(RED_SWEEP_QUEUE[j], id)
            if(retval !== void 0) {
              return retval
            }
          }
        }
  
        if(color !== 1) {
          //Intersect with blue
          for(var j=0; j<blueActive; ++j) {
            var retval = visit(BLUE_SWEEP_QUEUE[j], id)
            if(retval !== void 0) {
              return retval
            }
          }
        }
  
        if(color === 0) {
          //Red
          sqPush(RED_SWEEP_QUEUE, RED_SWEEP_INDEX, redActive++, id)
        } else if(color === 1) {
          //Blue
          sqPush(BLUE_SWEEP_QUEUE, BLUE_SWEEP_INDEX, blueActive++, id)
        } else if(color === 2) {
          //Both
          sqPush(COMMON_SWEEP_QUEUE, COMMON_SWEEP_INDEX, commonActive++, id)
        }
      } else {
        //Destroy event
        var id = (e>>1) - 1
        if(color === 0) {
          //Red
          sqPop(RED_SWEEP_QUEUE, RED_SWEEP_INDEX, redActive--, id)
        } else if(color === 1) {
          //Blue
          sqPop(BLUE_SWEEP_QUEUE, BLUE_SWEEP_INDEX, blueActive--, id)
        } else if(color === 2) {
          //Both
          sqPop(COMMON_SWEEP_QUEUE, COMMON_SWEEP_INDEX, commonActive--, id)
        }
      }
    }
  }
  
  //Sweep and prune/scanline algorithm:
  //  Scan along axis, detect intersections
  //  Brute force all boxes along axis
  function scanBipartite(
    d, axis, visit, flip,
    redStart,  redEnd, red, redIndex,
    blueStart, blueEnd, blue, blueIndex) {
    
    var ptr      = 0
    var elemSize = 2*d
    var istart   = axis
    var iend     = axis+d
  
    var redShift  = 1
    var blueShift = 1
    if(flip) {
      blueShift = BLUE_FLAG
    } else {
      redShift  = BLUE_FLAG
    }
  
    for(var i=redStart; i<redEnd; ++i) {
      var idx = i + redShift
      var redOffset = elemSize*i
      SWEEP_EVENTS[ptr++] = red[redOffset+istart]
      SWEEP_EVENTS[ptr++] = -idx
      SWEEP_EVENTS[ptr++] = red[redOffset+iend]
      SWEEP_EVENTS[ptr++] = idx
    }
    for(var i=blueStart; i<blueEnd; ++i) {
      var idx = i + blueShift
      var blueOffset = elemSize*i
      SWEEP_EVENTS[ptr++] = blue[blueOffset+istart]
      SWEEP_EVENTS[ptr++] = -idx
    }
  
    //process events from left->right
    var n = ptr >>> 1
    isort(SWEEP_EVENTS, n)
    
    var redActive    = 0
    for(var i=0; i<n; ++i) {
      var e = SWEEP_EVENTS[2*i+1]|0
      if(e < 0) {
        var idx   = -e
        var isRed = false
        if(idx >= BLUE_FLAG) {
          isRed = !flip
          idx -= BLUE_FLAG 
        } else {
          isRed = !!flip
          idx -= 1
        }
        if(isRed) {
          sqPush(RED_SWEEP_QUEUE, RED_SWEEP_INDEX, redActive++, idx)
        } else {
          var blueId  = blueIndex[idx]
          var bluePtr = elemSize * idx
          
          var b0 = blue[bluePtr+axis+1]
          var b1 = blue[bluePtr+axis+1+d]
  
  red_loop:
          for(var j=0; j<redActive; ++j) {
            var oidx   = RED_SWEEP_QUEUE[j]
            var redPtr = elemSize * oidx
  
            if(b1 < red[redPtr+axis+1] || 
               red[redPtr+axis+1+d] < b0) {
              continue
            }
  
            for(var k=axis+2; k<d; ++k) {
              if(blue[bluePtr + k + d] < red[redPtr + k] || 
                 red[redPtr + k + d] < blue[bluePtr + k]) {
                continue red_loop
              }
            }
  
            var redId  = redIndex[oidx]
            var retval
            if(flip) {
              retval = visit(blueId, redId)
            } else {
              retval = visit(redId, blueId)
            }
            if(retval !== void 0) {
              return retval 
            }
          }
        }
      } else {
        sqPop(RED_SWEEP_QUEUE, RED_SWEEP_INDEX, redActive--, e - redShift)
      }
    }
  }
  
  function scanComplete(
    d, axis, visit,
    redStart,  redEnd, red, redIndex,
    blueStart, blueEnd, blue, blueIndex) {
  
    var ptr      = 0
    var elemSize = 2*d
    var istart   = axis
    var iend     = axis+d
  
    for(var i=redStart; i<redEnd; ++i) {
      var idx = i + BLUE_FLAG
      var redOffset = elemSize*i
      SWEEP_EVENTS[ptr++] = red[redOffset+istart]
      SWEEP_EVENTS[ptr++] = -idx
      SWEEP_EVENTS[ptr++] = red[redOffset+iend]
      SWEEP_EVENTS[ptr++] = idx
    }
    for(var i=blueStart; i<blueEnd; ++i) {
      var idx = i + 1
      var blueOffset = elemSize*i
      SWEEP_EVENTS[ptr++] = blue[blueOffset+istart]
      SWEEP_EVENTS[ptr++] = -idx
    }
  
    //process events from left->right
    var n = ptr >>> 1
    isort(SWEEP_EVENTS, n)
    
    var redActive    = 0
    for(var i=0; i<n; ++i) {
      var e = SWEEP_EVENTS[2*i+1]|0
      if(e < 0) {
        var idx   = -e
        if(idx >= BLUE_FLAG) {
          RED_SWEEP_QUEUE[redActive++] = idx - BLUE_FLAG
        } else {
          idx -= 1
          var blueId  = blueIndex[idx]
          var bluePtr = elemSize * idx
  
          var b0 = blue[bluePtr+axis+1]
          var b1 = blue[bluePtr+axis+1+d]
  
  red_loop:
          for(var j=0; j<redActive; ++j) {
            var oidx   = RED_SWEEP_QUEUE[j]
            var redId  = redIndex[oidx]
  
            if(redId === blueId) {
              break
            }
  
            var redPtr = elemSize * oidx
            if(b1 < red[redPtr+axis+1] || 
              red[redPtr+axis+1+d] < b0) {
              continue
            }
            for(var k=axis+2; k<d; ++k) {
              if(blue[bluePtr + k + d] < red[redPtr + k] || 
                 red[redPtr + k + d]   < blue[bluePtr + k]) {
                continue red_loop
              }
            }
  
            var retval = visit(redId, blueId)
            if(retval !== void 0) {
              return retval 
            }
          }
        }
      } else {
        var idx = e - BLUE_FLAG
        for(var j=redActive-1; j>=0; --j) {
          if(RED_SWEEP_QUEUE[j] === idx) {
            for(var k=j+1; k<redActive; ++k) {
              RED_SWEEP_QUEUE[k-1] = RED_SWEEP_QUEUE[k]
            }
            break
          }
        }
        --redActive
      }
    }
  }
  })()
  },{"./sort":37,"bit-twiddle":40,"typedarray-pool":36}],35:[function(require,module,exports){
  'use strict'
  
  module.exports = boxIntersectIter
  
  var pool = require('typedarray-pool')
  var bits = require('bit-twiddle')
  var bruteForce = require('./brute')
  var bruteForcePartial = bruteForce.partial
  var bruteForceFull = bruteForce.full
  var sweep = require('./sweep')
  var findMedian = require('./median')
  var genPartition = require('./partition')
  
  //Twiddle parameters
  var BRUTE_FORCE_CUTOFF    = 128       //Cut off for brute force search
  var SCAN_CUTOFF           = (1<<22)   //Cut off for two way scan
  var SCAN_COMPLETE_CUTOFF  = (1<<22)  
  
  //Partition functions
  var partitionInteriorContainsInterval = genPartition(
    '!(lo>=p0)&&!(p1>=hi)', 
    ['p0', 'p1'])
  
  var partitionStartEqual = genPartition(
    'lo===p0',
    ['p0'])
  
  var partitionStartLessThan = genPartition(
    'lo<p0',
    ['p0'])
  
  var partitionEndLessThanEqual = genPartition(
    'hi<=p0',
    ['p0'])
  
  var partitionContainsPoint = genPartition(
    'lo<=p0&&p0<=hi',
    ['p0'])
  
  var partitionContainsPointProper = genPartition(
    'lo<p0&&p0<=hi',
    ['p0'])
  
  //Frame size for iterative loop
  var IFRAME_SIZE = 6
  var DFRAME_SIZE = 2
  
  //Data for box statck
  var INIT_CAPACITY = 1024
  var BOX_ISTACK  = pool.mallocInt32(INIT_CAPACITY)
  var BOX_DSTACK  = pool.mallocDouble(INIT_CAPACITY)
  
  //Initialize iterative loop queue
  function iterInit(d, count) {
    var levels = (8 * bits.log2(count+1) * (d+1))|0
    var maxInts = bits.nextPow2(IFRAME_SIZE*levels)
    if(BOX_ISTACK.length < maxInts) {
      pool.free(BOX_ISTACK)
      BOX_ISTACK = pool.mallocInt32(maxInts)
    }
    var maxDoubles = bits.nextPow2(DFRAME_SIZE*levels)
    if(BOX_DSTACK < maxDoubles) {
      pool.free(BOX_DSTACK)
      BOX_DSTACK = pool.mallocDouble(maxDoubles)
    }
  }
  
  //Append item to queue
  function iterPush(ptr,
    axis, 
    redStart, redEnd, 
    blueStart, blueEnd, 
    state, 
    lo, hi) {
  
    var iptr = IFRAME_SIZE * ptr
    BOX_ISTACK[iptr]   = axis
    BOX_ISTACK[iptr+1] = redStart
    BOX_ISTACK[iptr+2] = redEnd
    BOX_ISTACK[iptr+3] = blueStart
    BOX_ISTACK[iptr+4] = blueEnd
    BOX_ISTACK[iptr+5] = state
  
    var dptr = DFRAME_SIZE * ptr
    BOX_DSTACK[dptr]   = lo
    BOX_DSTACK[dptr+1] = hi
  }
  
  //Special case:  Intersect single point with list of intervals
  function onePointPartial(
    d, axis, visit, flip,
    redStart, redEnd, red, redIndex,
    blueOffset, blue, blueId) {
  
    var elemSize = 2 * d
    var bluePtr  = blueOffset * elemSize
    var blueX    = blue[bluePtr + axis]
  
  red_loop:
    for(var i=redStart, redPtr=redStart*elemSize; i<redEnd; ++i, redPtr+=elemSize) {
      var r0 = red[redPtr+axis]
      var r1 = red[redPtr+axis+d]
      if(blueX < r0 || r1 < blueX) {
        continue
      }
      if(flip && blueX === r0) {
        continue
      }
      var redId = redIndex[i]
      for(var j=axis+1; j<d; ++j) {
        var r0 = red[redPtr+j]
        var r1 = red[redPtr+j+d]
        var b0 = blue[bluePtr+j]
        var b1 = blue[bluePtr+j+d]
        if(r1 < b0 || b1 < r0) {
          continue red_loop
        }
      }
      var retval
      if(flip) {
        retval = visit(blueId, redId)
      } else {
        retval = visit(redId, blueId)
      }
      if(retval !== void 0) {
        return retval
      }
    }
  }
  
  //Special case:  Intersect one point with list of intervals
  function onePointFull(
    d, axis, visit,
    redStart, redEnd, red, redIndex,
    blueOffset, blue, blueId) {
  
    var elemSize = 2 * d
    var bluePtr  = blueOffset * elemSize
    var blueX    = blue[bluePtr + axis]
  
  red_loop:
    for(var i=redStart, redPtr=redStart*elemSize; i<redEnd; ++i, redPtr+=elemSize) {
      var redId = redIndex[i]
      if(redId === blueId) {
        continue
      }
      var r0 = red[redPtr+axis]
      var r1 = red[redPtr+axis+d]
      if(blueX < r0 || r1 < blueX) {
        continue
      }
      for(var j=axis+1; j<d; ++j) {
        var r0 = red[redPtr+j]
        var r1 = red[redPtr+j+d]
        var b0 = blue[bluePtr+j]
        var b1 = blue[bluePtr+j+d]
        if(r1 < b0 || b1 < r0) {
          continue red_loop
        }
      }
      var retval = visit(redId, blueId)
      if(retval !== void 0) {
        return retval
      }
    }
  }
  
  //The main box intersection routine
  function boxIntersectIter(
    d, visit, initFull,
    xSize, xBoxes, xIndex,
    ySize, yBoxes, yIndex) {
  
    //Reserve memory for stack
    iterInit(d, xSize + ySize)
  
    var top  = 0
    var elemSize = 2 * d
    var retval
  
    iterPush(top++,
        0,
        0, xSize,
        0, ySize,
        initFull ? 16 : 0, 
        -Infinity, Infinity)
    if(!initFull) {
      iterPush(top++,
        0,
        0, ySize,
        0, xSize,
        1, 
        -Infinity, Infinity)
    }
  
    while(top > 0) {
      top  -= 1
  
      var iptr = top * IFRAME_SIZE
      var axis      = BOX_ISTACK[iptr]
      var redStart  = BOX_ISTACK[iptr+1]
      var redEnd    = BOX_ISTACK[iptr+2]
      var blueStart = BOX_ISTACK[iptr+3]
      var blueEnd   = BOX_ISTACK[iptr+4]
      var state     = BOX_ISTACK[iptr+5]
  
      var dptr = top * DFRAME_SIZE
      var lo        = BOX_DSTACK[dptr]
      var hi        = BOX_DSTACK[dptr+1]
  
      //Unpack state info
      var flip      = (state & 1)
      var full      = !!(state & 16)
  
      //Unpack indices
      var red       = xBoxes
      var redIndex  = xIndex
      var blue      = yBoxes
      var blueIndex = yIndex
      if(flip) {
        red         = yBoxes
        redIndex    = yIndex
        blue        = xBoxes
        blueIndex   = xIndex
      }
  
      if(state & 2) {
        redEnd = partitionStartLessThan(
          d, axis,
          redStart, redEnd, red, redIndex,
          hi)
        if(redStart >= redEnd) {
          continue
        }
      }
      if(state & 4) {
        redStart = partitionEndLessThanEqual(
          d, axis,
          redStart, redEnd, red, redIndex,
          lo)
        if(redStart >= redEnd) {
          continue
        }
      }
      
      var redCount  = redEnd  - redStart
      var blueCount = blueEnd - blueStart
  
      if(full) {
        if(d * redCount * (redCount + blueCount) < SCAN_COMPLETE_CUTOFF) {
          retval = sweep.scanComplete(
            d, axis, visit, 
            redStart, redEnd, red, redIndex,
            blueStart, blueEnd, blue, blueIndex)
          if(retval !== void 0) {
            return retval
          }
          continue
        }
      } else {
        if(d * Math.min(redCount, blueCount) < BRUTE_FORCE_CUTOFF) {
          //If input small, then use brute force
          retval = bruteForcePartial(
              d, axis, visit, flip,
              redStart,  redEnd,  red,  redIndex,
              blueStart, blueEnd, blue, blueIndex)
          if(retval !== void 0) {
            return retval
          }
          continue
        } else if(d * redCount * blueCount < SCAN_CUTOFF) {
          //If input medium sized, then use sweep and prune
          retval = sweep.scanBipartite(
            d, axis, visit, flip, 
            redStart, redEnd, red, redIndex,
            blueStart, blueEnd, blue, blueIndex)
          if(retval !== void 0) {
            return retval
          }
          continue
        }
      }
      
      //First, find all red intervals whose interior contains (lo,hi)
      var red0 = partitionInteriorContainsInterval(
        d, axis, 
        redStart, redEnd, red, redIndex,
        lo, hi)
  
      //Lower dimensional case
      if(redStart < red0) {
  
        if(d * (red0 - redStart) < BRUTE_FORCE_CUTOFF) {
          //Special case for small inputs: use brute force
          retval = bruteForceFull(
            d, axis+1, visit,
            redStart, red0, red, redIndex,
            blueStart, blueEnd, blue, blueIndex)
          if(retval !== void 0) {
            return retval
          }
        } else if(axis === d-2) {
          if(flip) {
            retval = sweep.sweepBipartite(
              d, visit,
              blueStart, blueEnd, blue, blueIndex,
              redStart, red0, red, redIndex)
          } else {
            retval = sweep.sweepBipartite(
              d, visit,
              redStart, red0, red, redIndex,
              blueStart, blueEnd, blue, blueIndex)
          }
          if(retval !== void 0) {
            return retval
          }
        } else {
          iterPush(top++,
            axis+1,
            redStart, red0,
            blueStart, blueEnd,
            flip,
            -Infinity, Infinity)
          iterPush(top++,
            axis+1,
            blueStart, blueEnd,
            redStart, red0,
            flip^1,
            -Infinity, Infinity)
        }
      }
  
      //Divide and conquer phase
      if(red0 < redEnd) {
  
        //Cut blue into 3 parts:
        //
        //  Points < mid point
        //  Points = mid point
        //  Points > mid point
        //
        var blue0 = findMedian(
          d, axis, 
          blueStart, blueEnd, blue, blueIndex)
        var mid = blue[elemSize * blue0 + axis]
        var blue1 = partitionStartEqual(
          d, axis,
          blue0, blueEnd, blue, blueIndex,
          mid)
  
        //Right case
        if(blue1 < blueEnd) {
          iterPush(top++,
            axis,
            red0, redEnd,
            blue1, blueEnd,
            (flip|4) + (full ? 16 : 0),
            mid, hi)
        }
  
        //Left case
        if(blueStart < blue0) {
          iterPush(top++,
            axis,
            red0, redEnd,
            blueStart, blue0,
            (flip|2) + (full ? 16 : 0),
            lo, mid)
        }
  
        //Center case (the hard part)
        if(blue0 + 1 === blue1) {
          //Optimization: Range with exactly 1 point, use a brute force scan
          if(full) {
            retval = onePointFull(
              d, axis, visit,
              red0, redEnd, red, redIndex,
              blue0, blue, blueIndex[blue0])
          } else {
            retval = onePointPartial(
              d, axis, visit, flip,
              red0, redEnd, red, redIndex,
              blue0, blue, blueIndex[blue0])
          }
          if(retval !== void 0) {
            return retval
          }
        } else if(blue0 < blue1) {
          var red1
          if(full) {
            //If full intersection, need to handle special case
            red1 = partitionContainsPoint(
              d, axis,
              red0, redEnd, red, redIndex,
              mid)
            if(red0 < red1) {
              var redX = partitionStartEqual(
                d, axis,
                red0, red1, red, redIndex,
                mid)
              if(axis === d-2) {
                //Degenerate sweep intersection:
                //  [red0, redX] with [blue0, blue1]
                if(red0 < redX) {
                  retval = sweep.sweepComplete(
                    d, visit,
                    red0, redX, red, redIndex,
                    blue0, blue1, blue, blueIndex)
                  if(retval !== void 0) {
                    return retval
                  }
                }
  
                //Normal sweep intersection:
                //  [redX, red1] with [blue0, blue1]
                if(redX < red1) {
                  retval = sweep.sweepBipartite(
                    d, visit,
                    redX, red1, red, redIndex,
                    blue0, blue1, blue, blueIndex)
                  if(retval !== void 0) {
                    return retval
                  }
                }
              } else {
                if(red0 < redX) {
                  iterPush(top++,
                    axis+1,
                    red0, redX,
                    blue0, blue1,
                    16,
                    -Infinity, Infinity)
                }
                if(redX < red1) {
                  iterPush(top++,
                    axis+1,
                    redX, red1,
                    blue0, blue1,
                    0,
                    -Infinity, Infinity)
                  iterPush(top++,
                    axis+1,
                    blue0, blue1,
                    redX, red1,
                    1,
                    -Infinity, Infinity)
                }
              }
            }
          } else {
            if(flip) {
              red1 = partitionContainsPointProper(
                d, axis,
                red0, redEnd, red, redIndex,
                mid)
            } else {
              red1 = partitionContainsPoint(
                d, axis,
                red0, redEnd, red, redIndex,
                mid)
            }
            if(red0 < red1) {
              if(axis === d-2) {
                if(flip) {
                  retval = sweep.sweepBipartite(
                    d, visit,
                    blue0, blue1, blue, blueIndex,
                    red0, red1, red, redIndex)
                } else {
                  retval = sweep.sweepBipartite(
                    d, visit,
                    red0, red1, red, redIndex,
                    blue0, blue1, blue, blueIndex)
                }
              } else {
                iterPush(top++,
                  axis+1,
                  red0, red1,
                  blue0, blue1,
                  flip,
                  -Infinity, Infinity)
                iterPush(top++,
                  axis+1,
                  blue0, blue1,
                  red0, red1,
                  flip^1,
                  -Infinity, Infinity)
              }
            }
          }
        }
      }
    }
  }
  },{"./brute":38,"./median":41,"./partition":39,"./sweep":34,"bit-twiddle":40,"typedarray-pool":36}],41:[function(require,module,exports){
  'use strict'
  
  module.exports = findMedian
  
  var genPartition = require('./partition')
  
  var partitionStartLessThan = genPartition('lo<p0', ['p0'])
  
  var PARTITION_THRESHOLD = 8   //Cut off for using insertion sort in findMedian
  
  //Base case for median finding:  Use insertion sort
  function insertionSort(d, axis, start, end, boxes, ids) {
    var elemSize = 2 * d
    var boxPtr = elemSize * (start+1) + axis
    for(var i=start+1; i<end; ++i, boxPtr+=elemSize) {
      var x = boxes[boxPtr]
      for(var j=i, ptr=elemSize*(i-1); 
          j>start && boxes[ptr+axis] > x; 
          --j, ptr-=elemSize) {
        //Swap
        var aPtr = ptr
        var bPtr = ptr+elemSize
        for(var k=0; k<elemSize; ++k, ++aPtr, ++bPtr) {
          var y = boxes[aPtr]
          boxes[aPtr] = boxes[bPtr]
          boxes[bPtr] = y
        }
        var tmp = ids[j]
        ids[j] = ids[j-1]
        ids[j-1] = tmp
      }
    }
  }
  
  //Find median using quick select algorithm
  //  takes O(n) time with high probability
  function findMedian(d, axis, start, end, boxes, ids) {
    if(end <= start+1) {
      return start
    }
  
    var lo       = start
    var hi       = end
    var mid      = ((end + start) >>> 1)
    var elemSize = 2*d
    var pivot    = mid
    var value    = boxes[elemSize*mid+axis]
    
    while(lo < hi) {
      if(hi - lo < PARTITION_THRESHOLD) {
        insertionSort(d, axis, lo, hi, boxes, ids)
        value = boxes[elemSize*mid+axis]
        break
      }
      
      //Select pivot using median-of-3
      var count  = hi - lo
      var pivot0 = (Math.random()*count+lo)|0
      var value0 = boxes[elemSize*pivot0 + axis]
      var pivot1 = (Math.random()*count+lo)|0
      var value1 = boxes[elemSize*pivot1 + axis]
      var pivot2 = (Math.random()*count+lo)|0
      var value2 = boxes[elemSize*pivot2 + axis]
      if(value0 <= value1) {
        if(value2 >= value1) {
          pivot = pivot1
          value = value1
        } else if(value0 >= value2) {
          pivot = pivot0
          value = value0
        } else {
          pivot = pivot2
          value = value2
        }
      } else {
        if(value1 >= value2) {
          pivot = pivot1
          value = value1
        } else if(value2 >= value0) {
          pivot = pivot0
          value = value0
        } else {
          pivot = pivot2
          value = value2
        }
      }
  
      //Swap pivot to end of array
      var aPtr = elemSize * (hi-1)
      var bPtr = elemSize * pivot
      for(var i=0; i<elemSize; ++i, ++aPtr, ++bPtr) {
        var x = boxes[aPtr]
        boxes[aPtr] = boxes[bPtr]
        boxes[bPtr] = x
      }
      var y = ids[hi-1]
      ids[hi-1] = ids[pivot]
      ids[pivot] = y
  
      //Partition using pivot
      pivot = partitionStartLessThan(
        d, axis, 
        lo, hi-1, boxes, ids,
        value)
  
      //Swap pivot back
      var aPtr = elemSize * (hi-1)
      var bPtr = elemSize * pivot
      for(var i=0; i<elemSize; ++i, ++aPtr, ++bPtr) {
        var x = boxes[aPtr]
        boxes[aPtr] = boxes[bPtr]
        boxes[bPtr] = x
      }
      var y = ids[hi-1]
      ids[hi-1] = ids[pivot]
      ids[pivot] = y
  
      //Swap pivot to last pivot
      if(mid < pivot) {
        hi = pivot-1
        while(lo < hi && 
          boxes[elemSize*(hi-1)+axis] === value) {
          hi -= 1
        }
        hi += 1
      } else if(pivot < mid) {
        lo = pivot + 1
        while(lo < hi &&
          boxes[elemSize*lo+axis] === value) {
          lo += 1
        }
      } else {
        break
      }
    }
  
    //Make sure pivot is at start
    return partitionStartLessThan(
      d, axis, 
      start, mid, boxes, ids,
      boxes[elemSize*mid+axis])
  }
  },{"./partition":39}],42:[function(require,module,exports){
  "use strict"
  
  function dupe_array(count, value, i) {
    var c = count[i]|0
    if(c <= 0) {
      return []
    }
    var result = new Array(c), j
    if(i === count.length-1) {
      for(j=0; j<c; ++j) {
        result[j] = value
      }
    } else {
      for(j=0; j<c; ++j) {
        result[j] = dupe_array(count, value, i+1)
      }
    }
    return result
  }
  
  function dupe_number(count, value) {
    var result, i
    result = new Array(count)
    for(i=0; i<count; ++i) {
      result[i] = value
    }
    return result
  }
  
  function dupe(count, value) {
    if(typeof value === "undefined") {
      value = 0
    }
    switch(typeof count) {
      case "number":
        if(count > 0) {
          return dupe_number(count|0, value)
        }
      break
      case "object":
        if(typeof (count.length) === "number") {
          return dupe_array(count, value, 0)
        }
      break
    }
    return []
  }
  
  module.exports = dupe
  },{}],40:[function(require,module,exports){
  /**
   * Bit twiddling hacks for JavaScript.
   *
   * Author: Mikola Lysenko
   *
   * Ported from Stanford bit twiddling hack library:
   *    http://graphics.stanford.edu/~seander/bithacks.html
   */
  
  "use strict"; "use restrict";
  
  //Number of bits in an integer
  var INT_BITS = 32;
  
  //Constants
  exports.INT_BITS  = INT_BITS;
  exports.INT_MAX   =  0x7fffffff;
  exports.INT_MIN   = -1<<(INT_BITS-1);
  
  //Returns -1, 0, +1 depending on sign of x
  exports.sign = function(v) {
    return (v > 0) - (v < 0);
  }
  
  //Computes absolute value of integer
  exports.abs = function(v) {
    var mask = v >> (INT_BITS-1);
    return (v ^ mask) - mask;
  }
  
  //Computes minimum of integers x and y
  exports.min = function(x, y) {
    return y ^ ((x ^ y) & -(x < y));
  }
  
  //Computes maximum of integers x and y
  exports.max = function(x, y) {
    return x ^ ((x ^ y) & -(x < y));
  }
  
  //Checks if a number is a power of two
  exports.isPow2 = function(v) {
    return !(v & (v-1)) && (!!v);
  }
  
  //Computes log base 2 of v
  exports.log2 = function(v) {
    var r, shift;
    r =     (v > 0xFFFF) << 4; v >>>= r;
    shift = (v > 0xFF  ) << 3; v >>>= shift; r |= shift;
    shift = (v > 0xF   ) << 2; v >>>= shift; r |= shift;
    shift = (v > 0x3   ) << 1; v >>>= shift; r |= shift;
    return r | (v >> 1);
  }
  
  //Computes log base 10 of v
  exports.log10 = function(v) {
    return  (v >= 1000000000) ? 9 : (v >= 100000000) ? 8 : (v >= 10000000) ? 7 :
            (v >= 1000000) ? 6 : (v >= 100000) ? 5 : (v >= 10000) ? 4 :
            (v >= 1000) ? 3 : (v >= 100) ? 2 : (v >= 10) ? 1 : 0;
  }
  
  //Counts number of bits
  exports.popCount = function(v) {
    v = v - ((v >>> 1) & 0x55555555);
    v = (v & 0x33333333) + ((v >>> 2) & 0x33333333);
    return ((v + (v >>> 4) & 0xF0F0F0F) * 0x1010101) >>> 24;
  }
  
  //Counts number of trailing zeros
  function countTrailingZeros(v) {
    var c = 32;
    v &= -v;
    if (v) c--;
    if (v & 0x0000FFFF) c -= 16;
    if (v & 0x00FF00FF) c -= 8;
    if (v & 0x0F0F0F0F) c -= 4;
    if (v & 0x33333333) c -= 2;
    if (v & 0x55555555) c -= 1;
    return c;
  }
  exports.countTrailingZeros = countTrailingZeros;
  
  //Rounds to next power of 2
  exports.nextPow2 = function(v) {
    v += v === 0;
    --v;
    v |= v >>> 1;
    v |= v >>> 2;
    v |= v >>> 4;
    v |= v >>> 8;
    v |= v >>> 16;
    return v + 1;
  }
  
  //Rounds down to previous power of 2
  exports.prevPow2 = function(v) {
    v |= v >>> 1;
    v |= v >>> 2;
    v |= v >>> 4;
    v |= v >>> 8;
    v |= v >>> 16;
    return v - (v>>>1);
  }
  
  //Computes parity of word
  exports.parity = function(v) {
    v ^= v >>> 16;
    v ^= v >>> 8;
    v ^= v >>> 4;
    v &= 0xf;
    return (0x6996 >>> v) & 1;
  }
  
  var REVERSE_TABLE = new Array(256);
  
  (function(tab) {
    for(var i=0; i<256; ++i) {
      var v = i, r = i, s = 7;
      for (v >>>= 1; v; v >>>= 1) {
        r <<= 1;
        r |= v & 1;
        --s;
      }
      tab[i] = (r << s) & 0xff;
    }
  })(REVERSE_TABLE);
  
  //Reverse bits in a 32 bit word
  exports.reverse = function(v) {
    return  (REVERSE_TABLE[ v         & 0xff] << 24) |
            (REVERSE_TABLE[(v >>> 8)  & 0xff] << 16) |
            (REVERSE_TABLE[(v >>> 16) & 0xff] << 8)  |
             REVERSE_TABLE[(v >>> 24) & 0xff];
  }
  
  //Interleave bits of 2 coordinates with 16 bits.  Useful for fast quadtree codes
  exports.interleave2 = function(x, y) {
    x &= 0xFFFF;
    x = (x | (x << 8)) & 0x00FF00FF;
    x = (x | (x << 4)) & 0x0F0F0F0F;
    x = (x | (x << 2)) & 0x33333333;
    x = (x | (x << 1)) & 0x55555555;
  
    y &= 0xFFFF;
    y = (y | (y << 8)) & 0x00FF00FF;
    y = (y | (y << 4)) & 0x0F0F0F0F;
    y = (y | (y << 2)) & 0x33333333;
    y = (y | (y << 1)) & 0x55555555;
  
    return x | (y << 1);
  }
  
  //Extracts the nth interleaved component
  exports.deinterleave2 = function(v, n) {
    v = (v >>> n) & 0x55555555;
    v = (v | (v >>> 1))  & 0x33333333;
    v = (v | (v >>> 2))  & 0x0F0F0F0F;
    v = (v | (v >>> 4))  & 0x00FF00FF;
    v = (v | (v >>> 16)) & 0x000FFFF;
    return (v << 16) >> 16;
  }
  
  
  //Interleave bits of 3 coordinates, each with 10 bits.  Useful for fast octree codes
  exports.interleave3 = function(x, y, z) {
    x &= 0x3FF;
    x  = (x | (x<<16)) & 4278190335;
    x  = (x | (x<<8))  & 251719695;
    x  = (x | (x<<4))  & 3272356035;
    x  = (x | (x<<2))  & 1227133513;
  
    y &= 0x3FF;
    y  = (y | (y<<16)) & 4278190335;
    y  = (y | (y<<8))  & 251719695;
    y  = (y | (y<<4))  & 3272356035;
    y  = (y | (y<<2))  & 1227133513;
    x |= (y << 1);
    
    z &= 0x3FF;
    z  = (z | (z<<16)) & 4278190335;
    z  = (z | (z<<8))  & 251719695;
    z  = (z | (z<<4))  & 3272356035;
    z  = (z | (z<<2))  & 1227133513;
    
    return x | (z << 2);
  }
  
  //Extracts nth interleaved component of a 3-tuple
  exports.deinterleave3 = function(v, n) {
    v = (v >>> n)       & 1227133513;
    v = (v | (v>>>2))   & 3272356035;
    v = (v | (v>>>4))   & 251719695;
    v = (v | (v>>>8))   & 4278190335;
    v = (v | (v>>>16))  & 0x3FF;
    return (v<<22)>>22;
  }
  
  //Computes next combination in colexicographic order (this is mistakenly called nextPermutation on the bit twiddling hacks page)
  exports.nextCombination = function(v) {
    var t = v | (v - 1);
    return (t + 1) | (((~t & -~t) - 1) >>> (countTrailingZeros(v) + 1));
  }
  
  
  },{}],43:[function(require,module,exports){
  require=(function(e,t,n,r){function i(r){if(!n[r]){if(!t[r]){if(e)return e(r);throw new Error("Cannot find module '"+r+"'")}var s=n[r]={exports:{}};t[r][0](function(e){var n=t[r][1][e];return i(n?n:e)},s,s.exports)}return n[r].exports}for(var s=0;s<r.length;s++)i(r[s]);return i})(typeof require!=="undefined"&&require,{1:[function(require,module,exports){
  exports.readIEEE754 = function(buffer, offset, isBE, mLen, nBytes) {
    var e, m,
        eLen = nBytes * 8 - mLen - 1,
        eMax = (1 << eLen) - 1,
        eBias = eMax >> 1,
        nBits = -7,
        i = isBE ? 0 : (nBytes - 1),
        d = isBE ? 1 : -1,
        s = buffer[offset + i];
  
    i += d;
  
    e = s & ((1 << (-nBits)) - 1);
    s >>= (-nBits);
    nBits += eLen;
    for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8);
  
    m = e & ((1 << (-nBits)) - 1);
    e >>= (-nBits);
    nBits += mLen;
    for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8);
  
    if (e === 0) {
      e = 1 - eBias;
    } else if (e === eMax) {
      return m ? NaN : ((s ? -1 : 1) * Infinity);
    } else {
      m = m + Math.pow(2, mLen);
      e = e - eBias;
    }
    return (s ? -1 : 1) * m * Math.pow(2, e - mLen);
  };
  
  exports.writeIEEE754 = function(buffer, value, offset, isBE, mLen, nBytes) {
    var e, m, c,
        eLen = nBytes * 8 - mLen - 1,
        eMax = (1 << eLen) - 1,
        eBias = eMax >> 1,
        rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0),
        i = isBE ? (nBytes - 1) : 0,
        d = isBE ? -1 : 1,
        s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0;
  
    value = Math.abs(value);
  
    if (isNaN(value) || value === Infinity) {
      m = isNaN(value) ? 1 : 0;
      e = eMax;
    } else {
      e = Math.floor(Math.log(value) / Math.LN2);
      if (value * (c = Math.pow(2, -e)) < 1) {
        e--;
        c *= 2;
      }
      if (e + eBias >= 1) {
        value += rt / c;
      } else {
        value += rt * Math.pow(2, 1 - eBias);
      }
      if (value * c >= 2) {
        e++;
        c /= 2;
      }
  
      if (e + eBias >= eMax) {
        m = 0;
        e = eMax;
      } else if (e + eBias >= 1) {
        m = (value * c - 1) * Math.pow(2, mLen);
        e = e + eBias;
      } else {
        m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
        e = 0;
      }
    }
  
    for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8);
  
    e = (e << mLen) | m;
    eLen += mLen;
    for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8);
  
    buffer[offset + i - d] |= s * 128;
  };
  
  },{}],2:[function(require,module,exports){
  (function(){// UTILITY
  var util = require('util');
  var Buffer = require("buffer").Buffer;
  var pSlice = Array.prototype.slice;
  
  function objectKeys(object) {
    if (Object.keys) return Object.keys(object);
    var result = [];
    for (var name in object) {
      if (Object.prototype.hasOwnProperty.call(object, name)) {
        result.push(name);
      }
    }
    return result;
  }
  
  // 1. The assert module provides functions that throw
  // AssertionError's when particular conditions are not met. The
  // assert module must conform to the following interface.
  
  var assert = module.exports = ok;
  
  // 2. The AssertionError is defined in assert.
  // new assert.AssertionError({ message: message,
  //                             actual: actual,
  //                             expected: expected })
  
  assert.AssertionError = function AssertionError(options) {
    this.name = 'AssertionError';
    this.message = options.message;
    this.actual = options.actual;
    this.expected = options.expected;
    this.operator = options.operator;
    var stackStartFunction = options.stackStartFunction || fail;
  
    if (Error.captureStackTrace) {
      Error.captureStackTrace(this, stackStartFunction);
    }
  };
  util.inherits(assert.AssertionError, Error);
  
  function replacer(key, value) {
    if (value === undefined) {
      return '' + value;
    }
    if (typeof value === 'number' && (isNaN(value) || !isFinite(value))) {
      return value.toString();
    }
    if (typeof value === 'function' || value instanceof RegExp) {
      return value.toString();
    }
    return value;
  }
  
  function truncate(s, n) {
    if (typeof s == 'string') {
      return s.length < n ? s : s.slice(0, n);
    } else {
      return s;
    }
  }
  
  assert.AssertionError.prototype.toString = function() {
    if (this.message) {
      return [this.name + ':', this.message].join(' ');
    } else {
      return [
        this.name + ':',
        truncate(JSON.stringify(this.actual, replacer), 128),
        this.operator,
        truncate(JSON.stringify(this.expected, replacer), 128)
      ].join(' ');
    }
  };
  
  // assert.AssertionError instanceof Error
  
  assert.AssertionError.__proto__ = Error.prototype;
  
  // At present only the three keys mentioned above are used and
  // understood by the spec. Implementations or sub modules can pass
  // other keys to the AssertionError's constructor - they will be
  // ignored.
  
  // 3. All of the following functions must throw an AssertionError
  // when a corresponding condition is not met, with a message that
  // may be undefined if not provided.  All assertion methods provide
  // both the actual and expected values to the assertion error for
  // display purposes.
  
  function fail(actual, expected, message, operator, stackStartFunction) {
    throw new assert.AssertionError({
      message: message,
      actual: actual,
      expected: expected,
      operator: operator,
      stackStartFunction: stackStartFunction
    });
  }
  
  // EXTENSION! allows for well behaved errors defined elsewhere.
  assert.fail = fail;
  
  // 4. Pure assertion tests whether a value is truthy, as determined
  // by !!guard.
  // assert.ok(guard, message_opt);
  // This statement is equivalent to assert.equal(true, guard,
  // message_opt);. To test strictly for the value true, use
  // assert.strictEqual(true, guard, message_opt);.
  
  function ok(value, message) {
    if (!!!value) fail(value, true, message, '==', assert.ok);
  }
  assert.ok = ok;
  
  // 5. The equality assertion tests shallow, coercive equality with
  // ==.
  // assert.equal(actual, expected, message_opt);
  
  assert.equal = function equal(actual, expected, message) {
    if (actual != expected) fail(actual, expected, message, '==', assert.equal);
  };
  
  // 6. The non-equality assertion tests for whether two objects are not equal
  // with != assert.notEqual(actual, expected, message_opt);
  
  assert.notEqual = function notEqual(actual, expected, message) {
    if (actual == expected) {
      fail(actual, expected, message, '!=', assert.notEqual);
    }
  };
  
  // 7. The equivalence assertion tests a deep equality relation.
  // assert.deepEqual(actual, expected, message_opt);
  
  assert.deepEqual = function deepEqual(actual, expected, message) {
    if (!_deepEqual(actual, expected)) {
      fail(actual, expected, message, 'deepEqual', assert.deepEqual);
    }
  };
  
  function _deepEqual(actual, expected) {
    // 7.1. All identical values are equivalent, as determined by ===.
    if (actual === expected) {
      return true;
  
    } else if (Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) {
      if (actual.length != expected.length) return false;
  
      for (var i = 0; i < actual.length; i++) {
        if (actual[i] !== expected[i]) return false;
      }
  
      return true;
  
    // 7.2. If the expected value is a Date object, the actual value is
    // equivalent if it is also a Date object that refers to the same time.
    } else if (actual instanceof Date && expected instanceof Date) {
      return actual.getTime() === expected.getTime();
  
    // 7.3. Other pairs that do not both pass typeof value == 'object',
    // equivalence is determined by ==.
    } else if (typeof actual != 'object' && typeof expected != 'object') {
      return actual == expected;
  
    // 7.4. For all other Object pairs, including Array objects, equivalence is
    // determined by having the same number of owned properties (as verified
    // with Object.prototype.hasOwnProperty.call), the same set of keys
    // (although not necessarily the same order), equivalent values for every
    // corresponding key, and an identical 'prototype' property. Note: this
    // accounts for both named and indexed properties on Arrays.
    } else {
      return objEquiv(actual, expected);
    }
  }
  
  function isUndefinedOrNull(value) {
    return value === null || value === undefined;
  }
  
  function isArguments(object) {
    return Object.prototype.toString.call(object) == '[object Arguments]';
  }
  
  function objEquiv(a, b) {
    if (isUndefinedOrNull(a) || isUndefinedOrNull(b))
      return false;
    // an identical 'prototype' property.
    if (a.prototype !== b.prototype) return false;
    //~~~I've managed to break Object.keys through screwy arguments passing.
    //   Converting to array solves the problem.
    if (isArguments(a)) {
      if (!isArguments(b)) {
        return false;
      }
      a = pSlice.call(a);
      b = pSlice.call(b);
      return _deepEqual(a, b);
    }
    try {
      var ka = objectKeys(a),
          kb = objectKeys(b),
          key, i;
    } catch (e) {//happens when one is a string literal and the other isn't
      return false;
    }
    // having the same number of owned properties (keys incorporates
    // hasOwnProperty)
    if (ka.length != kb.length)
      return false;
    //the same set of keys (although not necessarily the same order),
    ka.sort();
    kb.sort();
    //~~~cheap key test
    for (i = ka.length - 1; i >= 0; i--) {
      if (ka[i] != kb[i])
        return false;
    }
    //equivalent values for every corresponding key, and
    //~~~possibly expensive deep test
    for (i = ka.length - 1; i >= 0; i--) {
      key = ka[i];
      if (!_deepEqual(a[key], b[key])) return false;
    }
    return true;
  }
  
  // 8. The non-equivalence assertion tests for any deep inequality.
  // assert.notDeepEqual(actual, expected, message_opt);
  
  assert.notDeepEqual = function notDeepEqual(actual, expected, message) {
    if (_deepEqual(actual, expected)) {
      fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual);
    }
  };
  
  // 9. The strict equality assertion tests strict equality, as determined by ===.
  // assert.strictEqual(actual, expected, message_opt);
  
  assert.strictEqual = function strictEqual(actual, expected, message) {
    if (actual !== expected) {
      fail(actual, expected, message, '===', assert.strictEqual);
    }
  };
  
  // 10. The strict non-equality assertion tests for strict inequality, as
  // determined by !==.  assert.notStrictEqual(actual, expected, message_opt);
  
  assert.notStrictEqual = function notStrictEqual(actual, expected, message) {
    if (actual === expected) {
      fail(actual, expected, message, '!==', assert.notStrictEqual);
    }
  };
  
  function expectedException(actual, expected) {
    if (!actual || !expected) {
      return false;
    }
  
    if (expected instanceof RegExp) {
      return expected.test(actual);
    } else if (actual instanceof expected) {
      return true;
    } else if (expected.call({}, actual) === true) {
      return true;
    }
  
    return false;
  }
  
  function _throws(shouldThrow, block, expected, message) {
    var actual;
  
    if (typeof expected === 'string') {
      message = expected;
      expected = null;
    }
  
    try {
      block();
    } catch (e) {
      actual = e;
    }
  
    message = (expected && expected.name ? ' (' + expected.name + ').' : '.') +
              (message ? ' ' + message : '.');
  
    if (shouldThrow && !actual) {
      fail('Missing expected exception' + message);
    }
  
    if (!shouldThrow && expectedException(actual, expected)) {
      fail('Got unwanted exception' + message);
    }
  
    if ((shouldThrow && actual && expected &&
        !expectedException(actual, expected)) || (!shouldThrow && actual)) {
      throw actual;
    }
  }
  
  // 11. Expected to throw an error:
  // assert.throws(block, Error_opt, message_opt);
  
  assert.throws = function(block, /*optional*/error, /*optional*/message) {
    _throws.apply(this, [true].concat(pSlice.call(arguments)));
  };
  
  // EXTENSION! This is annoying to write outside this module.
  assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) {
    _throws.apply(this, [false].concat(pSlice.call(arguments)));
  };
  
  assert.ifError = function(err) { if (err) {throw err;}};
  
  })()
  },{"util":3,"buffer":4}],"buffer-browserify":[function(require,module,exports){
  module.exports=require('q9TxCC');
  },{}],"q9TxCC":[function(require,module,exports){
  (function(){function SlowBuffer (size) {
      this.length = size;
  };
  
  var assert = require('assert');
  
  exports.INSPECT_MAX_BYTES = 50;
  
  
  function toHex(n) {
    if (n < 16) return '0' + n.toString(16);
    return n.toString(16);
  }
  
  function utf8ToBytes(str) {
    var byteArray = [];
    for (var i = 0; i < str.length; i++)
      if (str.charCodeAt(i) <= 0x7F)
        byteArray.push(str.charCodeAt(i));
      else {
        var h = encodeURIComponent(str.charAt(i)).substr(1).split('%');
        for (var j = 0; j < h.length; j++)
          byteArray.push(parseInt(h[j], 16));
      }
  
    return byteArray;
  }
  
  function asciiToBytes(str) {
    var byteArray = []
    for (var i = 0; i < str.length; i++ )
      // Node's code seems to be doing this and not & 0x7F..
      byteArray.push( str.charCodeAt(i) & 0xFF );
  
    return byteArray;
  }
  
  function base64ToBytes(str) {
    return require("base64-js").toByteArray(str);
  }
  
  SlowBuffer.byteLength = function (str, encoding) {
    switch (encoding || "utf8") {
      case 'hex':
        return str.length / 2;
  
      case 'utf8':
      case 'utf-8':
        return utf8ToBytes(str).length;
  
      case 'ascii':
      case 'binary':
        return str.length;
  
      case 'base64':
        return base64ToBytes(str).length;
  
      default:
        throw new Error('Unknown encoding');
    }
  };
  
  function blitBuffer(src, dst, offset, length) {
    var pos, i = 0;
    while (i < length) {
      if ((i+offset >= dst.length) || (i >= src.length))
        break;
  
      dst[i + offset] = src[i];
      i++;
    }
    return i;
  }
  
  SlowBuffer.prototype.utf8Write = function (string, offset, length) {
    var bytes, pos;
    return SlowBuffer._charsWritten =  blitBuffer(utf8ToBytes(string), this, offset, length);
  };
  
  SlowBuffer.prototype.asciiWrite = function (string, offset, length) {
    var bytes, pos;
    return SlowBuffer._charsWritten =  blitBuffer(asciiToBytes(string), this, offset, length);
  };
  
  SlowBuffer.prototype.binaryWrite = SlowBuffer.prototype.asciiWrite;
  
  SlowBuffer.prototype.base64Write = function (string, offset, length) {
    var bytes, pos;
    return SlowBuffer._charsWritten = blitBuffer(base64ToBytes(string), this, offset, length);
  };
  
  SlowBuffer.prototype.base64Slice = function (start, end) {
    var bytes = Array.prototype.slice.apply(this, arguments)
    return require("base64-js").fromByteArray(bytes);
  }
  
  function decodeUtf8Char(str) {
    try {
      return decodeURIComponent(str);
    } catch (err) {
      return String.fromCharCode(0xFFFD); // UTF 8 invalid char
    }
  }
  
  SlowBuffer.prototype.utf8Slice = function () {
    var bytes = Array.prototype.slice.apply(this, arguments);
    var res = "";
    var tmp = "";
    var i = 0;
    while (i < bytes.length) {
      if (bytes[i] <= 0x7F) {
        res += decodeUtf8Char(tmp) + String.fromCharCode(bytes[i]);
        tmp = "";
      } else
        tmp += "%" + bytes[i].toString(16);
  
      i++;
    }
  
    return res + decodeUtf8Char(tmp);
  }
  
  SlowBuffer.prototype.asciiSlice = function () {
    var bytes = Array.prototype.slice.apply(this, arguments);
    var ret = "";
    for (var i = 0; i < bytes.length; i++)
      ret += String.fromCharCode(bytes[i]);
    return ret;
  }
  
  SlowBuffer.prototype.binarySlice = SlowBuffer.prototype.asciiSlice;
  
  SlowBuffer.prototype.inspect = function() {
    var out = [],
        len = this.length;
    for (var i = 0; i < len; i++) {
      out[i] = toHex(this[i]);
      if (i == exports.INSPECT_MAX_BYTES) {
        out[i + 1] = '...';
        break;
      }
    }
    return '<SlowBuffer ' + out.join(' ') + '>';
  };
  
  
  SlowBuffer.prototype.hexSlice = function(start, end) {
    var len = this.length;
  
    if (!start || start < 0) start = 0;
    if (!end || end < 0 || end > len) end = len;
  
    var out = '';
    for (var i = start; i < end; i++) {
      out += toHex(this[i]);
    }
    return out;
  };
  
  
  SlowBuffer.prototype.toString = function(encoding, start, end) {
    encoding = String(encoding || 'utf8').toLowerCase();
    start = +start || 0;
    if (typeof end == 'undefined') end = this.length;
  
    // Fastpath empty strings
    if (+end == start) {
      return '';
    }
  
    switch (encoding) {
      case 'hex':
        return this.hexSlice(start, end);
  
      case 'utf8':
      case 'utf-8':
        return this.utf8Slice(start, end);
  
      case 'ascii':
        return this.asciiSlice(start, end);
  
      case 'binary':
        return this.binarySlice(start, end);
  
      case 'base64':
        return this.base64Slice(start, end);
  
      case 'ucs2':
      case 'ucs-2':
        return this.ucs2Slice(start, end);
  
      default:
        throw new Error('Unknown encoding');
    }
  };
  
  
  SlowBuffer.prototype.hexWrite = function(string, offset, length) {
    offset = +offset || 0;
    var remaining = this.length - offset;
    if (!length) {
      length = remaining;
    } else {
      length = +length;
      if (length > remaining) {
        length = remaining;
      }
    }
  
    // must be an even number of digits
    var strLen = string.length;
    if (strLen % 2) {
      throw new Error('Invalid hex string');
    }
    if (length > strLen / 2) {
      length = strLen / 2;
    }
    for (var i = 0; i < length; i++) {
      var byte = parseInt(string.substr(i * 2, 2), 16);
      if (isNaN(byte)) throw new Error('Invalid hex string');
      this[offset + i] = byte;
    }
    SlowBuffer._charsWritten = i * 2;
    return i;
  };
  
  
  SlowBuffer.prototype.write = function(string, offset, length, encoding) {
    // Support both (string, offset, length, encoding)
    // and the legacy (string, encoding, offset, length)
    if (isFinite(offset)) {
      if (!isFinite(length)) {
        encoding = length;
        length = undefined;
      }
    } else {  // legacy
      var swap = encoding;
      encoding = offset;
      offset = length;
      length = swap;
    }
  
    offset = +offset || 0;
    var remaining = this.length - offset;
    if (!length) {
      length = remaining;
    } else {
      length = +length;
      if (length > remaining) {
        length = remaining;
      }
    }
    encoding = String(encoding || 'utf8').toLowerCase();
  
    switch (encoding) {
      case 'hex':
        return this.hexWrite(string, offset, length);
  
      case 'utf8':
      case 'utf-8':
        return this.utf8Write(string, offset, length);
  
      case 'ascii':
        return this.asciiWrite(string, offset, length);
  
      case 'binary':
        return this.binaryWrite(string, offset, length);
  
      case 'base64':
        return this.base64Write(string, offset, length);
  
      case 'ucs2':
      case 'ucs-2':
        return this.ucs2Write(string, offset, length);
  
      default:
        throw new Error('Unknown encoding');
    }
  };
  
  
  // slice(start, end)
  SlowBuffer.prototype.slice = function(start, end) {
    if (end === undefined) end = this.length;
  
    if (end > this.length) {
      throw new Error('oob');
    }
    if (start > end) {
      throw new Error('oob');
    }
  
    return new Buffer(this, end - start, +start);
  };
  
  SlowBuffer.prototype.copy = function(target, targetstart, sourcestart, sourceend) {
    var temp = [];
    for (var i=sourcestart; i<sourceend; i++) {
      assert.ok(typeof this[i] !== 'undefined', "copying undefined buffer bytes!");
      temp.push(this[i]);
    }
  
    for (var i=targetstart; i<targetstart+temp.length; i++) {
      target[i] = temp[i-targetstart];
    }
  };
  
  SlowBuffer.prototype.fill = function(value, start, end) {
    if (end > this.length) {
      throw new Error('oob');
    }
    if (start > end) {
      throw new Error('oob');
    }
  
    for (var i = start; i < end; i++) {
      this[i] = value;
    }
  }
  
  function coerce(length) {
    // Coerce length to a number (possibly NaN), round up
    // in case it's fractional (e.g. 123.456) then do a
    // double negate to coerce a NaN to 0. Easy, right?
    length = ~~Math.ceil(+length);
    return length < 0 ? 0 : length;
  }
  
  
  // Buffer
  
  function Buffer(subject, encoding, offset) {
    if (!(this instanceof Buffer)) {
      return new Buffer(subject, encoding, offset);
    }
  
    var type;
  
    // Are we slicing?
    if (typeof offset === 'number') {
      this.length = coerce(encoding);
      this.parent = subject;
      this.offset = offset;
    } else {
      // Find the length
      switch (type = typeof subject) {
        case 'number':
          this.length = coerce(subject);
          break;
  
        case 'string':
          this.length = Buffer.byteLength(subject, encoding);
          break;
  
        case 'object': // Assume object is an array
          this.length = coerce(subject.length);
          break;
  
        default:
          throw new Error('First argument needs to be a number, ' +
                          'array or string.');
      }
  
      if (this.length > Buffer.poolSize) {
        // Big buffer, just alloc one.
        this.parent = new SlowBuffer(this.length);
        this.offset = 0;
  
      } else {
        // Small buffer.
        if (!pool || pool.length - pool.used < this.length) allocPool();
        this.parent = pool;
        this.offset = pool.used;
        pool.used += this.length;
      }
  
      // Treat array-ish objects as a byte array.
      if (isArrayIsh(subject)) {
        for (var i = 0; i < this.length; i++) {
          if (subject instanceof Buffer) {
            this.parent[i + this.offset] = subject.readUInt8(i);
          }
          else {
            this.parent[i + this.offset] = subject[i];
          }
        }
      } else if (type == 'string') {
        // We are a string
        this.length = this.write(subject, 0, encoding);
      }
    }
  
  }
  
  function isArrayIsh(subject) {
    return Array.isArray(subject) || Buffer.isBuffer(subject) ||
           subject && typeof subject === 'object' &&
           typeof subject.length === 'number';
  }
  
  exports.SlowBuffer = SlowBuffer;
  exports.Buffer = Buffer;
  
  Buffer.poolSize = 8 * 1024;
  var pool;
  
  function allocPool() {
    pool = new SlowBuffer(Buffer.poolSize);
    pool.used = 0;
  }
  
  
  // Static methods
  Buffer.isBuffer = function isBuffer(b) {
    return b instanceof Buffer || b instanceof SlowBuffer;
  };
  
  Buffer.concat = function (list, totalLength) {
    if (!Array.isArray(list)) {
      throw new Error("Usage: Buffer.concat(list, [totalLength])\n \
        list should be an Array.");
    }
  
    if (list.length === 0) {
      return new Buffer(0);
    } else if (list.length === 1) {
      return list[0];
    }
  
    if (typeof totalLength !== 'number') {
      totalLength = 0;
      for (var i = 0; i < list.length; i++) {
        var buf = list[i];
        totalLength += buf.length;
      }
    }
  
    var buffer = new Buffer(totalLength);
    var pos = 0;
    for (var i = 0; i < list.length; i++) {
      var buf = list[i];
      buf.copy(buffer, pos);
      pos += buf.length;
    }
    return buffer;
  };
  
  // Inspect
  Buffer.prototype.inspect = function inspect() {
    var out = [],
        len = this.length;
  
    for (var i = 0; i < len; i++) {
      out[i] = toHex(this.parent[i + this.offset]);
      if (i == exports.INSPECT_MAX_BYTES) {
        out[i + 1] = '...';
        break;
      }
    }
  
    return '<Buffer ' + out.join(' ') + '>';
  };
  
  
  Buffer.prototype.get = function get(i) {
    if (i < 0 || i >= this.length) throw new Error('oob');
    return this.parent[this.offset + i];
  };
  
  
  Buffer.prototype.set = function set(i, v) {
    if (i < 0 || i >= this.length) throw new Error('oob');
    return this.parent[this.offset + i] = v;
  };
  
  
  // write(string, offset = 0, length = buffer.length-offset, encoding = 'utf8')
  Buffer.prototype.write = function(string, offset, length, encoding) {
    // Support both (string, offset, length, encoding)
    // and the legacy (string, encoding, offset, length)
    if (isFinite(offset)) {
      if (!isFinite(length)) {
        encoding = length;
        length = undefined;
      }
    } else {  // legacy
      var swap = encoding;
      encoding = offset;
      offset = length;
      length = swap;
    }
  
    offset = +offset || 0;
    var remaining = this.length - offset;
    if (!length) {
      length = remaining;
    } else {
      length = +length;
      if (length > remaining) {
        length = remaining;
      }
    }
    encoding = String(encoding || 'utf8').toLowerCase();
  
    var ret;
    switch (encoding) {
      case 'hex':
        ret = this.parent.hexWrite(string, this.offset + offset, length);
        break;
  
      case 'utf8':
      case 'utf-8':
        ret = this.parent.utf8Write(string, this.offset + offset, length);
        break;
  
      case 'ascii':
        ret = this.parent.asciiWrite(string, this.offset + offset, length);
        break;
  
      case 'binary':
        ret = this.parent.binaryWrite(string, this.offset + offset, length);
        break;
  
      case 'base64':
        // Warning: maxLength not taken into account in base64Write
        ret = this.parent.base64Write(string, this.offset + offset, length);
        break;
  
      case 'ucs2':
      case 'ucs-2':
        ret = this.parent.ucs2Write(string, this.offset + offset, length);
        break;
  
      default:
        throw new Error('Unknown encoding');
    }
  
    Buffer._charsWritten = SlowBuffer._charsWritten;
  
    return ret;
  };
  
  
  // toString(encoding, start=0, end=buffer.length)
  Buffer.prototype.toString = function(encoding, start, end) {
    encoding = String(encoding || 'utf8').toLowerCase();
  
    if (typeof start == 'undefined' || start < 0) {
      start = 0;
    } else if (start > this.length) {
      start = this.length;
    }
  
    if (typeof end == 'undefined' || end > this.length) {
      end = this.length;
    } else if (end < 0) {
      end = 0;
    }
  
    start = start + this.offset;
    end = end + this.offset;
  
    switch (encoding) {
      case 'hex':
        return this.parent.hexSlice(start, end);
  
      case 'utf8':
      case 'utf-8':
        return this.parent.utf8Slice(start, end);
  
      case 'ascii':
        return this.parent.asciiSlice(start, end);
  
      case 'binary':
        return this.parent.binarySlice(start, end);
  
      case 'base64':
        return this.parent.base64Slice(start, end);
  
      case 'ucs2':
      case 'ucs-2':
        return this.parent.ucs2Slice(start, end);
  
      default:
        throw new Error('Unknown encoding');
    }
  };
  
  
  // byteLength
  Buffer.byteLength = SlowBuffer.byteLength;
  
  
  // fill(value, start=0, end=buffer.length)
  Buffer.prototype.fill = function fill(value, start, end) {
    value || (value = 0);
    start || (start = 0);
    end || (end = this.length);
  
    if (typeof value === 'string') {
      value = value.charCodeAt(0);
    }
    if (!(typeof value === 'number') || isNaN(value)) {
      throw new Error('value is not a number');
    }
  
    if (end < start) throw new Error('end < start');
  
    // Fill 0 bytes; we're done
    if (end === start) return 0;
    if (this.length == 0) return 0;
  
    if (start < 0 || start >= this.length) {
      throw new Error('start out of bounds');
    }
  
    if (end < 0 || end > this.length) {
      throw new Error('end out of bounds');
    }
  
    return this.parent.fill(value,
                            start + this.offset,
                            end + this.offset);
  };
  
  
  // copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
  Buffer.prototype.copy = function(target, target_start, start, end) {
    var source = this;
    start || (start = 0);
    end || (end = this.length);
    target_start || (target_start = 0);
  
    if (end < start) throw new Error('sourceEnd < sourceStart');
  
    // Copy 0 bytes; we're done
    if (end === start) return 0;
    if (target.length == 0 || source.length == 0) return 0;
  
    if (target_start < 0 || target_start >= target.length) {
      throw new Error('targetStart out of bounds');
    }
  
    if (start < 0 || start >= source.length) {
      throw new Error('sourceStart out of bounds');
    }
  
    if (end < 0 || end > source.length) {
      throw new Error('sourceEnd out of bounds');
    }
  
    // Are we oob?
    if (end > this.length) {
      end = this.length;
    }
  
    if (target.length - target_start < end - start) {
      end = target.length - target_start + start;
    }
  
    return this.parent.copy(target.parent,
                            target_start + target.offset,
                            start + this.offset,
                            end + this.offset);
  };
  
  
  // slice(start, end)
  Buffer.prototype.slice = function(start, end) {
    if (end === undefined) end = this.length;
    if (end > this.length) throw new Error('oob');
    if (start > end) throw new Error('oob');
  
    return new Buffer(this.parent, end - start, +start + this.offset);
  };
  
  
  // Legacy methods for backwards compatibility.
  
  Buffer.prototype.utf8Slice = function(start, end) {
    return this.toString('utf8', start, end);
  };
  
  Buffer.prototype.binarySlice = function(start, end) {
    return this.toString('binary', start, end);
  };
  
  Buffer.prototype.asciiSlice = function(start, end) {
    return this.toString('ascii', start, end);
  };
  
  Buffer.prototype.utf8Write = function(string, offset) {
    return this.write(string, offset, 'utf8');
  };
  
  Buffer.prototype.binaryWrite = function(string, offset) {
    return this.write(string, offset, 'binary');
  };
  
  Buffer.prototype.asciiWrite = function(string, offset) {
    return this.write(string, offset, 'ascii');
  };
  
  Buffer.prototype.readUInt8 = function(offset, noAssert) {
    var buffer = this;
  
    if (!noAssert) {
      assert.ok(offset !== undefined && offset !== null,
          'missing offset');
  
      assert.ok(offset < buffer.length,
          'Trying to read beyond buffer length');
    }
  
    if (offset >= buffer.length) return;
  
    return buffer.parent[buffer.offset + offset];
  };
  
  function readUInt16(buffer, offset, isBigEndian, noAssert) {
    var val = 0;
  
  
    if (!noAssert) {
      assert.ok(typeof (isBigEndian) === 'boolean',
          'missing or invalid endian');
  
      assert.ok(offset !== undefined && offset !== null,
          'missing offset');
  
      assert.ok(offset + 1 < buffer.length,
          'Trying to read beyond buffer length');
    }
  
    if (offset >= buffer.length) return 0;
  
    if (isBigEndian) {
      val = buffer.parent[buffer.offset + offset] << 8;
      if (offset + 1 < buffer.length) {
        val |= buffer.parent[buffer.offset + offset + 1];
      }
    } else {
      val = buffer.parent[buffer.offset + offset];
      if (offset + 1 < buffer.length) {
        val |= buffer.parent[buffer.offset + offset + 1] << 8;
      }
    }
  
    return val;
  }
  
  Buffer.prototype.readUInt16LE = function(offset, noAssert) {
    return readUInt16(this, offset, false, noAssert);
  };
  
  Buffer.prototype.readUInt16BE = function(offset, noAssert) {
    return readUInt16(this, offset, true, noAssert);
  };
  
  function readUInt32(buffer, offset, isBigEndian, noAssert) {
    var val = 0;
  
    if (!noAssert) {
      assert.ok(typeof (isBigEndian) === 'boolean',
          'missing or invalid endian');
  
      assert.ok(offset !== undefined && offset !== null,
          'missing offset');
  
      assert.ok(offset + 3 < buffer.length,
          'Trying to read beyond buffer length');
    }
  
    if (offset >= buffer.length) return 0;
  
    if (isBigEndian) {
      if (offset + 1 < buffer.length)
        val = buffer.parent[buffer.offset + offset + 1] << 16;
      if (offset + 2 < buffer.length)
        val |= buffer.parent[buffer.offset + offset + 2] << 8;
      if (offset + 3 < buffer.length)
        val |= buffer.parent[buffer.offset + offset + 3];
      val = val + (buffer.parent[buffer.offset + offset] << 24 >>> 0);
    } else {
      if (offset + 2 < buffer.length)
        val = buffer.parent[buffer.offset + offset + 2] << 16;
      if (offset + 1 < buffer.length)
        val |= buffer.parent[buffer.offset + offset + 1] << 8;
      val |= buffer.parent[buffer.offset + offset];
      if (offset + 3 < buffer.length)
        val = val + (buffer.parent[buffer.offset + offset + 3] << 24 >>> 0);
    }
  
    return val;
  }
  
  Buffer.prototype.readUInt32LE = function(offset, noAssert) {
    return readUInt32(this, offset, false, noAssert);
  };
  
  Buffer.prototype.readUInt32BE = function(offset, noAssert) {
    return readUInt32(this, offset, true, noAssert);
  };
  
  
  /*
   * Signed integer types, yay team! A reminder on how two's complement actually
   * works. The first bit is the signed bit, i.e. tells us whether or not the
   * number should be positive or negative. If the two's complement value is
   * positive, then we're done, as it's equivalent to the unsigned representation.
   *
   * Now if the number is positive, you're pretty much done, you can just leverage
   * the unsigned translations and return those. Unfortunately, negative numbers
   * aren't quite that straightforward.
   *
   * At first glance, one might be inclined to use the traditional formula to
   * translate binary numbers between the positive and negative values in two's
   * complement. (Though it doesn't quite work for the most negative value)
   * Mainly:
   *  - invert all the bits
   *  - add one to the result
   *
   * Of course, this doesn't quite work in Javascript. Take for example the value
   * of -128. This could be represented in 16 bits (big-endian) as 0xff80. But of
   * course, Javascript will do the following:
   *
   * > ~0xff80
   * -65409
   *
   * Whoh there, Javascript, that's not quite right. But wait, according to
   * Javascript that's perfectly correct. When Javascript ends up seeing the
   * constant 0xff80, it has no notion that it is actually a signed number. It
   * assumes that we've input the unsigned value 0xff80. Thus, when it does the
   * binary negation, it casts it into a signed value, (positive 0xff80). Then
   * when you perform binary negation on that, it turns it into a negative number.
   *
   * Instead, we're going to have to use the following general formula, that works
   * in a rather Javascript friendly way. I'm glad we don't support this kind of
   * weird numbering scheme in the kernel.
   *
   * (BIT-MAX - (unsigned)val + 1) * -1
   *
   * The astute observer, may think that this doesn't make sense for 8-bit numbers
   * (really it isn't necessary for them). However, when you get 16-bit numbers,
   * you do. Let's go back to our prior example and see how this will look:
   *
   * (0xffff - 0xff80 + 1) * -1
   * (0x007f + 1) * -1
   * (0x0080) * -1
   */
  Buffer.prototype.readInt8 = function(offset, noAssert) {
    var buffer = this;
    var neg;
  
    if (!noAssert) {
      assert.ok(offset !== undefined && offset !== null,
          'missing offset');
  
      assert.ok(offset < buffer.length,
          'Trying to read beyond buffer length');
    }
  
    if (offset >= buffer.length) return;
  
    neg = buffer.parent[buffer.offset + offset] & 0x80;
    if (!neg) {
      return (buffer.parent[buffer.offset + offset]);
    }
  
    return ((0xff - buffer.parent[buffer.offset + offset] + 1) * -1);
  };
  
  function readInt16(buffer, offset, isBigEndian, noAssert) {
    var neg, val;
  
    if (!noAssert) {
      assert.ok(typeof (isBigEndian) === 'boolean',
          'missing or invalid endian');
  
      assert.ok(offset !== undefined && offset !== null,
          'missing offset');
  
      assert.ok(offset + 1 < buffer.length,
          'Trying to read beyond buffer length');
    }
  
    val = readUInt16(buffer, offset, isBigEndian, noAssert);
    neg = val & 0x8000;
    if (!neg) {
      return val;
    }
  
    return (0xffff - val + 1) * -1;
  }
  
  Buffer.prototype.readInt16LE = function(offset, noAssert) {
    return readInt16(this, offset, false, noAssert);
  };
  
  Buffer.prototype.readInt16BE = function(offset, noAssert) {
    return readInt16(this, offset, true, noAssert);
  };
  
  function readInt32(buffer, offset, isBigEndian, noAssert) {
    var neg, val;
  
    if (!noAssert) {
      assert.ok(typeof (isBigEndian) === 'boolean',
          'missing or invalid endian');
  
      assert.ok(offset !== undefined && offset !== null,
          'missing offset');
  
      assert.ok(offset + 3 < buffer.length,
          'Trying to read beyond buffer length');
    }
  
    val = readUInt32(buffer, offset, isBigEndian, noAssert);
    neg = val & 0x80000000;
    if (!neg) {
      return (val);
    }
  
    return (0xffffffff - val + 1) * -1;
  }
  
  Buffer.prototype.readInt32LE = function(offset, noAssert) {
    return readInt32(this, offset, false, noAssert);
  };
  
  Buffer.prototype.readInt32BE = function(offset, noAssert) {
    return readInt32(this, offset, true, noAssert);
  };
  
  function readFloat(buffer, offset, isBigEndian, noAssert) {
    if (!noAssert) {
      assert.ok(typeof (isBigEndian) === 'boolean',
          'missing or invalid endian');
  
      assert.ok(offset + 3 < buffer.length,
          'Trying to read beyond buffer length');
    }
  
    return require('./buffer_ieee754').readIEEE754(buffer, offset, isBigEndian,
        23, 4);
  }
  
  Buffer.prototype.readFloatLE = function(offset, noAssert) {
    return readFloat(this, offset, false, noAssert);
  };
  
  Buffer.prototype.readFloatBE = function(offset, noAssert) {
    return readFloat(this, offset, true, noAssert);
  };
  
  function readDouble(buffer, offset, isBigEndian, noAssert) {
    if (!noAssert) {
      assert.ok(typeof (isBigEndian) === 'boolean',
          'missing or invalid endian');
  
      assert.ok(offset + 7 < buffer.length,
          'Trying to read beyond buffer length');
    }
  
    return require('./buffer_ieee754').readIEEE754(buffer, offset, isBigEndian,
        52, 8);
  }
  
  Buffer.prototype.readDoubleLE = function(offset, noAssert) {
    return readDouble(this, offset, false, noAssert);
  };
  
  Buffer.prototype.readDoubleBE = function(offset, noAssert) {
    return readDouble(this, offset, true, noAssert);
  };
  
  
  /*
   * We have to make sure that the value is a valid integer. This means that it is
   * non-negative. It has no fractional component and that it does not exceed the
   * maximum allowed value.
   *
   *      value           The number to check for validity
   *
   *      max             The maximum value
   */
  function verifuint(value, max) {
    assert.ok(typeof (value) == 'number',
        'cannot write a non-number as a number');
  
    assert.ok(value >= 0,
        'specified a negative value for writing an unsigned value');
  
    assert.ok(value <= max, 'value is larger than maximum value for type');
  
    assert.ok(Math.floor(value) === value, 'value has a fractional component');
  }
  
  Buffer.prototype.writeUInt8 = function(value, offset, noAssert) {
    var buffer = this;
  
    if (!noAssert) {
      assert.ok(value !== undefined && value !== null,
          'missing value');
  
      assert.ok(offset !== undefined && offset !== null,
          'missing offset');
  
      assert.ok(offset < buffer.length,
          'trying to write beyond buffer length');
  
      verifuint(value, 0xff);
    }
  
    if (offset < buffer.length) {
      buffer.parent[buffer.offset + offset] = value;
    }
  };
  
  function writeUInt16(buffer, value, offset, isBigEndian, noAssert) {
    if (!noAssert) {
      assert.ok(value !== undefined && value !== null,
          'missing value');
  
      assert.ok(typeof (isBigEndian) === 'boolean',
          'missing or invalid endian');
  
      assert.ok(offset !== undefined && offset !== null,
          'missing offset');
  
      assert.ok(offset + 1 < buffer.length,
          'trying to write beyond buffer length');
  
      verifuint(value, 0xffff);
    }
  
    for (var i = 0; i < Math.min(buffer.length - offset, 2); i++) {
      buffer.parent[buffer.offset + offset + i] =
          (value & (0xff << (8 * (isBigEndian ? 1 - i : i)))) >>>
              (isBigEndian ? 1 - i : i) * 8;
    }
  
  }
  
  Buffer.prototype.writeUInt16LE = function(value, offset, noAssert) {
    writeUInt16(this, value, offset, false, noAssert);
  };
  
  Buffer.prototype.writeUInt16BE = function(value, offset, noAssert) {
    writeUInt16(this, value, offset, true, noAssert);
  };
  
  function writeUInt32(buffer, value, offset, isBigEndian, noAssert) {
    if (!noAssert) {
      assert.ok(value !== undefined && value !== null,
          'missing value');
  
      assert.ok(typeof (isBigEndian) === 'boolean',
          'missing or invalid endian');
  
      assert.ok(offset !== undefined && offset !== null,
          'missing offset');
  
      assert.ok(offset + 3 < buffer.length,
          'trying to write beyond buffer length');
  
      verifuint(value, 0xffffffff);
    }
  
    for (var i = 0; i < Math.min(buffer.length - offset, 4); i++) {
      buffer.parent[buffer.offset + offset + i] =
          (value >>> (isBigEndian ? 3 - i : i) * 8) & 0xff;
    }
  }
  
  Buffer.prototype.writeUInt32LE = function(value, offset, noAssert) {
    writeUInt32(this, value, offset, false, noAssert);
  };
  
  Buffer.prototype.writeUInt32BE = function(value, offset, noAssert) {
    writeUInt32(this, value, offset, true, noAssert);
  };
  
  
  /*
   * We now move onto our friends in the signed number category. Unlike unsigned
   * numbers, we're going to have to worry a bit more about how we put values into
   * arrays. Since we are only worrying about signed 32-bit values, we're in
   * slightly better shape. Unfortunately, we really can't do our favorite binary
   * & in this system. It really seems to do the wrong thing. For example:
   *
   * > -32 & 0xff
   * 224
   *
   * What's happening above is really: 0xe0 & 0xff = 0xe0. However, the results of
   * this aren't treated as a signed number. Ultimately a bad thing.
   *
   * What we're going to want to do is basically create the unsigned equivalent of
   * our representation and pass that off to the wuint* functions. To do that
   * we're going to do the following:
   *
   *  - if the value is positive
   *      we can pass it directly off to the equivalent wuint
   *  - if the value is negative
   *      we do the following computation:
   *         mb + val + 1, where
   *         mb   is the maximum unsigned value in that byte size
   *         val  is the Javascript negative integer
   *
   *
   * As a concrete value, take -128. In signed 16 bits this would be 0xff80. If
   * you do out the computations:
   *
   * 0xffff - 128 + 1
   * 0xffff - 127
   * 0xff80
   *
   * You can then encode this value as the signed version. This is really rather
   * hacky, but it should work and get the job done which is our goal here.
   */
  
  /*
   * A series of checks to make sure we actually have a signed 32-bit number
   */
  function verifsint(value, max, min) {
    assert.ok(typeof (value) == 'number',
        'cannot write a non-number as a number');
  
    assert.ok(value <= max, 'value larger than maximum allowed value');
  
    assert.ok(value >= min, 'value smaller than minimum allowed value');
  
    assert.ok(Math.floor(value) === value, 'value has a fractional component');
  }
  
  function verifIEEE754(value, max, min) {
    assert.ok(typeof (value) == 'number',
        'cannot write a non-number as a number');
  
    assert.ok(value <= max, 'value larger than maximum allowed value');
  
    assert.ok(value >= min, 'value smaller than minimum allowed value');
  }
  
  Buffer.prototype.writeInt8 = function(value, offset, noAssert) {
    var buffer = this;
  
    if (!noAssert) {
      assert.ok(value !== undefined && value !== null,
          'missing value');
  
      assert.ok(offset !== undefined && offset !== null,
          'missing offset');
  
      assert.ok(offset < buffer.length,
          'Trying to write beyond buffer length');
  
      verifsint(value, 0x7f, -0x80);
    }
  
    if (value >= 0) {
      buffer.writeUInt8(value, offset, noAssert);
    } else {
      buffer.writeUInt8(0xff + value + 1, offset, noAssert);
    }
  };
  
  function writeInt16(buffer, value, offset, isBigEndian, noAssert) {
    if (!noAssert) {
      assert.ok(value !== undefined && value !== null,
          'missing value');
  
      assert.ok(typeof (isBigEndian) === 'boolean',
          'missing or invalid endian');
  
      assert.ok(offset !== undefined && offset !== null,
          'missing offset');
  
      assert.ok(offset + 1 < buffer.length,
          'Trying to write beyond buffer length');
  
      verifsint(value, 0x7fff, -0x8000);
    }
  
    if (value >= 0) {
      writeUInt16(buffer, value, offset, isBigEndian, noAssert);
    } else {
      writeUInt16(buffer, 0xffff + value + 1, offset, isBigEndian, noAssert);
    }
  }
  
  Buffer.prototype.writeInt16LE = function(value, offset, noAssert) {
    writeInt16(this, value, offset, false, noAssert);
  };
  
  Buffer.prototype.writeInt16BE = function(value, offset, noAssert) {
    writeInt16(this, value, offset, true, noAssert);
  };
  
  function writeInt32(buffer, value, offset, isBigEndian, noAssert) {
    if (!noAssert) {
      assert.ok(value !== undefined && value !== null,
          'missing value');
  
      assert.ok(typeof (isBigEndian) === 'boolean',
          'missing or invalid endian');
  
      assert.ok(offset !== undefined && offset !== null,
          'missing offset');
  
      assert.ok(offset + 3 < buffer.length,
          'Trying to write beyond buffer length');
  
      verifsint(value, 0x7fffffff, -0x80000000);
    }
  
    if (value >= 0) {
      writeUInt32(buffer, value, offset, isBigEndian, noAssert);
    } else {
      writeUInt32(buffer, 0xffffffff + value + 1, offset, isBigEndian, noAssert);
    }
  }
  
  Buffer.prototype.writeInt32LE = function(value, offset, noAssert) {
    writeInt32(this, value, offset, false, noAssert);
  };
  
  Buffer.prototype.writeInt32BE = function(value, offset, noAssert) {
    writeInt32(this, value, offset, true, noAssert);
  };
  
  function writeFloat(buffer, value, offset, isBigEndian, noAssert) {
    if (!noAssert) {
      assert.ok(value !== undefined && value !== null,
          'missing value');
  
      assert.ok(typeof (isBigEndian) === 'boolean',
          'missing or invalid endian');
  
      assert.ok(offset !== undefined && offset !== null,
          'missing offset');
  
      assert.ok(offset + 3 < buffer.length,
          'Trying to write beyond buffer length');
  
      verifIEEE754(value, 3.4028234663852886e+38, -3.4028234663852886e+38);
    }
  
    require('./buffer_ieee754').writeIEEE754(buffer, value, offset, isBigEndian,
        23, 4);
  }
  
  Buffer.prototype.writeFloatLE = function(value, offset, noAssert) {
    writeFloat(this, value, offset, false, noAssert);
  };
  
  Buffer.prototype.writeFloatBE = function(value, offset, noAssert) {
    writeFloat(this, value, offset, true, noAssert);
  };
  
  function writeDouble(buffer, value, offset, isBigEndian, noAssert) {
    if (!noAssert) {
      assert.ok(value !== undefined && value !== null,
          'missing value');
  
      assert.ok(typeof (isBigEndian) === 'boolean',
          'missing or invalid endian');
  
      assert.ok(offset !== undefined && offset !== null,
          'missing offset');
  
      assert.ok(offset + 7 < buffer.length,
          'Trying to write beyond buffer length');
  
      verifIEEE754(value, 1.7976931348623157E+308, -1.7976931348623157E+308);
    }
  
    require('./buffer_ieee754').writeIEEE754(buffer, value, offset, isBigEndian,
        52, 8);
  }
  
  Buffer.prototype.writeDoubleLE = function(value, offset, noAssert) {
    writeDouble(this, value, offset, false, noAssert);
  };
  
  Buffer.prototype.writeDoubleBE = function(value, offset, noAssert) {
    writeDouble(this, value, offset, true, noAssert);
  };
  
  SlowBuffer.prototype.readUInt8 = Buffer.prototype.readUInt8;
  SlowBuffer.prototype.readUInt16LE = Buffer.prototype.readUInt16LE;
  SlowBuffer.prototype.readUInt16BE = Buffer.prototype.readUInt16BE;
  SlowBuffer.prototype.readUInt32LE = Buffer.prototype.readUInt32LE;
  SlowBuffer.prototype.readUInt32BE = Buffer.prototype.readUInt32BE;
  SlowBuffer.prototype.readInt8 = Buffer.prototype.readInt8;
  SlowBuffer.prototype.readInt16LE = Buffer.prototype.readInt16LE;
  SlowBuffer.prototype.readInt16BE = Buffer.prototype.readInt16BE;
  SlowBuffer.prototype.readInt32LE = Buffer.prototype.readInt32LE;
  SlowBuffer.prototype.readInt32BE = Buffer.prototype.readInt32BE;
  SlowBuffer.prototype.readFloatLE = Buffer.prototype.readFloatLE;
  SlowBuffer.prototype.readFloatBE = Buffer.prototype.readFloatBE;
  SlowBuffer.prototype.readDoubleLE = Buffer.prototype.readDoubleLE;
  SlowBuffer.prototype.readDoubleBE = Buffer.prototype.readDoubleBE;
  SlowBuffer.prototype.writeUInt8 = Buffer.prototype.writeUInt8;
  SlowBuffer.prototype.writeUInt16LE = Buffer.prototype.writeUInt16LE;
  SlowBuffer.prototype.writeUInt16BE = Buffer.prototype.writeUInt16BE;
  SlowBuffer.prototype.writeUInt32LE = Buffer.prototype.writeUInt32LE;
  SlowBuffer.prototype.writeUInt32BE = Buffer.prototype.writeUInt32BE;
  SlowBuffer.prototype.writeInt8 = Buffer.prototype.writeInt8;
  SlowBuffer.prototype.writeInt16LE = Buffer.prototype.writeInt16LE;
  SlowBuffer.prototype.writeInt16BE = Buffer.prototype.writeInt16BE;
  SlowBuffer.prototype.writeInt32LE = Buffer.prototype.writeInt32LE;
  SlowBuffer.prototype.writeInt32BE = Buffer.prototype.writeInt32BE;
  SlowBuffer.prototype.writeFloatLE = Buffer.prototype.writeFloatLE;
  SlowBuffer.prototype.writeFloatBE = Buffer.prototype.writeFloatBE;
  SlowBuffer.prototype.writeDoubleLE = Buffer.prototype.writeDoubleLE;
  SlowBuffer.prototype.writeDoubleBE = Buffer.prototype.writeDoubleBE;
  
  })()
  },{"assert":2,"./buffer_ieee754":1,"base64-js":5}],3:[function(require,module,exports){
  var events = require('events');
  
  exports.isArray = isArray;
  exports.isDate = function(obj){return Object.prototype.toString.call(obj) === '[object Date]'};
  exports.isRegExp = function(obj){return Object.prototype.toString.call(obj) === '[object RegExp]'};
  
  
  exports.print = function () {};
  exports.puts = function () {};
  exports.debug = function() {};
  
  exports.inspect = function(obj, showHidden, depth, colors) {
    var seen = [];
  
    var stylize = function(str, styleType) {
      // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
      var styles =
          { 'bold' : [1, 22],
            'italic' : [3, 23],
            'underline' : [4, 24],
            'inverse' : [7, 27],
            'white' : [37, 39],
            'grey' : [90, 39],
            'black' : [30, 39],
            'blue' : [34, 39],
            'cyan' : [36, 39],
            'green' : [32, 39],
            'magenta' : [35, 39],
            'red' : [31, 39],
            'yellow' : [33, 39] };
  
      var style =
          { 'special': 'cyan',
            'number': 'blue',
            'boolean': 'yellow',
            'undefined': 'grey',
            'null': 'bold',
            'string': 'green',
            'date': 'magenta',
            // "name": intentionally not styling
            'regexp': 'red' }[styleType];
  
      if (style) {
        return '\033[' + styles[style][0] + 'm' + str +
               '\033[' + styles[style][1] + 'm';
      } else {
        return str;
      }
    };
    if (! colors) {
      stylize = function(str, styleType) { return str; };
    }
  
    function format(value, recurseTimes) {
      // Provide a hook for user-specified inspect functions.
      // Check that value is an object with an inspect function on it
      if (value && typeof value.inspect === 'function' &&
          // Filter out the util module, it's inspect function is special
          value !== exports &&
          // Also filter out any prototype objects using the circular check.
          !(value.constructor && value.constructor.prototype === value)) {
        return value.inspect(recurseTimes);
      }
  
      // Primitive types cannot have properties
      switch (typeof value) {
        case 'undefined':
          return stylize('undefined', 'undefined');
  
        case 'string':
          var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
                                                   .replace(/'/g, "\\'")
                                                   .replace(/\\"/g, '"') + '\'';
          return stylize(simple, 'string');
  
        case 'number':
          return stylize('' + value, 'number');
  
        case 'boolean':
          return stylize('' + value, 'boolean');
      }
      // For some reason typeof null is "object", so special case here.
      if (value === null) {
        return stylize('null', 'null');
      }
  
      // Look up the keys of the object.
      var visible_keys = Object_keys(value);
      var keys = showHidden ? Object_getOwnPropertyNames(value) : visible_keys;
  
      // Functions without properties can be shortcutted.
      if (typeof value === 'function' && keys.length === 0) {
        if (isRegExp(value)) {
          return stylize('' + value, 'regexp');
        } else {
          var name = value.name ? ': ' + value.name : '';
          return stylize('[Function' + name + ']', 'special');
        }
      }
  
      // Dates without properties can be shortcutted
      if (isDate(value) && keys.length === 0) {
        return stylize(value.toUTCString(), 'date');
      }
  
      var base, type, braces;
      // Determine the object type
      if (isArray(value)) {
        type = 'Array';
        braces = ['[', ']'];
      } else {
        type = 'Object';
        braces = ['{', '}'];
      }
  
      // Make functions say that they are functions
      if (typeof value === 'function') {
        var n = value.name ? ': ' + value.name : '';
        base = (isRegExp(value)) ? ' ' + value : ' [Function' + n + ']';
      } else {
        base = '';
      }
  
      // Make dates with properties first say the date
      if (isDate(value)) {
        base = ' ' + value.toUTCString();
      }
  
      if (keys.length === 0) {
        return braces[0] + base + braces[1];
      }
  
      if (recurseTimes < 0) {
        if (isRegExp(value)) {
          return stylize('' + value, 'regexp');
        } else {
          return stylize('[Object]', 'special');
        }
      }
  
      seen.push(value);
  
      var output = keys.map(function(key) {
        var name, str;
        if (value.__lookupGetter__) {
          if (value.__lookupGetter__(key)) {
            if (value.__lookupSetter__(key)) {
              str = stylize('[Getter/Setter]', 'special');
            } else {
              str = stylize('[Getter]', 'special');
            }
          } else {
            if (value.__lookupSetter__(key)) {
              str = stylize('[Setter]', 'special');
            }
          }
        }
        if (visible_keys.indexOf(key) < 0) {
          name = '[' + key + ']';
        }
        if (!str) {
          if (seen.indexOf(value[key]) < 0) {
            if (recurseTimes === null) {
              str = format(value[key]);
            } else {
              str = format(value[key], recurseTimes - 1);
            }
            if (str.indexOf('\n') > -1) {
              if (isArray(value)) {
                str = str.split('\n').map(function(line) {
                  return '  ' + line;
                }).join('\n').substr(2);
              } else {
                str = '\n' + str.split('\n').map(function(line) {
                  return '   ' + line;
                }).join('\n');
              }
            }
          } else {
            str = stylize('[Circular]', 'special');
          }
        }
        if (typeof name === 'undefined') {
          if (type === 'Array' && key.match(/^\d+$/)) {
            return str;
          }
          name = JSON.stringify('' + key);
          if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
            name = name.substr(1, name.length - 2);
            name = stylize(name, 'name');
          } else {
            name = name.replace(/'/g, "\\'")
                       .replace(/\\"/g, '"')
                       .replace(/(^"|"$)/g, "'");
            name = stylize(name, 'string');
          }
        }
  
        return name + ': ' + str;
      });
  
      seen.pop();
  
      var numLinesEst = 0;
      var length = output.reduce(function(prev, cur) {
        numLinesEst++;
        if (cur.indexOf('\n') >= 0) numLinesEst++;
        return prev + cur.length + 1;
      }, 0);
  
      if (length > 50) {
        output = braces[0] +
                 (base === '' ? '' : base + '\n ') +
                 ' ' +
                 output.join(',\n  ') +
                 ' ' +
                 braces[1];
  
      } else {
        output = braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
      }
  
      return output;
    }
    return format(obj, (typeof depth === 'undefined' ? 2 : depth));
  };
  
  
  function isArray(ar) {
    return ar instanceof Array ||
           Array.isArray(ar) ||
           (ar && ar !== Object.prototype && isArray(ar.__proto__));
  }
  
  
  function isRegExp(re) {
    return re instanceof RegExp ||
      (typeof re === 'object' && Object.prototype.toString.call(re) === '[object RegExp]');
  }
  
  
  function isDate(d) {
    if (d instanceof Date) return true;
    if (typeof d !== 'object') return false;
    var properties = Date.prototype && Object_getOwnPropertyNames(Date.prototype);
    var proto = d.__proto__ && Object_getOwnPropertyNames(d.__proto__);
    return JSON.stringify(proto) === JSON.stringify(properties);
  }
  
  function pad(n) {
    return n < 10 ? '0' + n.toString(10) : n.toString(10);
  }
  
  var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
                'Oct', 'Nov', 'Dec'];
  
  // 26 Feb 16:19:34
  function timestamp() {
    var d = new Date();
    var time = [pad(d.getHours()),
                pad(d.getMinutes()),
                pad(d.getSeconds())].join(':');
    return [d.getDate(), months[d.getMonth()], time].join(' ');
  }
  
  exports.log = function (msg) {};
  
  exports.pump = null;
  
  var Object_keys = Object.keys || function (obj) {
      var res = [];
      for (var key in obj) res.push(key);
      return res;
  };
  
  var Object_getOwnPropertyNames = Object.getOwnPropertyNames || function (obj) {
      var res = [];
      for (var key in obj) {
          if (Object.hasOwnProperty.call(obj, key)) res.push(key);
      }
      return res;
  };
  
  var Object_create = Object.create || function (prototype, properties) {
      // from es5-shim
      var object;
      if (prototype === null) {
          object = { '__proto__' : null };
      }
      else {
          if (typeof prototype !== 'object') {
              throw new TypeError(
                  'typeof prototype[' + (typeof prototype) + '] != \'object\''
              );
          }
          var Type = function () {};
          Type.prototype = prototype;
          object = new Type();
          object.__proto__ = prototype;
      }
      if (typeof properties !== 'undefined' && Object.defineProperties) {
          Object.defineProperties(object, properties);
      }
      return object;
  };
  
  exports.inherits = function(ctor, superCtor) {
    ctor.super_ = superCtor;
    ctor.prototype = Object_create(superCtor.prototype, {
      constructor: {
        value: ctor,
        enumerable: false,
        writable: true,
        configurable: true
      }
    });
  };
  
  var formatRegExp = /%[sdj%]/g;
  exports.format = function(f) {
    if (typeof f !== 'string') {
      var objects = [];
      for (var i = 0; i < arguments.length; i++) {
        objects.push(exports.inspect(arguments[i]));
      }
      return objects.join(' ');
    }
  
    var i = 1;
    var args = arguments;
    var len = args.length;
    var str = String(f).replace(formatRegExp, function(x) {
      if (x === '%%') return '%';
      if (i >= len) return x;
      switch (x) {
        case '%s': return String(args[i++]);
        case '%d': return Number(args[i++]);
        case '%j': return JSON.stringify(args[i++]);
        default:
          return x;
      }
    });
    for(var x = args[i]; i < len; x = args[++i]){
      if (x === null || typeof x !== 'object') {
        str += ' ' + x;
      } else {
        str += ' ' + exports.inspect(x);
      }
    }
    return str;
  };
  
  },{"events":6}],5:[function(require,module,exports){
  (function (exports) {
  	'use strict';
  
  	var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
  
  	function b64ToByteArray(b64) {
  		var i, j, l, tmp, placeHolders, arr;
  	
  		if (b64.length % 4 > 0) {
  			throw 'Invalid string. Length must be a multiple of 4';
  		}
  
  		// the number of equal signs (place holders)
  		// if there are two placeholders, than the two characters before it
  		// represent one byte
  		// if there is only one, then the three characters before it represent 2 bytes
  		// this is just a cheap hack to not do indexOf twice
  		placeHolders = b64.indexOf('=');
  		placeHolders = placeHolders > 0 ? b64.length - placeHolders : 0;
  
  		// base64 is 4/3 + up to two characters of the original data
  		arr = [];//new Uint8Array(b64.length * 3 / 4 - placeHolders);
  
  		// if there are placeholders, only get up to the last complete 4 chars
  		l = placeHolders > 0 ? b64.length - 4 : b64.length;
  
  		for (i = 0, j = 0; i < l; i += 4, j += 3) {
  			tmp = (lookup.indexOf(b64[i]) << 18) | (lookup.indexOf(b64[i + 1]) << 12) | (lookup.indexOf(b64[i + 2]) << 6) | lookup.indexOf(b64[i + 3]);
  			arr.push((tmp & 0xFF0000) >> 16);
  			arr.push((tmp & 0xFF00) >> 8);
  			arr.push(tmp & 0xFF);
  		}
  
  		if (placeHolders === 2) {
  			tmp = (lookup.indexOf(b64[i]) << 2) | (lookup.indexOf(b64[i + 1]) >> 4);
  			arr.push(tmp & 0xFF);
  		} else if (placeHolders === 1) {
  			tmp = (lookup.indexOf(b64[i]) << 10) | (lookup.indexOf(b64[i + 1]) << 4) | (lookup.indexOf(b64[i + 2]) >> 2);
  			arr.push((tmp >> 8) & 0xFF);
  			arr.push(tmp & 0xFF);
  		}
  
  		return arr;
  	}
  
  	function uint8ToBase64(uint8) {
  		var i,
  			extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes
  			output = "",
  			temp, length;
  
  		function tripletToBase64 (num) {
  			return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F];
  		};
  
  		// go through the array every three bytes, we'll deal with trailing stuff later
  		for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {
  			temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]);
  			output += tripletToBase64(temp);
  		}
  
  		// pad the end with zeros, but make sure to not forget the extra bytes
  		switch (extraBytes) {
  			case 1:
  				temp = uint8[uint8.length - 1];
  				output += lookup[temp >> 2];
  				output += lookup[(temp << 4) & 0x3F];
  				output += '==';
  				break;
  			case 2:
  				temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1]);
  				output += lookup[temp >> 10];
  				output += lookup[(temp >> 4) & 0x3F];
  				output += lookup[(temp << 2) & 0x3F];
  				output += '=';
  				break;
  		}
  
  		return output;
  	}
  
  	module.exports.toByteArray = b64ToByteArray;
  	module.exports.fromByteArray = uint8ToBase64;
  }());
  
  },{}],7:[function(require,module,exports){
  exports.readIEEE754 = function(buffer, offset, isBE, mLen, nBytes) {
    var e, m,
        eLen = nBytes * 8 - mLen - 1,
        eMax = (1 << eLen) - 1,
        eBias = eMax >> 1,
        nBits = -7,
        i = isBE ? 0 : (nBytes - 1),
        d = isBE ? 1 : -1,
        s = buffer[offset + i];
  
    i += d;
  
    e = s & ((1 << (-nBits)) - 1);
    s >>= (-nBits);
    nBits += eLen;
    for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8);
  
    m = e & ((1 << (-nBits)) - 1);
    e >>= (-nBits);
    nBits += mLen;
    for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8);
  
    if (e === 0) {
      e = 1 - eBias;
    } else if (e === eMax) {
      return m ? NaN : ((s ? -1 : 1) * Infinity);
    } else {
      m = m + Math.pow(2, mLen);
      e = e - eBias;
    }
    return (s ? -1 : 1) * m * Math.pow(2, e - mLen);
  };
  
  exports.writeIEEE754 = function(buffer, value, offset, isBE, mLen, nBytes) {
    var e, m, c,
        eLen = nBytes * 8 - mLen - 1,
        eMax = (1 << eLen) - 1,
        eBias = eMax >> 1,
        rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0),
        i = isBE ? (nBytes - 1) : 0,
        d = isBE ? -1 : 1,
        s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0;
  
    value = Math.abs(value);
  
    if (isNaN(value) || value === Infinity) {
      m = isNaN(value) ? 1 : 0;
      e = eMax;
    } else {
      e = Math.floor(Math.log(value) / Math.LN2);
      if (value * (c = Math.pow(2, -e)) < 1) {
        e--;
        c *= 2;
      }
      if (e + eBias >= 1) {
        value += rt / c;
      } else {
        value += rt * Math.pow(2, 1 - eBias);
      }
      if (value * c >= 2) {
        e++;
        c /= 2;
      }
  
      if (e + eBias >= eMax) {
        m = 0;
        e = eMax;
      } else if (e + eBias >= 1) {
        m = (value * c - 1) * Math.pow(2, mLen);
        e = e + eBias;
      } else {
        m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
        e = 0;
      }
    }
  
    for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8);
  
    e = (e << mLen) | m;
    eLen += mLen;
    for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8);
  
    buffer[offset + i - d] |= s * 128;
  };
  
  },{}],8:[function(require,module,exports){
  // shim for using process in browser
  
  var process = module.exports = {};
  
  process.nextTick = (function () {
      var canSetImmediate = typeof window !== 'undefined'
      && window.setImmediate;
      var canPost = typeof window !== 'undefined'
      && window.postMessage && window.addEventListener
      ;
  
      if (canSetImmediate) {
          return function (f) { return window.setImmediate(f) };
      }
  
      if (canPost) {
          var queue = [];
          window.addEventListener('message', function (ev) {
              if (ev.source === window && ev.data === 'process-tick') {
                  ev.stopPropagation();
                  if (queue.length > 0) {
                      var fn = queue.shift();
                      fn();
                  }
              }
          }, true);
  
          return function nextTick(fn) {
              queue.push(fn);
              window.postMessage('process-tick', '*');
          };
      }
  
      return function nextTick(fn) {
          setTimeout(fn, 0);
      };
  })();
  
  process.title = 'browser';
  process.browser = true;
  process.env = {};
  process.argv = [];
  
  process.binding = function (name) {
      throw new Error('process.binding is not supported');
  }
  
  // TODO(shtylman)
  process.cwd = function () { return '/' };
  process.chdir = function (dir) {
      throw new Error('process.chdir is not supported');
  };
  
  },{}],6:[function(require,module,exports){
  (function(process){if (!process.EventEmitter) process.EventEmitter = function () {};
  
  var EventEmitter = exports.EventEmitter = process.EventEmitter;
  var isArray = typeof Array.isArray === 'function'
      ? Array.isArray
      : function (xs) {
          return Object.prototype.toString.call(xs) === '[object Array]'
      }
  ;
  function indexOf (xs, x) {
      if (xs.indexOf) return xs.indexOf(x);
      for (var i = 0; i < xs.length; i++) {
          if (x === xs[i]) return i;
      }
      return -1;
  }
  
  // By default EventEmitters will print a warning if more than
  // 10 listeners are added to it. This is a useful default which
  // helps finding memory leaks.
  //
  // Obviously not all Emitters should be limited to 10. This function allows
  // that to be increased. Set to zero for unlimited.
  var defaultMaxListeners = 10;
  EventEmitter.prototype.setMaxListeners = function(n) {
    if (!this._events) this._events = {};
    this._events.maxListeners = n;
  };
  
  
  EventEmitter.prototype.emit = function(type) {
    // If there is no 'error' event listener then throw.
    if (type === 'error') {
      if (!this._events || !this._events.error ||
          (isArray(this._events.error) && !this._events.error.length))
      {
        if (arguments[1] instanceof Error) {
          throw arguments[1]; // Unhandled 'error' event
        } else {
          throw new Error("Uncaught, unspecified 'error' event.");
        }
        return false;
      }
    }
  
    if (!this._events) return false;
    var handler = this._events[type];
    if (!handler) return false;
  
    if (typeof handler == 'function') {
      switch (arguments.length) {
        // fast cases
        case 1:
          handler.call(this);
          break;
        case 2:
          handler.call(this, arguments[1]);
          break;
        case 3:
          handler.call(this, arguments[1], arguments[2]);
          break;
        // slower
        default:
          var args = Array.prototype.slice.call(arguments, 1);
          handler.apply(this, args);
      }
      return true;
  
    } else if (isArray(handler)) {
      var args = Array.prototype.slice.call(arguments, 1);
  
      var listeners = handler.slice();
      for (var i = 0, l = listeners.length; i < l; i++) {
        listeners[i].apply(this, args);
      }
      return true;
  
    } else {
      return false;
    }
  };
  
  // EventEmitter is defined in src/node_events.cc
  // EventEmitter.prototype.emit() is also defined there.
  EventEmitter.prototype.addListener = function(type, listener) {
    if ('function' !== typeof listener) {
      throw new Error('addListener only takes instances of Function');
    }
  
    if (!this._events) this._events = {};
  
    // To avoid recursion in the case that type == "newListeners"! Before
    // adding it to the listeners, first emit "newListeners".
    this.emit('newListener', type, listener);
  
    if (!this._events[type]) {
      // Optimize the case of one listener. Don't need the extra array object.
      this._events[type] = listener;
    } else if (isArray(this._events[type])) {
  
      // Check for listener leak
      if (!this._events[type].warned) {
        var m;
        if (this._events.maxListeners !== undefined) {
          m = this._events.maxListeners;
        } else {
          m = defaultMaxListeners;
        }
  
        if (m && m > 0 && this._events[type].length > m) {
          this._events[type].warned = true;
          console.error('(node) warning: possible EventEmitter memory ' +
                        'leak detected. %d listeners added. ' +
                        'Use emitter.setMaxListeners() to increase limit.',
                        this._events[type].length);
          console.trace();
        }
      }
  
      // If we've already got an array, just append.
      this._events[type].push(listener);
    } else {
      // Adding the second element, need to change to array.
      this._events[type] = [this._events[type], listener];
    }
  
    return this;
  };
  
  EventEmitter.prototype.on = EventEmitter.prototype.addListener;
  
  EventEmitter.prototype.once = function(type, listener) {
    var self = this;
    self.on(type, function g() {
      self.removeListener(type, g);
      listener.apply(this, arguments);
    });
  
    return this;
  };
  
  EventEmitter.prototype.removeListener = function(type, listener) {
    if ('function' !== typeof listener) {
      throw new Error('removeListener only takes instances of Function');
    }
  
    // does not use listeners(), so no side effect of creating _events[type]
    if (!this._events || !this._events[type]) return this;
  
    var list = this._events[type];
  
    if (isArray(list)) {
      var i = indexOf(list, listener);
      if (i < 0) return this;
      list.splice(i, 1);
      if (list.length == 0)
        delete this._events[type];
    } else if (this._events[type] === listener) {
      delete this._events[type];
    }
  
    return this;
  };
  
  EventEmitter.prototype.removeAllListeners = function(type) {
    if (arguments.length === 0) {
      this._events = {};
      return this;
    }
  
    // does not use listeners(), so no side effect of creating _events[type]
    if (type && this._events && this._events[type]) this._events[type] = null;
    return this;
  };
  
  EventEmitter.prototype.listeners = function(type) {
    if (!this._events) this._events = {};
    if (!this._events[type]) this._events[type] = [];
    if (!isArray(this._events[type])) {
      this._events[type] = [this._events[type]];
    }
    return this._events[type];
  };
  
  })(require("__browserify_process"))
  },{"__browserify_process":8}],4:[function(require,module,exports){
  (function(){function SlowBuffer (size) {
      this.length = size;
  };
  
  var assert = require('assert');
  
  exports.INSPECT_MAX_BYTES = 50;
  
  
  function toHex(n) {
    if (n < 16) return '0' + n.toString(16);
    return n.toString(16);
  }
  
  function utf8ToBytes(str) {
    var byteArray = [];
    for (var i = 0; i < str.length; i++)
      if (str.charCodeAt(i) <= 0x7F)
        byteArray.push(str.charCodeAt(i));
      else {
        var h = encodeURIComponent(str.charAt(i)).substr(1).split('%');
        for (var j = 0; j < h.length; j++)
          byteArray.push(parseInt(h[j], 16));
      }
  
    return byteArray;
  }
  
  function asciiToBytes(str) {
    var byteArray = []
    for (var i = 0; i < str.length; i++ )
      // Node's code seems to be doing this and not & 0x7F..
      byteArray.push( str.charCodeAt(i) & 0xFF );
  
    return byteArray;
  }
  
  function base64ToBytes(str) {
    return require("base64-js").toByteArray(str);
  }
  
  SlowBuffer.byteLength = function (str, encoding) {
    switch (encoding || "utf8") {
      case 'hex':
        return str.length / 2;
  
      case 'utf8':
      case 'utf-8':
        return utf8ToBytes(str).length;
  
      case 'ascii':
        return str.length;
  
      case 'base64':
        return base64ToBytes(str).length;
  
      default:
        throw new Error('Unknown encoding');
    }
  };
  
  function blitBuffer(src, dst, offset, length) {
    var pos, i = 0;
    while (i < length) {
      if ((i+offset >= dst.length) || (i >= src.length))
        break;
  
      dst[i + offset] = src[i];
      i++;
    }
    return i;
  }
  
  SlowBuffer.prototype.utf8Write = function (string, offset, length) {
    var bytes, pos;
    return SlowBuffer._charsWritten =  blitBuffer(utf8ToBytes(string), this, offset, length);
  };
  
  SlowBuffer.prototype.asciiWrite = function (string, offset, length) {
    var bytes, pos;
    return SlowBuffer._charsWritten =  blitBuffer(asciiToBytes(string), this, offset, length);
  };
  
  SlowBuffer.prototype.base64Write = function (string, offset, length) {
    var bytes, pos;
    return SlowBuffer._charsWritten = blitBuffer(base64ToBytes(string), this, offset, length);
  };
  
  SlowBuffer.prototype.base64Slice = function (start, end) {
    var bytes = Array.prototype.slice.apply(this, arguments)
    return require("base64-js").fromByteArray(bytes);
  }
  
  function decodeUtf8Char(str) {
    try {
      return decodeURIComponent(str);
    } catch (err) {
      return String.fromCharCode(0xFFFD); // UTF 8 invalid char
    }
  }
  
  SlowBuffer.prototype.utf8Slice = function () {
    var bytes = Array.prototype.slice.apply(this, arguments);
    var res = "";
    var tmp = "";
    var i = 0;
    while (i < bytes.length) {
      if (bytes[i] <= 0x7F) {
        res += decodeUtf8Char(tmp) + String.fromCharCode(bytes[i]);
        tmp = "";
      } else
        tmp += "%" + bytes[i].toString(16);
  
      i++;
    }
  
    return res + decodeUtf8Char(tmp);
  }
  
  SlowBuffer.prototype.asciiSlice = function () {
    var bytes = Array.prototype.slice.apply(this, arguments);
    var ret = "";
    for (var i = 0; i < bytes.length; i++)
      ret += String.fromCharCode(bytes[i]);
    return ret;
  }
  
  SlowBuffer.prototype.inspect = function() {
    var out = [],
        len = this.length;
    for (var i = 0; i < len; i++) {
      out[i] = toHex(this[i]);
      if (i == exports.INSPECT_MAX_BYTES) {
        out[i + 1] = '...';
        break;
      }
    }
    return '<SlowBuffer ' + out.join(' ') + '>';
  };
  
  
  SlowBuffer.prototype.hexSlice = function(start, end) {
    var len = this.length;
  
    if (!start || start < 0) start = 0;
    if (!end || end < 0 || end > len) end = len;
  
    var out = '';
    for (var i = start; i < end; i++) {
      out += toHex(this[i]);
    }
    return out;
  };
  
  
  SlowBuffer.prototype.toString = function(encoding, start, end) {
    encoding = String(encoding || 'utf8').toLowerCase();
    start = +start || 0;
    if (typeof end == 'undefined') end = this.length;
  
    // Fastpath empty strings
    if (+end == start) {
      return '';
    }
  
    switch (encoding) {
      case 'hex':
        return this.hexSlice(start, end);
  
      case 'utf8':
      case 'utf-8':
        return this.utf8Slice(start, end);
  
      case 'ascii':
        return this.asciiSlice(start, end);
  
      case 'binary':
        return this.binarySlice(start, end);
  
      case 'base64':
        return this.base64Slice(start, end);
  
      case 'ucs2':
      case 'ucs-2':
        return this.ucs2Slice(start, end);
  
      default:
        throw new Error('Unknown encoding');
    }
  };
  
  
  SlowBuffer.prototype.hexWrite = function(string, offset, length) {
    offset = +offset || 0;
    var remaining = this.length - offset;
    if (!length) {
      length = remaining;
    } else {
      length = +length;
      if (length > remaining) {
        length = remaining;
      }
    }
  
    // must be an even number of digits
    var strLen = string.length;
    if (strLen % 2) {
      throw new Error('Invalid hex string');
    }
    if (length > strLen / 2) {
      length = strLen / 2;
    }
    for (var i = 0; i < length; i++) {
      var byte = parseInt(string.substr(i * 2, 2), 16);
      if (isNaN(byte)) throw new Error('Invalid hex string');
      this[offset + i] = byte;
    }
    SlowBuffer._charsWritten = i * 2;
    return i;
  };
  
  
  SlowBuffer.prototype.write = function(string, offset, length, encoding) {
    // Support both (string, offset, length, encoding)
    // and the legacy (string, encoding, offset, length)
    if (isFinite(offset)) {
      if (!isFinite(length)) {
        encoding = length;
        length = undefined;
      }
    } else {  // legacy
      var swap = encoding;
      encoding = offset;
      offset = length;
      length = swap;
    }
  
    offset = +offset || 0;
    var remaining = this.length - offset;
    if (!length) {
      length = remaining;
    } else {
      length = +length;
      if (length > remaining) {
        length = remaining;
      }
    }
    encoding = String(encoding || 'utf8').toLowerCase();
  
    switch (encoding) {
      case 'hex':
        return this.hexWrite(string, offset, length);
  
      case 'utf8':
      case 'utf-8':
        return this.utf8Write(string, offset, length);
  
      case 'ascii':
        return this.asciiWrite(string, offset, length);
  
      case 'binary':
        return this.binaryWrite(string, offset, length);
  
      case 'base64':
        return this.base64Write(string, offset, length);
  
      case 'ucs2':
      case 'ucs-2':
        return this.ucs2Write(string, offset, length);
  
      default:
        throw new Error('Unknown encoding');
    }
  };
  
  
  // slice(start, end)
  SlowBuffer.prototype.slice = function(start, end) {
    if (end === undefined) end = this.length;
  
    if (end > this.length) {
      throw new Error('oob');
    }
    if (start > end) {
      throw new Error('oob');
    }
  
    return new Buffer(this, end - start, +start);
  };
  
  SlowBuffer.prototype.copy = function(target, targetstart, sourcestart, sourceend) {
    var temp = [];
    for (var i=sourcestart; i<sourceend; i++) {
      assert.ok(typeof this[i] !== 'undefined', "copying undefined buffer bytes!");
      temp.push(this[i]);
    }
  
    for (var i=targetstart; i<targetstart+temp.length; i++) {
      target[i] = temp[i-targetstart];
    }
  };
  
  function coerce(length) {
    // Coerce length to a number (possibly NaN), round up
    // in case it's fractional (e.g. 123.456) then do a
    // double negate to coerce a NaN to 0. Easy, right?
    length = ~~Math.ceil(+length);
    return length < 0 ? 0 : length;
  }
  
  
  // Buffer
  
  function Buffer(subject, encoding, offset) {
    if (!(this instanceof Buffer)) {
      return new Buffer(subject, encoding, offset);
    }
  
    var type;
  
    // Are we slicing?
    if (typeof offset === 'number') {
      this.length = coerce(encoding);
      this.parent = subject;
      this.offset = offset;
    } else {
      // Find the length
      switch (type = typeof subject) {
        case 'number':
          this.length = coerce(subject);
          break;
  
        case 'string':
          this.length = Buffer.byteLength(subject, encoding);
          break;
  
        case 'object': // Assume object is an array
          this.length = coerce(subject.length);
          break;
  
        default:
          throw new Error('First argument needs to be a number, ' +
                          'array or string.');
      }
  
      if (this.length > Buffer.poolSize) {
        // Big buffer, just alloc one.
        this.parent = new SlowBuffer(this.length);
        this.offset = 0;
  
      } else {
        // Small buffer.
        if (!pool || pool.length - pool.used < this.length) allocPool();
        this.parent = pool;
        this.offset = pool.used;
        pool.used += this.length;
      }
  
      // Treat array-ish objects as a byte array.
      if (isArrayIsh(subject)) {
        for (var i = 0; i < this.length; i++) {
          this.parent[i + this.offset] = subject[i];
        }
      } else if (type == 'string') {
        // We are a string
        this.length = this.write(subject, 0, encoding);
      }
    }
  
  }
  
  function isArrayIsh(subject) {
    return Array.isArray(subject) || Buffer.isBuffer(subject) ||
           subject && typeof subject === 'object' &&
           typeof subject.length === 'number';
  }
  
  exports.SlowBuffer = SlowBuffer;
  exports.Buffer = Buffer;
  
  Buffer.poolSize = 8 * 1024;
  var pool;
  
  function allocPool() {
    pool = new SlowBuffer(Buffer.poolSize);
    pool.used = 0;
  }
  
  
  // Static methods
  Buffer.isBuffer = function isBuffer(b) {
    return b instanceof Buffer || b instanceof SlowBuffer;
  };
  
  Buffer.concat = function (list, totalLength) {
    if (!Array.isArray(list)) {
      throw new Error("Usage: Buffer.concat(list, [totalLength])\n \
        list should be an Array.");
    }
  
    if (list.length === 0) {
      return new Buffer(0);
    } else if (list.length === 1) {
      return list[0];
    }
  
    if (typeof totalLength !== 'number') {
      totalLength = 0;
      for (var i = 0; i < list.length; i++) {
        var buf = list[i];
        totalLength += buf.length;
      }
    }
  
    var buffer = new Buffer(totalLength);
    var pos = 0;
    for (var i = 0; i < list.length; i++) {
      var buf = list[i];
      buf.copy(buffer, pos);
      pos += buf.length;
    }
    return buffer;
  };
  
  // Inspect
  Buffer.prototype.inspect = function inspect() {
    var out = [],
        len = this.length;
  
    for (var i = 0; i < len; i++) {
      out[i] = toHex(this.parent[i + this.offset]);
      if (i == exports.INSPECT_MAX_BYTES) {
        out[i + 1] = '...';
        break;
      }
    }
  
    return '<Buffer ' + out.join(' ') + '>';
  };
  
  
  Buffer.prototype.get = function get(i) {
    if (i < 0 || i >= this.length) throw new Error('oob');
    return this.parent[this.offset + i];
  };
  
  
  Buffer.prototype.set = function set(i, v) {
    if (i < 0 || i >= this.length) throw new Error('oob');
    return this.parent[this.offset + i] = v;
  };
  
  
  // write(string, offset = 0, length = buffer.length-offset, encoding = 'utf8')
  Buffer.prototype.write = function(string, offset, length, encoding) {
    // Support both (string, offset, length, encoding)
    // and the legacy (string, encoding, offset, length)
    if (isFinite(offset)) {
      if (!isFinite(length)) {
        encoding = length;
        length = undefined;
      }
    } else {  // legacy
      var swap = encoding;
      encoding = offset;
      offset = length;
      length = swap;
    }
  
    offset = +offset || 0;
    var remaining = this.length - offset;
    if (!length) {
      length = remaining;
    } else {
      length = +length;
      if (length > remaining) {
        length = remaining;
      }
    }
    encoding = String(encoding || 'utf8').toLowerCase();
  
    var ret;
    switch (encoding) {
      case 'hex':
        ret = this.parent.hexWrite(string, this.offset + offset, length);
        break;
  
      case 'utf8':
      case 'utf-8':
        ret = this.parent.utf8Write(string, this.offset + offset, length);
        break;
  
      case 'ascii':
        ret = this.parent.asciiWrite(string, this.offset + offset, length);
        break;
  
      case 'binary':
        ret = this.parent.binaryWrite(string, this.offset + offset, length);
        break;
  
      case 'base64':
        // Warning: maxLength not taken into account in base64Write
        ret = this.parent.base64Write(string, this.offset + offset, length);
        break;
  
      case 'ucs2':
      case 'ucs-2':
        ret = this.parent.ucs2Write(string, this.offset + offset, length);
        break;
  
      default:
        throw new Error('Unknown encoding');
    }
  
    Buffer._charsWritten = SlowBuffer._charsWritten;
  
    return ret;
  };
  
  
  // toString(encoding, start=0, end=buffer.length)
  Buffer.prototype.toString = function(encoding, start, end) {
    encoding = String(encoding || 'utf8').toLowerCase();
  
    if (typeof start == 'undefined' || start < 0) {
      start = 0;
    } else if (start > this.length) {
      start = this.length;
    }
  
    if (typeof end == 'undefined' || end > this.length) {
      end = this.length;
    } else if (end < 0) {
      end = 0;
    }
  
    start = start + this.offset;
    end = end + this.offset;
  
    switch (encoding) {
      case 'hex':
        return this.parent.hexSlice(start, end);
  
      case 'utf8':
      case 'utf-8':
        return this.parent.utf8Slice(start, end);
  
      case 'ascii':
        return this.parent.asciiSlice(start, end);
  
      case 'binary':
        return this.parent.binarySlice(start, end);
  
      case 'base64':
        return this.parent.base64Slice(start, end);
  
      case 'ucs2':
      case 'ucs-2':
        return this.parent.ucs2Slice(start, end);
  
      default:
        throw new Error('Unknown encoding');
    }
  };
  
  
  // byteLength
  Buffer.byteLength = SlowBuffer.byteLength;
  
  
  // fill(value, start=0, end=buffer.length)
  Buffer.prototype.fill = function fill(value, start, end) {
    value || (value = 0);
    start || (start = 0);
    end || (end = this.length);
  
    if (typeof value === 'string') {
      value = value.charCodeAt(0);
    }
    if (!(typeof value === 'number') || isNaN(value)) {
      throw new Error('value is not a number');
    }
  
    if (end < start) throw new Error('end < start');
  
    // Fill 0 bytes; we're done
    if (end === start) return 0;
    if (this.length == 0) return 0;
  
    if (start < 0 || start >= this.length) {
      throw new Error('start out of bounds');
    }
  
    if (end < 0 || end > this.length) {
      throw new Error('end out of bounds');
    }
  
    return this.parent.fill(value,
                            start + this.offset,
                            end + this.offset);
  };
  
  
  // copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
  Buffer.prototype.copy = function(target, target_start, start, end) {
    var source = this;
    start || (start = 0);
    end || (end = this.length);
    target_start || (target_start = 0);
  
    if (end < start) throw new Error('sourceEnd < sourceStart');
  
    // Copy 0 bytes; we're done
    if (end === start) return 0;
    if (target.length == 0 || source.length == 0) return 0;
  
    if (target_start < 0 || target_start >= target.length) {
      throw new Error('targetStart out of bounds');
    }
  
    if (start < 0 || start >= source.length) {
      throw new Error('sourceStart out of bounds');
    }
  
    if (end < 0 || end > source.length) {
      throw new Error('sourceEnd out of bounds');
    }
  
    // Are we oob?
    if (end > this.length) {
      end = this.length;
    }
  
    if (target.length - target_start < end - start) {
      end = target.length - target_start + start;
    }
  
    return this.parent.copy(target.parent,
                            target_start + target.offset,
                            start + this.offset,
                            end + this.offset);
  };
  
  
  // slice(start, end)
  Buffer.prototype.slice = function(start, end) {
    if (end === undefined) end = this.length;
    if (end > this.length) throw new Error('oob');
    if (start > end) throw new Error('oob');
  
    return new Buffer(this.parent, end - start, +start + this.offset);
  };
  
  
  // Legacy methods for backwards compatibility.
  
  Buffer.prototype.utf8Slice = function(start, end) {
    return this.toString('utf8', start, end);
  };
  
  Buffer.prototype.binarySlice = function(start, end) {
    return this.toString('binary', start, end);
  };
  
  Buffer.prototype.asciiSlice = function(start, end) {
    return this.toString('ascii', start, end);
  };
  
  Buffer.prototype.utf8Write = function(string, offset) {
    return this.write(string, offset, 'utf8');
  };
  
  Buffer.prototype.binaryWrite = function(string, offset) {
    return this.write(string, offset, 'binary');
  };
  
  Buffer.prototype.asciiWrite = function(string, offset) {
    return this.write(string, offset, 'ascii');
  };
  
  Buffer.prototype.readUInt8 = function(offset, noAssert) {
    var buffer = this;
  
    if (!noAssert) {
      assert.ok(offset !== undefined && offset !== null,
          'missing offset');
  
      assert.ok(offset < buffer.length,
          'Trying to read beyond buffer length');
    }
  
    return buffer.parent[buffer.offset + offset];
  };
  
  function readUInt16(buffer, offset, isBigEndian, noAssert) {
    var val = 0;
  
  
    if (!noAssert) {
      assert.ok(typeof (isBigEndian) === 'boolean',
          'missing or invalid endian');
  
      assert.ok(offset !== undefined && offset !== null,
          'missing offset');
  
      assert.ok(offset + 1 < buffer.length,
          'Trying to read beyond buffer length');
    }
  
    if (isBigEndian) {
      val = buffer.parent[buffer.offset + offset] << 8;
      val |= buffer.parent[buffer.offset + offset + 1];
    } else {
      val = buffer.parent[buffer.offset + offset];
      val |= buffer.parent[buffer.offset + offset + 1] << 8;
    }
  
    return val;
  }
  
  Buffer.prototype.readUInt16LE = function(offset, noAssert) {
    return readUInt16(this, offset, false, noAssert);
  };
  
  Buffer.prototype.readUInt16BE = function(offset, noAssert) {
    return readUInt16(this, offset, true, noAssert);
  };
  
  function readUInt32(buffer, offset, isBigEndian, noAssert) {
    var val = 0;
  
    if (!noAssert) {
      assert.ok(typeof (isBigEndian) === 'boolean',
          'missing or invalid endian');
  
      assert.ok(offset !== undefined && offset !== null,
          'missing offset');
  
      assert.ok(offset + 3 < buffer.length,
          'Trying to read beyond buffer length');
    }
  
    if (isBigEndian) {
      val = buffer.parent[buffer.offset + offset + 1] << 16;
      val |= buffer.parent[buffer.offset + offset + 2] << 8;
      val |= buffer.parent[buffer.offset + offset + 3];
      val = val + (buffer.parent[buffer.offset + offset] << 24 >>> 0);
    } else {
      val = buffer.parent[buffer.offset + offset + 2] << 16;
      val |= buffer.parent[buffer.offset + offset + 1] << 8;
      val |= buffer.parent[buffer.offset + offset];
      val = val + (buffer.parent[buffer.offset + offset + 3] << 24 >>> 0);
    }
  
    return val;
  }
  
  Buffer.prototype.readUInt32LE = function(offset, noAssert) {
    return readUInt32(this, offset, false, noAssert);
  };
  
  Buffer.prototype.readUInt32BE = function(offset, noAssert) {
    return readUInt32(this, offset, true, noAssert);
  };
  
  
  /*
   * Signed integer types, yay team! A reminder on how two's complement actually
   * works. The first bit is the signed bit, i.e. tells us whether or not the
   * number should be positive or negative. If the two's complement value is
   * positive, then we're done, as it's equivalent to the unsigned representation.
   *
   * Now if the number is positive, you're pretty much done, you can just leverage
   * the unsigned translations and return those. Unfortunately, negative numbers
   * aren't quite that straightforward.
   *
   * At first glance, one might be inclined to use the traditional formula to
   * translate binary numbers between the positive and negative values in two's
   * complement. (Though it doesn't quite work for the most negative value)
   * Mainly:
   *  - invert all the bits
   *  - add one to the result
   *
   * Of course, this doesn't quite work in Javascript. Take for example the value
   * of -128. This could be represented in 16 bits (big-endian) as 0xff80. But of
   * course, Javascript will do the following:
   *
   * > ~0xff80
   * -65409
   *
   * Whoh there, Javascript, that's not quite right. But wait, according to
   * Javascript that's perfectly correct. When Javascript ends up seeing the
   * constant 0xff80, it has no notion that it is actually a signed number. It
   * assumes that we've input the unsigned value 0xff80. Thus, when it does the
   * binary negation, it casts it into a signed value, (positive 0xff80). Then
   * when you perform binary negation on that, it turns it into a negative number.
   *
   * Instead, we're going to have to use the following general formula, that works
   * in a rather Javascript friendly way. I'm glad we don't support this kind of
   * weird numbering scheme in the kernel.
   *
   * (BIT-MAX - (unsigned)val + 1) * -1
   *
   * The astute observer, may think that this doesn't make sense for 8-bit numbers
   * (really it isn't necessary for them). However, when you get 16-bit numbers,
   * you do. Let's go back to our prior example and see how this will look:
   *
   * (0xffff - 0xff80 + 1) * -1
   * (0x007f + 1) * -1
   * (0x0080) * -1
   */
  Buffer.prototype.readInt8 = function(offset, noAssert) {
    var buffer = this;
    var neg;
  
    if (!noAssert) {
      assert.ok(offset !== undefined && offset !== null,
          'missing offset');
  
      assert.ok(offset < buffer.length,
          'Trying to read beyond buffer length');
    }
  
    neg = buffer.parent[buffer.offset + offset] & 0x80;
    if (!neg) {
      return (buffer.parent[buffer.offset + offset]);
    }
  
    return ((0xff - buffer.parent[buffer.offset + offset] + 1) * -1);
  };
  
  function readInt16(buffer, offset, isBigEndian, noAssert) {
    var neg, val;
  
    if (!noAssert) {
      assert.ok(typeof (isBigEndian) === 'boolean',
          'missing or invalid endian');
  
      assert.ok(offset !== undefined && offset !== null,
          'missing offset');
  
      assert.ok(offset + 1 < buffer.length,
          'Trying to read beyond buffer length');
    }
  
    val = readUInt16(buffer, offset, isBigEndian, noAssert);
    neg = val & 0x8000;
    if (!neg) {
      return val;
    }
  
    return (0xffff - val + 1) * -1;
  }
  
  Buffer.prototype.readInt16LE = function(offset, noAssert) {
    return readInt16(this, offset, false, noAssert);
  };
  
  Buffer.prototype.readInt16BE = function(offset, noAssert) {
    return readInt16(this, offset, true, noAssert);
  };
  
  function readInt32(buffer, offset, isBigEndian, noAssert) {
    var neg, val;
  
    if (!noAssert) {
      assert.ok(typeof (isBigEndian) === 'boolean',
          'missing or invalid endian');
  
      assert.ok(offset !== undefined && offset !== null,
          'missing offset');
  
      assert.ok(offset + 3 < buffer.length,
          'Trying to read beyond buffer length');
    }
  
    val = readUInt32(buffer, offset, isBigEndian, noAssert);
    neg = val & 0x80000000;
    if (!neg) {
      return (val);
    }
  
    return (0xffffffff - val + 1) * -1;
  }
  
  Buffer.prototype.readInt32LE = function(offset, noAssert) {
    return readInt32(this, offset, false, noAssert);
  };
  
  Buffer.prototype.readInt32BE = function(offset, noAssert) {
    return readInt32(this, offset, true, noAssert);
  };
  
  function readFloat(buffer, offset, isBigEndian, noAssert) {
    if (!noAssert) {
      assert.ok(typeof (isBigEndian) === 'boolean',
          'missing or invalid endian');
  
      assert.ok(offset + 3 < buffer.length,
          'Trying to read beyond buffer length');
    }
  
    return require('./buffer_ieee754').readIEEE754(buffer, offset, isBigEndian,
        23, 4);
  }
  
  Buffer.prototype.readFloatLE = function(offset, noAssert) {
    return readFloat(this, offset, false, noAssert);
  };
  
  Buffer.prototype.readFloatBE = function(offset, noAssert) {
    return readFloat(this, offset, true, noAssert);
  };
  
  function readDouble(buffer, offset, isBigEndian, noAssert) {
    if (!noAssert) {
      assert.ok(typeof (isBigEndian) === 'boolean',
          'missing or invalid endian');
  
      assert.ok(offset + 7 < buffer.length,
          'Trying to read beyond buffer length');
    }
  
    return require('./buffer_ieee754').readIEEE754(buffer, offset, isBigEndian,
        52, 8);
  }
  
  Buffer.prototype.readDoubleLE = function(offset, noAssert) {
    return readDouble(this, offset, false, noAssert);
  };
  
  Buffer.prototype.readDoubleBE = function(offset, noAssert) {
    return readDouble(this, offset, true, noAssert);
  };
  
  
  /*
   * We have to make sure that the value is a valid integer. This means that it is
   * non-negative. It has no fractional component and that it does not exceed the
   * maximum allowed value.
   *
   *      value           The number to check for validity
   *
   *      max             The maximum value
   */
  function verifuint(value, max) {
    assert.ok(typeof (value) == 'number',
        'cannot write a non-number as a number');
  
    assert.ok(value >= 0,
        'specified a negative value for writing an unsigned value');
  
    assert.ok(value <= max, 'value is larger than maximum value for type');
  
    assert.ok(Math.floor(value) === value, 'value has a fractional component');
  }
  
  Buffer.prototype.writeUInt8 = function(value, offset, noAssert) {
    var buffer = this;
  
    if (!noAssert) {
      assert.ok(value !== undefined && value !== null,
          'missing value');
  
      assert.ok(offset !== undefined && offset !== null,
          'missing offset');
  
      assert.ok(offset < buffer.length,
          'trying to write beyond buffer length');
  
      verifuint(value, 0xff);
    }
  
    buffer.parent[buffer.offset + offset] = value;
  };
  
  function writeUInt16(buffer, value, offset, isBigEndian, noAssert) {
    if (!noAssert) {
      assert.ok(value !== undefined && value !== null,
          'missing value');
  
      assert.ok(typeof (isBigEndian) === 'boolean',
          'missing or invalid endian');
  
      assert.ok(offset !== undefined && offset !== null,
          'missing offset');
  
      assert.ok(offset + 1 < buffer.length,
          'trying to write beyond buffer length');
  
      verifuint(value, 0xffff);
    }
  
    if (isBigEndian) {
      buffer.parent[buffer.offset + offset] = (value & 0xff00) >>> 8;
      buffer.parent[buffer.offset + offset + 1] = value & 0x00ff;
    } else {
      buffer.parent[buffer.offset + offset + 1] = (value & 0xff00) >>> 8;
      buffer.parent[buffer.offset + offset] = value & 0x00ff;
    }
  }
  
  Buffer.prototype.writeUInt16LE = function(value, offset, noAssert) {
    writeUInt16(this, value, offset, false, noAssert);
  };
  
  Buffer.prototype.writeUInt16BE = function(value, offset, noAssert) {
    writeUInt16(this, value, offset, true, noAssert);
  };
  
  function writeUInt32(buffer, value, offset, isBigEndian, noAssert) {
    if (!noAssert) {
      assert.ok(value !== undefined && value !== null,
          'missing value');
  
      assert.ok(typeof (isBigEndian) === 'boolean',
          'missing or invalid endian');
  
      assert.ok(offset !== undefined && offset !== null,
          'missing offset');
  
      assert.ok(offset + 3 < buffer.length,
          'trying to write beyond buffer length');
  
      verifuint(value, 0xffffffff);
    }
  
    if (isBigEndian) {
      buffer.parent[buffer.offset + offset] = (value >>> 24) & 0xff;
      buffer.parent[buffer.offset + offset + 1] = (value >>> 16) & 0xff;
      buffer.parent[buffer.offset + offset + 2] = (value >>> 8) & 0xff;
      buffer.parent[buffer.offset + offset + 3] = value & 0xff;
    } else {
      buffer.parent[buffer.offset + offset + 3] = (value >>> 24) & 0xff;
      buffer.parent[buffer.offset + offset + 2] = (value >>> 16) & 0xff;
      buffer.parent[buffer.offset + offset + 1] = (value >>> 8) & 0xff;
      buffer.parent[buffer.offset + offset] = value & 0xff;
    }
  }
  
  Buffer.prototype.writeUInt32LE = function(value, offset, noAssert) {
    writeUInt32(this, value, offset, false, noAssert);
  };
  
  Buffer.prototype.writeUInt32BE = function(value, offset, noAssert) {
    writeUInt32(this, value, offset, true, noAssert);
  };
  
  
  /*
   * We now move onto our friends in the signed number category. Unlike unsigned
   * numbers, we're going to have to worry a bit more about how we put values into
   * arrays. Since we are only worrying about signed 32-bit values, we're in
   * slightly better shape. Unfortunately, we really can't do our favorite binary
   * & in this system. It really seems to do the wrong thing. For example:
   *
   * > -32 & 0xff
   * 224
   *
   * What's happening above is really: 0xe0 & 0xff = 0xe0. However, the results of
   * this aren't treated as a signed number. Ultimately a bad thing.
   *
   * What we're going to want to do is basically create the unsigned equivalent of
   * our representation and pass that off to the wuint* functions. To do that
   * we're going to do the following:
   *
   *  - if the value is positive
   *      we can pass it directly off to the equivalent wuint
   *  - if the value is negative
   *      we do the following computation:
   *         mb + val + 1, where
   *         mb   is the maximum unsigned value in that byte size
   *         val  is the Javascript negative integer
   *
   *
   * As a concrete value, take -128. In signed 16 bits this would be 0xff80. If
   * you do out the computations:
   *
   * 0xffff - 128 + 1
   * 0xffff - 127
   * 0xff80
   *
   * You can then encode this value as the signed version. This is really rather
   * hacky, but it should work and get the job done which is our goal here.
   */
  
  /*
   * A series of checks to make sure we actually have a signed 32-bit number
   */
  function verifsint(value, max, min) {
    assert.ok(typeof (value) == 'number',
        'cannot write a non-number as a number');
  
    assert.ok(value <= max, 'value larger than maximum allowed value');
  
    assert.ok(value >= min, 'value smaller than minimum allowed value');
  
    assert.ok(Math.floor(value) === value, 'value has a fractional component');
  }
  
  function verifIEEE754(value, max, min) {
    assert.ok(typeof (value) == 'number',
        'cannot write a non-number as a number');
  
    assert.ok(value <= max, 'value larger than maximum allowed value');
  
    assert.ok(value >= min, 'value smaller than minimum allowed value');
  }
  
  Buffer.prototype.writeInt8 = function(value, offset, noAssert) {
    var buffer = this;
  
    if (!noAssert) {
      assert.ok(value !== undefined && value !== null,
          'missing value');
  
      assert.ok(offset !== undefined && offset !== null,
          'missing offset');
  
      assert.ok(offset < buffer.length,
          'Trying to write beyond buffer length');
  
      verifsint(value, 0x7f, -0x80);
    }
  
    if (value >= 0) {
      buffer.writeUInt8(value, offset, noAssert);
    } else {
      buffer.writeUInt8(0xff + value + 1, offset, noAssert);
    }
  };
  
  function writeInt16(buffer, value, offset, isBigEndian, noAssert) {
    if (!noAssert) {
      assert.ok(value !== undefined && value !== null,
          'missing value');
  
      assert.ok(typeof (isBigEndian) === 'boolean',
          'missing or invalid endian');
  
      assert.ok(offset !== undefined && offset !== null,
          'missing offset');
  
      assert.ok(offset + 1 < buffer.length,
          'Trying to write beyond buffer length');
  
      verifsint(value, 0x7fff, -0x8000);
    }
  
    if (value >= 0) {
      writeUInt16(buffer, value, offset, isBigEndian, noAssert);
    } else {
      writeUInt16(buffer, 0xffff + value + 1, offset, isBigEndian, noAssert);
    }
  }
  
  Buffer.prototype.writeInt16LE = function(value, offset, noAssert) {
    writeInt16(this, value, offset, false, noAssert);
  };
  
  Buffer.prototype.writeInt16BE = function(value, offset, noAssert) {
    writeInt16(this, value, offset, true, noAssert);
  };
  
  function writeInt32(buffer, value, offset, isBigEndian, noAssert) {
    if (!noAssert) {
      assert.ok(value !== undefined && value !== null,
          'missing value');
  
      assert.ok(typeof (isBigEndian) === 'boolean',
          'missing or invalid endian');
  
      assert.ok(offset !== undefined && offset !== null,
          'missing offset');
  
      assert.ok(offset + 3 < buffer.length,
          'Trying to write beyond buffer length');
  
      verifsint(value, 0x7fffffff, -0x80000000);
    }
  
    if (value >= 0) {
      writeUInt32(buffer, value, offset, isBigEndian, noAssert);
    } else {
      writeUInt32(buffer, 0xffffffff + value + 1, offset, isBigEndian, noAssert);
    }
  }
  
  Buffer.prototype.writeInt32LE = function(value, offset, noAssert) {
    writeInt32(this, value, offset, false, noAssert);
  };
  
  Buffer.prototype.writeInt32BE = function(value, offset, noAssert) {
    writeInt32(this, value, offset, true, noAssert);
  };
  
  function writeFloat(buffer, value, offset, isBigEndian, noAssert) {
    if (!noAssert) {
      assert.ok(value !== undefined && value !== null,
          'missing value');
  
      assert.ok(typeof (isBigEndian) === 'boolean',
          'missing or invalid endian');
  
      assert.ok(offset !== undefined && offset !== null,
          'missing offset');
  
      assert.ok(offset + 3 < buffer.length,
          'Trying to write beyond buffer length');
  
      verifIEEE754(value, 3.4028234663852886e+38, -3.4028234663852886e+38);
    }
  
    require('./buffer_ieee754').writeIEEE754(buffer, value, offset, isBigEndian,
        23, 4);
  }
  
  Buffer.prototype.writeFloatLE = function(value, offset, noAssert) {
    writeFloat(this, value, offset, false, noAssert);
  };
  
  Buffer.prototype.writeFloatBE = function(value, offset, noAssert) {
    writeFloat(this, value, offset, true, noAssert);
  };
  
  function writeDouble(buffer, value, offset, isBigEndian, noAssert) {
    if (!noAssert) {
      assert.ok(value !== undefined && value !== null,
          'missing value');
  
      assert.ok(typeof (isBigEndian) === 'boolean',
          'missing or invalid endian');
  
      assert.ok(offset !== undefined && offset !== null,
          'missing offset');
  
      assert.ok(offset + 7 < buffer.length,
          'Trying to write beyond buffer length');
  
      verifIEEE754(value, 1.7976931348623157E+308, -1.7976931348623157E+308);
    }
  
    require('./buffer_ieee754').writeIEEE754(buffer, value, offset, isBigEndian,
        52, 8);
  }
  
  Buffer.prototype.writeDoubleLE = function(value, offset, noAssert) {
    writeDouble(this, value, offset, false, noAssert);
  };
  
  Buffer.prototype.writeDoubleBE = function(value, offset, noAssert) {
    writeDouble(this, value, offset, true, noAssert);
  };
  
  SlowBuffer.prototype.readUInt8 = Buffer.prototype.readUInt8;
  SlowBuffer.prototype.readUInt16LE = Buffer.prototype.readUInt16LE;
  SlowBuffer.prototype.readUInt16BE = Buffer.prototype.readUInt16BE;
  SlowBuffer.prototype.readUInt32LE = Buffer.prototype.readUInt32LE;
  SlowBuffer.prototype.readUInt32BE = Buffer.prototype.readUInt32BE;
  SlowBuffer.prototype.readInt8 = Buffer.prototype.readInt8;
  SlowBuffer.prototype.readInt16LE = Buffer.prototype.readInt16LE;
  SlowBuffer.prototype.readInt16BE = Buffer.prototype.readInt16BE;
  SlowBuffer.prototype.readInt32LE = Buffer.prototype.readInt32LE;
  SlowBuffer.prototype.readInt32BE = Buffer.prototype.readInt32BE;
  SlowBuffer.prototype.readFloatLE = Buffer.prototype.readFloatLE;
  SlowBuffer.prototype.readFloatBE = Buffer.prototype.readFloatBE;
  SlowBuffer.prototype.readDoubleLE = Buffer.prototype.readDoubleLE;
  SlowBuffer.prototype.readDoubleBE = Buffer.prototype.readDoubleBE;
  SlowBuffer.prototype.writeUInt8 = Buffer.prototype.writeUInt8;
  SlowBuffer.prototype.writeUInt16LE = Buffer.prototype.writeUInt16LE;
  SlowBuffer.prototype.writeUInt16BE = Buffer.prototype.writeUInt16BE;
  SlowBuffer.prototype.writeUInt32LE = Buffer.prototype.writeUInt32LE;
  SlowBuffer.prototype.writeUInt32BE = Buffer.prototype.writeUInt32BE;
  SlowBuffer.prototype.writeInt8 = Buffer.prototype.writeInt8;
  SlowBuffer.prototype.writeInt16LE = Buffer.prototype.writeInt16LE;
  SlowBuffer.prototype.writeInt16BE = Buffer.prototype.writeInt16BE;
  SlowBuffer.prototype.writeInt32LE = Buffer.prototype.writeInt32LE;
  SlowBuffer.prototype.writeInt32BE = Buffer.prototype.writeInt32BE;
  SlowBuffer.prototype.writeFloatLE = Buffer.prototype.writeFloatLE;
  SlowBuffer.prototype.writeFloatBE = Buffer.prototype.writeFloatBE;
  SlowBuffer.prototype.writeDoubleLE = Buffer.prototype.writeDoubleLE;
  SlowBuffer.prototype.writeDoubleBE = Buffer.prototype.writeDoubleBE;
  
  })()
  },{"assert":2,"./buffer_ieee754":7,"base64-js":9}],9:[function(require,module,exports){
  (function (exports) {
  	'use strict';
  
  	var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
  
  	function b64ToByteArray(b64) {
  		var i, j, l, tmp, placeHolders, arr;
  	
  		if (b64.length % 4 > 0) {
  			throw 'Invalid string. Length must be a multiple of 4';
  		}
  
  		// the number of equal signs (place holders)
  		// if there are two placeholders, than the two characters before it
  		// represent one byte
  		// if there is only one, then the three characters before it represent 2 bytes
  		// this is just a cheap hack to not do indexOf twice
  		placeHolders = b64.indexOf('=');
  		placeHolders = placeHolders > 0 ? b64.length - placeHolders : 0;
  
  		// base64 is 4/3 + up to two characters of the original data
  		arr = [];//new Uint8Array(b64.length * 3 / 4 - placeHolders);
  
  		// if there are placeholders, only get up to the last complete 4 chars
  		l = placeHolders > 0 ? b64.length - 4 : b64.length;
  
  		for (i = 0, j = 0; i < l; i += 4, j += 3) {
  			tmp = (lookup.indexOf(b64[i]) << 18) | (lookup.indexOf(b64[i + 1]) << 12) | (lookup.indexOf(b64[i + 2]) << 6) | lookup.indexOf(b64[i + 3]);
  			arr.push((tmp & 0xFF0000) >> 16);
  			arr.push((tmp & 0xFF00) >> 8);
  			arr.push(tmp & 0xFF);
  		}
  
  		if (placeHolders === 2) {
  			tmp = (lookup.indexOf(b64[i]) << 2) | (lookup.indexOf(b64[i + 1]) >> 4);
  			arr.push(tmp & 0xFF);
  		} else if (placeHolders === 1) {
  			tmp = (lookup.indexOf(b64[i]) << 10) | (lookup.indexOf(b64[i + 1]) << 4) | (lookup.indexOf(b64[i + 2]) >> 2);
  			arr.push((tmp >> 8) & 0xFF);
  			arr.push(tmp & 0xFF);
  		}
  
  		return arr;
  	}
  
  	function uint8ToBase64(uint8) {
  		var i,
  			extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes
  			output = "",
  			temp, length;
  
  		function tripletToBase64 (num) {
  			return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F];
  		};
  
  		// go through the array every three bytes, we'll deal with trailing stuff later
  		for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {
  			temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]);
  			output += tripletToBase64(temp);
  		}
  
  		// pad the end with zeros, but make sure to not forget the extra bytes
  		switch (extraBytes) {
  			case 1:
  				temp = uint8[uint8.length - 1];
  				output += lookup[temp >> 2];
  				output += lookup[(temp << 4) & 0x3F];
  				output += '==';
  				break;
  			case 2:
  				temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1]);
  				output += lookup[temp >> 10];
  				output += lookup[(temp >> 4) & 0x3F];
  				output += lookup[(temp << 2) & 0x3F];
  				output += '=';
  				break;
  		}
  
  		return output;
  	}
  
  	module.exports.toByteArray = b64ToByteArray;
  	module.exports.fromByteArray = uint8ToBase64;
  }());
  
  },{}]},{},[])
  ;;module.exports=require("buffer-browserify")
  
  },{}],36:[function(require,module,exports){
  (function(Buffer,global){'use strict'
  
  var bits = require('bit-twiddle')
  var dup = require('dup')
  
  //Legacy pool support
  if(!global.__TYPEDARRAY_POOL) {
    global.__TYPEDARRAY_POOL = {
        UINT8   : dup([32, 0])
      , UINT16  : dup([32, 0])
      , UINT32  : dup([32, 0])
      , INT8    : dup([32, 0])
      , INT16   : dup([32, 0])
      , INT32   : dup([32, 0])
      , FLOAT   : dup([32, 0])
      , DOUBLE  : dup([32, 0])
      , DATA    : dup([32, 0])
      , UINT8C  : dup([32, 0])
      , BUFFER  : dup([32, 0])
    }
  }
  
  var hasUint8C = (typeof Uint8ClampedArray) !== 'undefined'
  var POOL = global.__TYPEDARRAY_POOL
  
  //Upgrade pool
  if(!POOL.UINT8C) {
    POOL.UINT8C = dup([32, 0])
  }
  if(!POOL.BUFFER) {
    POOL.BUFFER = dup([32, 0])
  }
  
  //New technique: Only allocate from ArrayBufferView and Buffer
  var DATA    = POOL.DATA
    , BUFFER  = POOL.BUFFER
  
  exports.free = function free(array) {
    if(Buffer.isBuffer(array)) {
      BUFFER[bits.log2(array.length)].push(array)
    } else {
      if(Object.prototype.toString.call(array) !== '[object ArrayBuffer]') {
        array = array.buffer
      }
      if(!array) {
        return
      }
      var n = array.length || array.byteLength
      var log_n = bits.log2(n)|0
      DATA[log_n].push(array)
    }
  }
  
  function freeArrayBuffer(buffer) {
    if(!buffer) {
      return
    }
    var n = buffer.length || buffer.byteLength
    var log_n = bits.log2(n)
    DATA[log_n].push(buffer)
  }
  
  function freeTypedArray(array) {
    freeArrayBuffer(array.buffer)
  }
  
  exports.freeUint8 =
  exports.freeUint16 =
  exports.freeUint32 =
  exports.freeInt8 =
  exports.freeInt16 =
  exports.freeInt32 =
  exports.freeFloat32 = 
  exports.freeFloat =
  exports.freeFloat64 = 
  exports.freeDouble = 
  exports.freeUint8Clamped = 
  exports.freeDataView = freeTypedArray
  
  exports.freeArrayBuffer = freeArrayBuffer
  
  exports.freeBuffer = function freeBuffer(array) {
    BUFFER[bits.log2(array.length)].push(array)
  }
  
  exports.malloc = function malloc(n, dtype) {
    if(dtype === undefined || dtype === 'arraybuffer') {
      return mallocArrayBuffer(n)
    } else {
      switch(dtype) {
        case 'uint8':
          return mallocUint8(n)
        case 'uint16':
          return mallocUint16(n)
        case 'uint32':
          return mallocUint32(n)
        case 'int8':
          return mallocInt8(n)
        case 'int16':
          return mallocInt16(n)
        case 'int32':
          return mallocInt32(n)
        case 'float':
        case 'float32':
          return mallocFloat(n)
        case 'double':
        case 'float64':
          return mallocDouble(n)
        case 'uint8_clamped':
          return mallocUint8Clamped(n)
        case 'buffer':
          return mallocBuffer(n)
        case 'data':
        case 'dataview':
          return mallocDataView(n)
  
        default:
          return null
      }
    }
    return null
  }
  
  function mallocArrayBuffer(n) {
    var n = bits.nextPow2(n)
    var log_n = bits.log2(n)
    var d = DATA[log_n]
    if(d.length > 0) {
      return d.pop()
    }
    return new ArrayBuffer(n)
  }
  exports.mallocArrayBuffer = mallocArrayBuffer
  
  function mallocUint8(n) {
    return new Uint8Array(mallocArrayBuffer(n), 0, n)
  }
  exports.mallocUint8 = mallocUint8
  
  function mallocUint16(n) {
    return new Uint16Array(mallocArrayBuffer(2*n), 0, n)
  }
  exports.mallocUint16 = mallocUint16
  
  function mallocUint32(n) {
    return new Uint32Array(mallocArrayBuffer(4*n), 0, n)
  }
  exports.mallocUint32 = mallocUint32
  
  function mallocInt8(n) {
    return new Int8Array(mallocArrayBuffer(n), 0, n)
  }
  exports.mallocInt8 = mallocInt8
  
  function mallocInt16(n) {
    return new Int16Array(mallocArrayBuffer(2*n), 0, n)
  }
  exports.mallocInt16 = mallocInt16
  
  function mallocInt32(n) {
    return new Int32Array(mallocArrayBuffer(4*n), 0, n)
  }
  exports.mallocInt32 = mallocInt32
  
  function mallocFloat(n) {
    return new Float32Array(mallocArrayBuffer(4*n), 0, n)
  }
  exports.mallocFloat32 = exports.mallocFloat = mallocFloat
  
  function mallocDouble(n) {
    return new Float64Array(mallocArrayBuffer(8*n), 0, n)
  }
  exports.mallocFloat64 = exports.mallocDouble = mallocDouble
  
  function mallocUint8Clamped(n) {
    if(hasUint8C) {
      return new Uint8ClampedArray(mallocArrayBuffer(n), 0, n)
    } else {
      return mallocUint8(n)
    }
  }
  exports.mallocUint8Clamped = mallocUint8Clamped
  
  function mallocDataView(n) {
    return new DataView(mallocArrayBuffer(n), 0, n)
  }
  exports.mallocDataView = mallocDataView
  
  function mallocBuffer(n) {
    n = bits.nextPow2(n)
    var log_n = bits.log2(n)
    var cache = BUFFER[log_n]
    if(cache.length > 0) {
      return cache.pop()
    }
    return new Buffer(n)
  }
  exports.mallocBuffer = mallocBuffer
  
  exports.clearCache = function clearCache() {
    for(var i=0; i<32; ++i) {
      POOL.UINT8[i].length = 0
      POOL.UINT16[i].length = 0
      POOL.UINT32[i].length = 0
      POOL.INT8[i].length = 0
      POOL.INT16[i].length = 0
      POOL.INT32[i].length = 0
      POOL.FLOAT[i].length = 0
      POOL.DOUBLE[i].length = 0
      POOL.UINT8C[i].length = 0
      DATA[i].length = 0
      BUFFER[i].length = 0
    }
  }
  })(require("__browserify_buffer").Buffer,window)
  },{"__browserify_buffer":43,"bit-twiddle":40,"dup":42}]},{},[1])
  ;