Jelajahi Sumber

corpus ajax loaded and displayed as physics map

Bachir Soussi Chiadmi 7 tahun lalu
induk
melakukan
6255e3285a

+ 1153 - 0
sites/all/modules/figli/edlp_corpus/assets/dist/bower/physics.js

@@ -0,0 +1,1153 @@
+/**
+ * Physics
+ * A requirified port of Traer Physics from Processing to JavaScript.
+ * Copyright (C) 2012 jonobr1
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
+var _      = require('./common')
+,   Vector = require('./vector')
+;
+
+  function Attraction(a, b, k, d) {
+
+    this.a = a;
+    this.b = b;
+    this.constant = k;
+    this.on = true;
+    this.distanceMin = d;
+    this.distanceMinSquared = d * d;
+
+  }
+
+  _.extend(Attraction.prototype, {
+
+    update: function() {
+
+     var a = this.a, b = this.b;
+     if (!this.on || (a.fixed && b.fixed)) {
+       return;
+     }
+
+     var a2bx = a.position.x - b.position.x;
+     var a2by = a.position.y - b.position.y;
+
+     var a2b = new Vector().sub(a.position, b.position);
+
+     var a2bdistanceSquared = Math.max(a2b.lengthSquared(), this.distanceMinSquared);
+
+     var force = (this.constant * a.mass * b.mass) / a2bdistanceSquared;
+
+     var length = Math.sqrt(a2bdistanceSquared);
+
+     if (force === 0 || length === 0) {
+       a2b.clear();
+     } else {
+       a2b.divideScalar(length).multiplyScalar(force);
+     }
+
+     if (!a.fixed) {
+       a.force.subSelf(a2b);
+     }
+     if (!b.fixed) {
+       b.force.addSelf(a2b);
+     }
+
+     return this;
+
+    },
+
+    /**
+     * Returns a boolean describing whether the spring is resting or not.
+     * Convenient for knowing whether or not the spring needs another update
+     * tick.
+     *
+     * TODO: Test
+     */
+    resting: function() {
+
+      var a = this.a;
+      var b = this.b;
+      var l = this.distanceMin;
+
+      return !this.on || (a.fixed && b.fixed)
+        || (a.fixed && b.position.distanceTo(a.position) <= l && b.resting())
+        || (b.fixed && a.position.distanceTo(b.position) <= l && a.resting());
+
+    }
+
+  });
+
+  module.exports = Attraction;
+
+},{"./common":8,"./vector":12}],2:[function(require,module,exports){
+var _      = require('./common')
+,   Vector = require('./vector')
+;
+
+  /**
+   * Runge Kutta Integrator
+   * http://en.wikipedia.org/wiki/Runge%E2%80%93Kutta_methods
+   *
+   * @class
+   */
+  function Integrator(s) {
+    this.s = s;
+    this.originalPositions = [];
+    this.originalVelocities = [];
+    this.k1Forces = [];
+    this.k1Velocities = [];
+    this.k2Forces = [];
+    this.k2Velocities = [];
+    this.k3Forces = [];
+    this.k3Velocities = [];
+    this.k4Forces = [];
+    this.k4Velocities = [];
+  }
+
+  _.extend(Integrator.prototype, {
+
+    allocateParticles: function() {
+
+      while (this.s.particles.length > this.originalPositions.length) {
+        this.originalPositions.push(new Vector());
+        this.originalVelocities.push(new Vector());
+        this.k1Forces.push(new Vector());
+        this.k1Velocities.push(new Vector());
+        this.k2Forces.push(new Vector());
+        this.k2Velocities.push(new Vector());
+        this.k3Forces.push(new Vector());
+        this.k3Velocities.push(new Vector());
+        this.k4Forces.push(new Vector());
+        this.k4Velocities.push(new Vector());
+      }
+
+      return this;
+
+    },
+
+    step: function(dt) {
+
+      var s = this.s;
+      var p, x, y;
+
+      this.allocateParticles();
+
+      _.each(s.particles, function(p, i) {
+        if (!p.fixed) {
+          this.originalPositions[i].copy(p.position);
+          this.originalVelocities[i].copy(p.velocity);
+        }
+        p.force.clear();
+      }, this);
+
+      // K1
+
+      s.applyForces();
+
+      _.each(s.particles, function(p, i) {
+        if (!p.fixed) {
+          this.k1Forces[i].copy(p.force);
+          this.k1Velocities[i].copy(p.velocity);
+        }
+        p.force.clear();
+      }, this);
+
+      // K2
+
+      _.each(s.particles, function(p, i) {
+        if (!p.fixed) {
+
+          var op = this.originalPositions[i];
+          var k1v = this.k1Velocities[i];
+          x = op.x + k1v.x * 0.5 * dt;
+          y = op.y + k1v.y * 0.5 * dt;
+          p.position.set(x, y);
+
+          var ov = this.originalVelocities[i];
+          var k1f = this.k1Forces[i];
+          x = ov.x + k1f.x * 0.5 * dt / p.mass;
+          y = ov.y + k1f.y * 0.5 * dt / p.mass;
+          p.velocity.set(x, y);
+
+        }
+      }, this);
+
+      s.applyForces();
+
+      _.each(s.particles, function(p, i) {
+        if (!p.fixed) {
+          this.k2Forces[i].copy(p.force);
+          this.k2Velocities[i].copy(p.velocity);
+        }
+        p.force.clear();
+      }, this);
+
+      // K3
+
+      _.each(s.particles, function(p, i) {
+        if (!p.fixed) {
+
+          var op = this.originalPositions[i];
+          var k2v = this.k2Velocities[i];
+          p.position.set(op.x + k2v.x * 0.5 * dt, op.y + k2v.y * 0.5 * dt);
+
+          var ov = this.originalVelocities[i];
+          var k2f = this.k2Forces[i];
+          p.velocity.set(ov.x + k2f.x * 0.5 * dt / p.mass, ov.y + k2f.y * 0.5 * dt / p.mass);
+        }
+      }, this);
+
+      s.applyForces();
+
+      _.each(s.particles, function(p, i) {
+        if (!p.fixed) {
+          this.k3Forces[i].copy(p.force);
+          this.k3Velocities[i].copy(p.velocity);
+        }
+        p.force.clear();
+      }, this);
+
+      // K4
+
+      _.each(s.particles, function(p, i) {
+        if (!p.fixed) {
+
+          var op = this.originalPositions[i];
+          var k3v = this.k3Velocities[i];
+          p.position.set(op.x + k3v.x * dt, op.y + k3v.y * dt)
+
+          var ov = this.originalVelocities[i];
+          var k3f = this.k3Forces[i];
+          p.velocity.set(ov.x + k3f.x * dt / p.mass, ov.y + k3f.y * dt / p.mass);
+        }
+      }, this);
+
+      s.applyForces();
+
+      _.each(s.particles, function(p, i) {
+        if (!p.fixed) {
+          this.k4Forces[i].copy(p.force);
+          this.k4Velocities[i].copy(p.velocity);
+        }
+      }, this);
+
+      // TOTAL
+
+      _.each(s.particles, function(p, i) {
+
+        p.age += dt;
+
+        if (!p.fixed) {
+
+          var op = this.originalPositions[i];
+          var k1v = this.k1Velocities[i];
+          var k2v = this.k2Velocities[i];
+          var k3v = this.k3Velocities[i];
+          var k4v = this.k4Velocities[i];
+
+          var x = op.x + dt / 6.0 * (k1v.x + 2.0 * k2v.x + 2.0 * k3v.x + k4v.x);
+          var y = op.y + dt / 6.0 * (k1v.y + 2.0 * k2v.y + 2.0 * k3v.y + k4v.y);
+
+          p.position.set(x, y);
+
+          var ov = this.originalVelocities[i];
+          var k1f = this.k1Forces[i];
+          var k2f = this.k2Forces[i];
+          var k3f = this.k3Forces[i];
+          var k4f = this.k4Forces[i];
+
+          x = ov.x + dt / (6.0 * p.mass) * (k1f.x + 2.0 * k2f.x + 2.0 * k3f.x + k4f.x);
+          y = ov.y + dt / (6.0 * p.mass) * (k1f.y + 2.0 * k2f.y + 2.0 * k3f.y + k4f.y);
+
+          p.velocity.set(x, y);
+
+        }
+
+      }, this);
+
+      return this;
+
+    }
+
+  });
+
+  module.exports = Integrator;
+
+},{"./common":8,"./vector":12}],3:[function(require,module,exports){
+var _      = require('./common')
+,   Vector = require('./vector')
+;
+
+  function Particle(mass) {
+
+    this.position = new Vector();
+    this.velocity = new Vector();
+    this.force = new Vector();
+    this.mass = mass;
+    this.fixed = false;
+    this.age = 0;
+    this.dead = false;
+
+  }
+
+  _.extend(Particle.prototype, {
+
+    /**
+     * Get the distance between two particles.
+     */
+    distanceTo: function(p) {
+      return this.position.distanceTo(p.position);
+    },
+
+    /**
+     * Make the particle fixed in 2D space.
+     */
+    makeFixed: function() {
+      this.fixed = true;
+      this.velocity.clear();
+      return this;
+    },
+
+    /**
+     * Reset a particle.
+     */
+    reset: function() {
+
+      this.age = 0;
+      this.dead = false;
+      this.position.clear();
+      this.velocity.clear();
+      this.force.clear();
+      this.mass = 1.0;
+
+      return this;
+    },
+
+    /**
+     * Returns a boolean describing whether the particle is in movement.
+     */
+    resting: function() {
+      return this.fixed || this.velocity.isZero() && this.force.isZero();
+    }
+
+  });
+
+  module.exports = Particle;
+
+},{"./common":8,"./vector":12}],4:[function(require,module,exports){
+var _          = require('./common')
+,   Vector     = require('./Vector')
+,   Particle   = require('./Particle')
+,   Spring     = require('./Spring')
+,   Attraction = require('./Attraction')
+,   Integrator = require('./Integrator')
+;
+
+  /**
+   * traer.js
+   * A particle-based physics engine ported from Jeff Traer's Processing
+   * library to JavaScript. This version is intended for use with the
+   * HTML5 canvas element. It is dependent on Three.js' Vector2 class,
+   * but can be overridden with any Vector2 class with the methods included.
+   *
+   * @author Jeffrey Traer Bernstein <jeff TA traer TOD cc> (original Java library)
+   * @author Adam Saponara <saponara TA gmail TOD com> (JavaScript port)
+   * @author Jono Brandel <http://jonobr1.com/> (requirified/optimization port)
+   * @author David Schoonover <http://less.ly> (Node/CommonJS/Browserify port)
+   *
+   * @version 0.3
+   * @date March 25, 2012
+   */
+
+  /**
+   * The whole kit and kaboodle.
+   *
+   * @class
+   */
+  function ParticleSystem() {
+
+    this.__equilibriumCriteria = { particles: true, springs: true, attractions: true };
+    this.__equilibrium = false; // are we at equilibrium?
+    this.__optimized = false;
+
+    this.particles = [];
+    this.springs = [];
+    this.attractions = [];
+    this.forces = [];
+    this.integrator = new Integrator(this);
+    this.hasDeadParticles = false;
+
+    var args = arguments.length;
+
+    if (args === 1) {
+      this.gravity = new Vector(0, arguments[0]);
+      this.drag = ParticleSystem.DEFAULT_DRAG;
+    } else if (args === 2) {
+      this.gravity = new Vector(0, arguments[0]);
+      this.drag = arguments[1];
+    } else if (args === 3) {
+      this.gravity = new Vector(arguments[0], arguments[1]);
+      this.drag = arguments[3];
+    } else {
+      this.gravity = new Vector(0, ParticleSystem.DEFAULT_GRAVITY);
+      this.drag = ParticleSystem.DEFAULT_DRAG;
+    }
+
+  }
+
+  _.extend(ParticleSystem, {
+
+    DEFAULT_GRAVITY: 0,
+
+    DEFAULT_DRAG: 0.001,
+
+    Attraction: Attraction,
+
+    Integrator: Integrator,
+
+    Particle: Particle,
+
+    Spring: Spring,
+
+    Vector: Vector
+
+  });
+
+  _.extend(ParticleSystem.prototype, {
+
+    /**
+     * Set whether to optimize the simulation. This enables the check of whether
+     * particles are moving.
+     */
+    optimize: function(b) {
+      this.__optimized = !!b;
+      return this;
+    },
+
+    /**
+     * Set the gravity of the ParticleSystem.
+     */
+    setGravity: function(x, y) {
+      this.gravity.set(x, y);
+      return this;
+    },
+
+    /**
+    * Sets the criteria for equilibrium
+    */
+    setEquilibriumCriteria: function(particles, springs, attractions) {
+      this.__equilibriumCriteria.particles = !!particles;
+      this.__equilibriumCriteria.springs = !!springs;
+      this.__equilibriumCriteria.attractions = !!attractions;
+    },
+
+    /**
+     * Update the integrator
+     */
+    tick: function() {
+      this.integrator.step(arguments.length === 0 ? 1 : arguments[0]);
+      if (this.__optimized) {
+        this.__equilibrium = !this.needsUpdate();
+      }
+      return this;
+    },
+
+    /**
+     * Checks all springs and attractions to see if the contained particles are
+     * inert / resting and returns a boolean.
+     */
+    needsUpdate: function() {
+      var i = 0;
+
+      if(this.__equilibriumCriteria.particles) {
+        for (i = 0, l = this.particles.length; i < l; i++) {
+          if (!this.particles[i].resting()) {
+            return true;
+          }
+        }
+      }
+
+      if(this.__equilibriumCriteria.springs) {
+        for (i = 0, l = this.springs.length; i < l; i++) {
+          if (!this.springs[i].resting()) {
+            return true;
+          }
+        }
+      }
+
+      if(this.__equilibriumCriteria.attractions) {
+        for (i = 0, l = this.attractions.length; i < l; i++) {
+          if (!this.attractions[i].resting()) {
+            return true;
+          }
+        }
+      }
+
+      return false;
+
+    },
+
+    /**
+     * Add a particle to the ParticleSystem.
+     */
+    addParticle: function(p) {
+
+      this.particles.push(p);
+      return this;
+
+    },
+
+    /**
+     * Add a spring to the ParticleSystem.
+     */
+    addSpring: function(s) {
+
+      this.springs.push(s);
+      return this;
+
+    },
+
+    /**
+     * Add an attraction to the ParticleSystem.
+     */
+    addAttraction: function(a) {
+
+      this.attractions.push(a);
+      return this;
+
+    },
+
+    /**
+     * Makes and then adds Particle to ParticleSystem.
+     */
+    makeParticle: function(m, x, y) {
+
+      var mass = _.isNumber(m) ? m : 1.0;
+      var x = x || 0;
+      var y = y || 0;
+
+      var p = new Particle(mass);
+      p.position.set(x, y);
+      this.addParticle(p);
+      return p;
+
+    },
+
+    /**
+     * Makes and then adds Spring to ParticleSystem.
+     */
+    makeSpring: function(a, b, k, d, l) {
+
+      var s = new Spring(a, b, k, d, l);
+      this.addSpring(s);
+      return s;
+
+    },
+
+    /**
+     * Makes and then adds Attraction to ParticleSystem.
+     */
+    makeAttraction: function(a, b, k, d) {
+
+      var a = new Attraction(a, b, k, d);
+      this.addAttraction(a);
+      return a;
+
+    },
+
+    /**
+     * Wipe the ParticleSystem clean.
+     */
+    clear: function() {
+
+      this.particles.length = 0;
+      this.springs.length = 0;
+      this.attractions.length = 0;
+
+    },
+
+    /**
+     * Calculate and apply forces.
+     */
+    applyForces: function() {
+
+      if (!this.gravity.isZero()) {
+        _.each(this.particles, function(p) {
+          p.force.addSelf(this.gravity);
+        }, this);
+      }
+
+      var t = new Vector();
+
+      _.each(this.particles, function(p) {
+        t.set(p.velocity.x * -1 * this.drag, p.velocity.y * -1 * this.drag);
+        p.force.addSelf(t);
+      }, this);
+
+      _.each(this.springs, function(s) {
+        s.update();
+      });
+
+      _.each(this.attractions, function(a) {
+        a.update();
+      });
+
+      _.each(this.forces, function(f) {
+        f.update();
+      });
+
+      return this;
+
+    },
+
+    /**
+     * Clear all particles in the system.
+     */
+    clearForces: function() {
+      _.each(this.particles, function(p) {
+        p.clear();
+      });
+      return this;
+    }
+
+  });
+
+  module.exports = ParticleSystem;
+
+},{"./Attraction":1,"./Integrator":2,"./Particle":3,"./Spring":6,"./Vector":7,"./common":8}],5:[function(require,module,exports){
+var _              = require('./common')
+,   raf            = require('./requestAnimationFrame')
+,   ParticleSystem = require('./ParticleSystem')
+;
+
+  var updates = [];
+
+  /**
+   * Extended singleton instance of ParticleSystem with convenience methods for
+   * Request Animation Frame.
+   * @class
+   */
+  function Physics() {
+
+    var _this = this;
+
+    this.playing = false;
+
+    ParticleSystem.apply(this, arguments);
+
+    this.animations = [];
+
+    this.equilibriumCallbacks = [];
+
+    update.call(this);
+
+  }
+
+  _.extend(Physics, ParticleSystem, {
+
+    superclass: ParticleSystem
+
+  });
+
+  _.extend(Physics.prototype, ParticleSystem.prototype, {
+
+    /**
+     * Play the animation loop. Doesn't affect whether in equilibrium or not.
+     */
+    play: function() {
+
+      if (this.playing) {
+        return this;
+      }
+
+      this.playing = true;
+      this.__equilibrium = false;
+      update.call(this);
+
+      return this;
+
+    },
+
+    /**
+     * Pause the animation loop. Doesn't affect whether in equilibrium or not.
+     */
+    pause: function() {
+
+      this.playing = false;
+      return this;
+
+    },
+
+    /**
+     * Toggle between playing and pausing the simulation.
+     */
+    toggle: function() {
+
+      if (this.playing) {
+        this.pause();
+      } else {
+        this.play();
+      }
+
+      return this;
+
+    },
+
+    onUpdate: function(func) {
+
+      if (_.indexOf(this.animations, func) >= 0 || !_.isFunction(func)) {
+        return this;
+      }
+
+      this.animations.push(func);
+
+      return this;
+
+    },
+
+    onEquilibrium: function(func) {
+
+      if (_.indexOf(this.equilibriumCallbacks, func) >= 0 || !_.isFunction(func)) {
+        return this;
+      }
+
+      this.equilibriumCallbacks.push(func);
+
+      return this;
+
+    },
+
+    /**
+     * Call update after values in the system have changed and this will fire
+     * it's own Request Animation Frame to update until things have settled
+     * to equilibrium — at which point the system will stop updating.
+     */
+    update: function() {
+
+      if (!this.__equilibrium) {
+        return this;
+      }
+
+      this.__equilibrium = false;
+      if (this.playing) {
+        update.call(this);
+      }
+
+      return this;
+
+    }
+
+  });
+
+  function update() {
+
+    var _this = this;
+
+    this.tick();
+
+    _.each(this.animations, function(a) {
+      a();
+    });
+
+    if ((this.__optimized && !this.__equilibrium || !this.__optimized) && this.playing) {
+
+      raf(function() {
+        update.call(_this);
+      });
+
+    }
+
+    if (this.__optimized && this.__equilibrium){
+
+      _.each(this.equilibriumCallbacks, function(a) {
+        a();
+      });
+
+    }
+
+  }
+
+  module.exports = Physics;
+
+
+},{"./ParticleSystem":4,"./common":8,"./requestAnimationFrame":11}],6:[function(require,module,exports){
+var _      = require('./common')
+,   Vector = require('./vector')
+;
+
+  function Spring(a, b, k, d, l) {
+
+    this.constant = k;
+    this.damping = d;
+    this.length = l;
+    this.a = a;
+    this.b = b;
+    this.on = true;
+
+  }
+
+  _.extend(Spring.prototype, {
+
+    /**
+     * Returns the distance between particle a and particle b
+     * in 2D space.
+     */
+    currentLength: function() {
+      return this.a.position.distanceTo(this.b.position);
+    },
+
+    /**
+     * Update spring logic.
+     */
+    update: function() {
+
+      var a = this.a;
+      var b = this.b;
+      if (!(this.on && (!a.fixed || !b.fixed))) return this;
+
+      var a2b = new Vector().sub(a.position, b.position);
+      var d = a2b.length();
+
+      if (d === 0) {
+        a2b.clear();
+      } else {
+        a2b.divideScalar(d);  // Essentially normalize
+      }
+
+      var fspring = -1 * (d - this.length) * this.constant;
+
+      var va2b = new Vector().sub(a.velocity, b.velocity);
+
+      var fdamping = -1 * this.damping * va2b.dot(a2b);
+
+      var fr = fspring + fdamping;
+
+      a2b.multiplyScalar(fr);
+
+      if (!a.fixed) {
+        a.force.addSelf(a2b);
+      }
+      if (!b.fixed) {
+        b.force.subSelf(a2b);
+      }
+
+      return this;
+
+    },
+
+    /**
+     * Returns a boolean describing whether the spring is resting or not.
+     * Convenient for knowing whether or not the spring needs another update
+     * tick.
+     */
+    resting: function() {
+
+      var a = this.a;
+      var b = this.b;
+      var l = this.length;
+
+      return !this.on || (a.fixed && b.fixed)
+        || (a.fixed && (l === 0 ? b.position.equals(a.position) : b.position.distanceTo(a.position) <= l) && b.resting())
+        || (b.fixed && (l === 0 ? a.position.equals(b.position) : a.position.distanceTo(b.position) <= l) && a.resting());
+
+    }
+
+  });
+
+  module.exports = Spring;
+
+
+},{"./common":8,"./vector":12}],7:[function(require,module,exports){
+/**
+ * @author mr.doob / http://mrdoob.com/
+ * @author philogb / http://blog.thejit.org/
+ * @author egraether / http://egraether.com/
+ * @author zz85 / http://www.lab4games.net/zz85/blog
+ * @author jonobr1 / http://jonobr1.com/
+ */
+
+var _ = require('./common');
+
+  /**
+   * A two dimensional vector.
+   */
+  function Vector(x, y) {
+
+    this.x = x || 0;
+    this.y = y || 0;
+
+  }
+
+  _.extend(Vector.prototype, {
+
+    set: function(x, y) {
+      this.x = x;
+      this.y = y;
+      return this;
+    },
+
+    copy: function(v) {
+      this.x = v.x;
+      this.y = v.y;
+      return this;
+    },
+
+    clear: function() {
+      this.x = 0;
+      this.y = 0;
+      return this;
+    },
+
+    clone: function() {
+      return new Vector(this.x, this.y);
+    },
+
+    add: function(v1, v2) {
+      this.x = v1.x + v2.x;
+      this.y = v1.y + v2.y;
+      return this;
+    },
+
+    addSelf: function(v) {
+      this.x += v.x;
+      this.y += v.y;
+      return this;
+    },
+
+    sub: function(v1, v2) {
+      this.x = v1.x - v2.x;
+      this.y = v1.y - v2.y;
+      return this;
+    },
+
+    subSelf: function(v) {
+      this.x -= v.x;
+      this.y -= v.y;
+      return this;
+    },
+
+    multiplySelf: function(v) {
+      this.x *= v.x;
+      this.y *= v.y;
+      return this;
+    },
+
+    multiplyScalar: function(s) {
+      this.x *= s;
+      this.y *= s;
+      return this;
+    },
+
+    multiplyScalarXY: function(sx,sy) {
+      this.x *= sx;
+      this.y *= sy;
+      return this;
+    },
+
+    divideScalar: function(s) {
+      if (s) {
+        this.x /= s;
+        this.y /= s;
+      } else {
+        this.set(0, 0);
+      }
+      return this;
+    },
+
+    negate: function() {
+      return this.multiplyScalar(-1);
+    },
+
+    dot: function(v) {
+      return this.x * v.x + this.y * v.y;
+    },
+
+    lengthSquared: function() {
+      return this.x * this.x + this.y * this.y;
+    },
+
+    length: function() {
+      return Math.sqrt(this.lengthSquared());
+    },
+
+    normalize: function() {
+      return this.divideScalar(this.length());
+    },
+
+    distanceTo: function(v) {
+      return Math.sqrt(this.distanceToSquared(v));
+    },
+
+    distanceToSquared: function(v) {
+      var dx = this.x - v.x, dy = this.y - v.y;
+      return dx * dx + dy * dy;
+    },
+
+    setLength: function(l) {
+      return this.normalize().multiplyScalar(l);
+    },
+
+    equals: function(v) {
+      return (this.distanceTo(v) < 0.0001 /* almost same position */);
+    },
+
+    lerp: function(v, t) {
+      var x = (v.x - this.x) * t + this.x;
+      var y = (v.y - this.y) * t + this.y;
+      return this.set(x, y);
+    },
+
+    isZero: function() {
+      return (this.length() < 0.0001 /* almost zero */ );
+    }
+
+  });
+
+  module.exports = Vector;
+
+},{"./common":8}],8:[function(require,module,exports){
+
+  /**
+   * Pulled only what's needed from:
+   *
+   * Underscore.js 1.3.3
+   * (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
+   * http://documentcloud.github.com/underscore
+   */
+
+  var breaker = {};
+  var ArrayProto = Array.prototype;
+  var ObjProto = Object.prototype;
+  var hasOwnProperty = ObjProto.hasOwnProperty;
+  var slice = ArrayProto.slice;
+  var nativeForEach = ArrayProto.forEach;
+  var nativeIndexOf      = ArrayProto.indexOf;
+  var toString = ObjProto.toString;
+
+  var has = function(obj, key) {
+    return hasOwnProperty.call(obj, key);
+  };
+
+  var each = function(obj, iterator, context) {
+
+    if (obj == null) return;
+        if (nativeForEach && obj.forEach === nativeForEach) {
+          obj.forEach(iterator, context);
+        } else if (obj.length === +obj.length) {
+          for (var i = 0, l = obj.length; i < l; i++) {
+            if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return;
+          }
+        } else {
+          for (var key in obj) {
+            if (_.has(obj, key)) {
+              if (iterator.call(context, obj[key], key, obj) === breaker) return;
+            }
+          }
+        }
+
+  };
+
+  var identity = function(value) {
+    return value;
+  };
+
+  var sortedIndex = function(array, obj, iterator) {
+    iterator || (iterator = identity);
+    var low = 0, high = array.length;
+    while (low < high) {
+      var mid = (low + high) >> 1;
+      iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid;
+    }
+    return low;
+  };
+
+  module.exports = {
+
+    has: has,
+
+    each: each,
+
+    extend: function(obj) {
+      each(slice.call(arguments, 1), function(source) {
+        for (var prop in source) {
+          obj[prop] = source[prop];
+        }
+      });
+      return obj;
+    },
+
+    indexOf: function(array, item, isSorted) {
+      if (array == null) return -1;
+      var i, l;
+      if (isSorted) {
+        i = sortedIndex(array, item);
+        return array[i] === item ? i : -1;
+      }
+      if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
+      for (i = 0, l = array.length; i < l; i++) if (i in array && array[i] === item) return i;
+      return -1;
+    },
+
+    sortedIndex: sortedIndex,
+
+    identity: identity,
+
+    isNumber: function(obj) {
+      return toString.call(obj) == '[object Number]';
+    },
+
+    isFunction: function(obj) {
+      return toString.call(obj) == '[object Function]' || typeof obj == 'function';
+    },
+
+    isUndefined: function(obj) {
+      return obj === void 0;
+    },
+
+    isNull: function(obj) {
+      return obj === null;
+    }
+
+  };
+
+
+},{}],"H99CHA":[function(require,module,exports){
+var root = (function(){ return this; })()
+,   previousShortcut = root.Physics
+;
+
+module.exports = root.Physics = require('./Physics');
+
+},{"./Physics":5}],"physics":[function(require,module,exports){
+module.exports=require('H99CHA');
+},{}],11:[function(require,module,exports){
+  /*
+   * Requirified version of Paul Irish's request animation frame.
+   * http://paulirish.com/2011/requestanimationframe-for-smart-animating/
+   */
+module.exports =
+          window.requestAnimationFrame       ||
+          window.webkitRequestAnimationFrame ||
+          window.mozRequestAnimationFrame    ||
+          window.oRequestAnimationFrame      ||
+          window.msRequestAnimationFrame     ||
+          function (callback) {
+            window.setTimeout(callback, 1000 / 60);
+          };
+
+},{}],12:[function(require,module,exports){
+module.exports=require(7)
+},{"./common":8}]},{},["H99CHA"])

+ 0 - 11963
sites/all/modules/figli/edlp_corpus/assets/dist/bower/physicsjs-full.js

@@ -1,11963 +0,0 @@
-/**
- * PhysicsJS v0.7.0 - 2014-12-08
- * A modular, extendable, and easy-to-use physics engine for javascript
- * http://wellcaffeinated.net/PhysicsJS
- *
- * Copyright (c) 2014 Jasper Palfree <jasper@wellcaffeinated.net>
- * Licensed MIT
- */
-
-// ---
-// inside: src/intro.js
-
-(function (root, factory) {
-    if (typeof exports === 'object') {
-        // Node.
-        module.exports = factory.call(root);
-    } else if (typeof define === 'function' && define.amd) {
-        // AMD. Register as an anonymous module.
-        define(function(){ return factory.call(root) });
-    } else {
-        // Browser globals (root is window)
-        root.Physics = factory.call(root);
-    }
-}(typeof window !== 'undefined' ? window : this, function () {
-
-'use strict';
-
-var window = this;
-var document = window.document;
-
-/** related to: Physics.world
- * Physics
- *
- * The top-level namespace. All of PhysicsJS is contained in
- * the `Physics` namespace.
- *
- * It may (and should) be invoked as a function to create a world instance. For all intensive purposes, [[Physics]] and [[Physics.world]] are the same thing.
- *
- * See [[new Physics.world]] for config options and function signature.
- *
- * Example:
- *
- * ```javascript
- * Physics( cfg, function( world ) {
- *     // use world
- * }); // -> world
- * ```
- **/
-var Physics = function Physics(){
-
-    return Physics.world.apply(Physics, arguments);
-};
-
-/**
- * Physics.util
- *
- * Namespace for utility functions.
- **/
-Physics.util = {};
-
-/**
- * == Special ==
- *
- * This section contains miscellaneous functionality.
- **/
-
-
-// ---
-// inside: src/math/aabb.js
-
-(function(){
-
-    /**
-     * Physics.aabb( minX, minY, maxX, maxY ) -> Object
-     * Physics.aabb( pt1, pt2 ) -> Object
-     * Physics.aabb( width, height[, pt] ) -> Object
-     * - minX (Number): The x coord of the "top left" point
-     * - minY (Number): The y coord of the "top left" point
-     * - maxX (Number): The x coord of the "bottom right" point
-     * - maxY (Number): The y coord of the "bottom right" point
-     * - pt1 (Vectorish): The first corner
-     * - pt2 (Vectorish): The opposite corner
-     * - width (Number): The width of the bounding box
-     * - height (Number): The height of the bounding box
-     * - pt (Vectorish): The center point of the bounding box
-     *
-     * Create an Axis Aligned Bounding Box.
-     *
-     * Signature:
-     *
-     * ```javascript
-     * {
-     *     x: Number, // the x coord of the center point
-     *     y: Number, // the y coord of the center point
-     *     hw: Number, // the half-width
-     *     hh: Number, // the half-height
-     * }
-     * ```
-     **/
-    Physics.aabb = function( minX, minY, maxX, maxY ){
-
-        var aabb = { x: 0, y: 0, hw: 0, hh: 0 };
-
-        if ( minX === undefined ){
-            return aabb;
-        }
-
-        if ( minX && minX.x !== undefined ){
-            // we have a point specified as first arg
-            maxX = minY.x;
-            maxY = minY.y;
-            minY = minX.y;
-            minX = minX.x;
-        }
-
-        if ( maxY === undefined && minX !== undefined && minY !== undefined ){
-
-            aabb.hw = minX * 0.5;
-            aabb.hh = minY * 0.5;
-
-            if ( maxX && maxX.x !== undefined ){
-                // we have a point specified as the third arg
-                // so we assume it's the center point
-                aabb.x = maxX.x;
-                aabb.y = maxX.y;
-            }
-
-            return aabb;
-        }
-
-        // here, we should have all the arguments as numbers
-        aabb.hw = Math.abs(maxX - minX) * 0.5;
-        aabb.hh = Math.abs(maxY - minY) * 0.5;
-        aabb.x = (maxX + minX) * 0.5;
-        aabb.y = (maxY + minY) * 0.5;
-
-        return aabb;
-    };
-
-    /**
-     * Physics.aabb.contains( aabb, pt ) -> Boolean
-     * - aabb (Object): The aabb
-     * - pt (Vectorish): The point
-     * + (Boolean): `true` if `pt` is inside `aabb`, `false` otherwise
-     *
-     * Check if a point is inside an aabb.
-     **/
-    Physics.aabb.contains = function contains( aabb, pt ){
-
-        return  (pt.x > (aabb.x - aabb.hw)) &&
-                (pt.x < (aabb.x + aabb.hw)) &&
-                (pt.y > (aabb.y - aabb.hh)) &&
-                (pt.y < (aabb.y + aabb.hh));
-    };
-
-    /**
-     * Physics.aabb.clone( aabb ) -> Object
-     * - aabb (Object): The aabb to clone
-     * + (Object): The clone
-     *
-     * Clone an aabb.
-     **/
-    Physics.aabb.clone = function( aabb ){
-        return {
-            x: aabb.x,
-            y: aabb.y,
-            hw: aabb.hw,
-            hh: aabb.hh
-        };
-    };
-
-    /**
-     * Physics.aabb.union( aabb1, aabb2[, modify] ) -> Object
-     * - aabb1 (Object): The first aabb (returned if modify is `true`)
-     * - aabb2 (Object): The second aabb
-     * + (Object): The union of two aabbs. If modify is `true`, then the first aabb will be modified and returned.
-     *
-     * Get the union of two aabbs.
-     **/
-    Physics.aabb.union = function( aabb1, aabb2, modify ){
-
-        var ret = modify === true ? aabb1 : {}
-            ,maxX = Math.max( aabb1.x + aabb1.hw, aabb2.x + aabb2.hw )
-            ,maxY = Math.max( aabb1.y + aabb1.hh, aabb2.y + aabb2.hh )
-            ,minX = Math.min( aabb1.x - aabb1.hw, aabb2.x - aabb2.hw )
-            ,minY = Math.min( aabb1.y - aabb1.hh, aabb2.y - aabb2.hh )
-            ;
-
-        ret.hw = Math.abs(maxX - minX) * 0.5;
-        ret.hh = Math.abs(maxY - minY) * 0.5;
-        ret.x = (maxX + minX) * 0.5;
-        ret.y = (maxY + minY) * 0.5;
-
-        return ret;
-    };
-
-
-    /**
-     * Physics.aabb.overlap( aabb1, aabb2 ) -> Boolean
-     * - aabb1 (Object): The first aabb
-     * - aabb2 (Object): The second aabb
-     * + (Boolean): `true` if they overlap, `false` otherwise
-     *
-     * Check if two AABBs overlap.
-     **/
-    Physics.aabb.overlap = function( aabb1, aabb2 ){
-
-        var min1 = aabb1.x - aabb1.hw
-            ,min2 = aabb2.x - aabb2.hw
-            ,max1 = aabb1.x + aabb1.hw
-            ,max2 = aabb2.x + aabb2.hw
-            ;
-
-        // first check x-axis
-
-        if ( (min2 <= max1 && max1 <= max2) || (min1 <= max2 && max2 <= max1) ){
-            // overlap in x-axis
-            // check y...
-            min1 = aabb1.y - aabb1.hh;
-            min2 = aabb2.y - aabb2.hh;
-            max1 = aabb1.y + aabb1.hh;
-            max2 = aabb2.y + aabb2.hh;
-
-            return (min2 <= max1 && max1 <= max2) || (min1 <= max2 && max2 <= max1);
-        }
-
-        // they don't overlap
-        return false;
-    };
-
-}());
-
-
-// ---
-// inside: src/math/gjk.js
-
-(function(){
-
-    // the algorithm doesn't always converge for curved shapes.
-    // need these constants to dictate how accurate we want to be.
-    var gjkAccuracy = 0.0001;
-    var gjkMaxIterations = 100;
-
-    // get the next search direction from two simplex points
-    var getNextSearchDir = function getNextSearchDir( ptA, ptB, dir ){
-
-        var ABdotB = ptB.normSq() - ptB.dot( ptA )
-            ,ABdotA = ptB.dot( ptA ) - ptA.normSq()
-            ;
-
-        // if the origin is farther than either of these points
-        // get the direction from one of those points to the origin
-        if ( ABdotB < 0 ){
-
-            return dir.clone( ptB ).negate();
-
-        } else if ( ABdotA > 0 ){
-
-            return dir.clone( ptA ).negate();
-
-        // otherwise, use the perpendicular direction from the simplex
-        } else {
-
-            // dir = AB = B - A
-            dir.clone( ptB ).vsub( ptA );
-            // if (left handed coordinate system)
-            // A cross AB < 0 then get perpendicular counterclockwise
-            return dir.perp( (ptA.cross( dir ) > 0) );
-        }
-    };
-
-    /** hide
-     * getClosestPoints( simplex ) -> Object
-     * - simplex (Array): The simplex
-     *
-     * Figure out the closest points on the original objects
-     * from the last two entries of the simplex
-     **/
-    var getClosestPoints = function getClosestPoints( simplex ){
-
-        // see http://www.codezealot.org/archives/153
-        // for algorithm details
-
-        // we know that the position of the last point
-        // is very close to the previous. (by nature of the distance test)
-        // this won't give great results for the closest
-        // points algorithm, so let's use the previous two
-        var len = simplex.length
-            ,last = simplex[ len - 2 ]
-            ,prev = simplex[ len - 3 ]
-            ,scratch = Physics.scratchpad()
-            ,A = scratch.vector().clone( last.pt )
-            // L = B - A
-            ,L = scratch.vector().clone( prev.pt ).vsub( A )
-            ,lambdaB
-            ,lambdaA
-            ;
-
-        if ( L.equals(Physics.vector.zero) ){
-
-            // oh.. it's a zero vector. So A and B are both the closest.
-            // just use one of them
-            return scratch.done({
-
-                a: last.a,
-                b: last.b
-            });
-        }
-
-        lambdaB = - L.dot( A ) / L.normSq();
-        lambdaA = 1 - lambdaB;
-
-        if ( lambdaA <= 0 ){
-            // woops.. that means the closest simplex point
-            // isn't on the line it's point B itself
-            return scratch.done({
-                a: prev.a,
-                b: prev.b
-            });
-        } else if ( lambdaB <= 0 ){
-            // vice versa
-            return scratch.done({
-                a: last.a,
-                b: last.b
-            });
-        }
-
-        // guess we'd better do the math now...
-        return scratch.done({
-            // a closest = lambdaA * Aa + lambdaB * Ba
-            a: A.clone( last.a ).mult( lambdaA ).vadd( L.clone( prev.a ).mult( lambdaB ) ).values(),
-            // b closest = lambdaA * Ab + lambdaB * Bb
-            b: A.clone( last.b ).mult( lambdaA ).vadd( L.clone( prev.b ).mult( lambdaB ) ).values()
-        });
-    };
-
-    /**
-     * Physics.gjk( support(axis)[, seed, checkOverlapOnly, debugFn] ) -> Object
-     * - support (Function): The support function. Must return an object containing
-       the witness points (`.a`, `.b`) and the support point (`.pt`).
-       Recommended to use simple objects.
-       Eg:
-       ```javascript
-       return {
-            a: { x: 1, y:2 },
-            b: { x: 3, y: 4 },
-            pt: { x: 2, y: 2 }
-       };
-       ```
-     * - axis (Physics.vector): The axis to search
-     * - seed (Physics.vector): The starting direction for the simplex (defaults to x-axis)
-     * - checkOverlapOnly (Boolean): only check whether there is an overlap, don't calculate the depth
-     * - debugFn (Function): For debugging. Called at every iteration with the current simplex.
-     *
-     * Implementation agnostic GJK function.
-     *
-     * Gilbert–Johnson–Keerthi object collison algorithm
-     * For general information about GJK see:
-     * - [www.codezealot.org/archives/88](http://www.codezealot.org/archives/88)
-     * - [mollyrocket.com/849](http://mollyrocket.com/849)
-     *
-     * The algorithm information returned:
-     * ```javascript
-     * {
-     *     overlap: Boolean,
-     *     simplex: [] // array containing simplex points as simple x/y objects
-     * }
-     * ```
-     **/
-    var gjk = function gjk( support, seed, checkOverlapOnly, debugFn ){
-
-        var overlap = false
-            ,noOverlap = false // if we're sure we're not overlapping
-            ,distance = false
-            ,simplex = []
-            ,simplexLen = 1
-            // setup a scratchpad of temporary cheap objects
-            ,scratch = Physics.scratchpad()
-            // use seed as starting direction or use x axis
-            ,dir = scratch.vector().clone(seed || Physics.vector.axis[ 0 ])
-            ,last = scratch.vector()
-            ,lastlast = scratch.vector()
-            // some temp vectors
-            ,v1 = scratch.vector()
-            ,v2 = scratch.vector()
-            ,ab
-            ,ac
-            ,sign
-            ,tmp
-            ,iterations = 0
-            ;
-
-        // get the first Minkowski Difference point
-        tmp = support( dir );
-        simplexLen = simplex.push( tmp );
-        last.clone( tmp.pt );
-        // negate d for the next point
-        dir.negate();
-
-        // start looping
-        while ( ++iterations ) {
-
-            // swap last and lastlast, to save on memory/speed
-            last.swap(lastlast);
-            // push a new point to the simplex because we haven't terminated yet
-            tmp = support( dir );
-            simplexLen = simplex.push( tmp );
-            last.clone( tmp.pt );
-
-            if ( debugFn ){
-                debugFn( simplex );
-            }
-
-            if ( last.equals(Physics.vector.zero) ){
-                // we happened to pick the origin as a support point... lucky.
-                overlap = true;
-                break;
-            }
-
-            // check if the last point we added actually passed the origin
-            if ( !noOverlap && last.dot( dir ) <= 0.0 ) {
-                // if the point added last was not past the origin in the direction of d
-                // then the Minkowski difference cannot possibly contain the origin since
-                // the last point added is on the edge of the Minkowski Difference
-
-                // if we just need the overlap...
-                if ( checkOverlapOnly ){
-                    break;
-                }
-
-                noOverlap = true;
-            }
-
-            // if it's a line...
-            if ( simplexLen === 2 ){
-
-                // otherwise we need to determine if the origin is in
-                // the current simplex and act accordingly
-
-                dir = getNextSearchDir( last, lastlast, dir );
-                // continue...
-
-            // if it's a triangle... and we're looking for the distance
-            } else if ( noOverlap ){
-
-                // if we know there isn't any overlap and
-                // we're just trying to find the distance...
-                // make sure we're getting closer to the origin
-                dir.normalize();
-                tmp = lastlast.dot( dir );
-                if ( Math.abs(tmp - last.dot( dir )) < gjkAccuracy ){
-
-                    distance = -tmp;
-                    break;
-                }
-
-                // if we are still getting closer then only keep
-                // the points in the simplex that are closest to
-                // the origin (we already know that last is closer
-                // than the previous two)
-                // the norm is the same as distance(origin, a)
-                // use norm squared to avoid the sqrt operations
-                if (lastlast.normSq() < v1.clone(simplex[ 0 ].pt).normSq()) {
-
-                    simplex.shift();
-
-                } else {
-
-                    simplex.splice(1, 1);
-                }
-
-                dir = getNextSearchDir( v1.clone(simplex[ 1 ].pt), v2.clone(simplex[ 0 ].pt), dir );
-                // continue...
-
-            // if it's a triangle
-            } else {
-
-                // we need to trim the useless point...
-
-                ab = ab || scratch.vector();
-                ac = ac || scratch.vector();
-
-                // get the edges AB and AC
-                ab.clone( lastlast ).vsub( last );
-                ac.clone( simplex[ 0 ].pt ).vsub( last );
-
-                // here normally people think about this as getting outward facing
-                // normals and checking dot products. Since we're in 2D
-                // we can be clever...
-                sign = ab.cross( ac ) > 0;
-
-                if ( sign ^ (last.cross( ab ) > 0) ){
-
-                    // ok... so there's an XOR here... don't freak out
-                    // remember last = A = -AO
-                    // if AB cross AC and AO cross AB have the same sign
-                    // then the origin is along the outward facing normal of AB
-                    // so if AB cross AC and A cross AB have _different_ (XOR) signs
-                    // then this is also the case... so we proceed...
-
-                    // point C is dead to us now...
-                    simplex.shift();
-
-                    // if we haven't deduced that we've enclosed the origin
-                    // then we know which way to look...
-                    // morph the ab vector into its outward facing normal
-                    ab.perp( !sign );
-
-                    // swap
-                    dir.swap( ab );
-
-                    // continue...
-
-                    // if we get to this if, then it means we can continue to look along
-                    // the other outward normal direction (ACperp)
-                    // if we don't see the origin... then we must have it enclosed
-                } else if ( sign ^ (ac.cross( last ) > 0) ){
-                    // then the origin is along the outward facing normal
-                    // of AC; (ACperp)
-
-                    // point B is dead to us now...
-                    simplex.splice(1, 1);
-
-                    ac.perp( sign );
-
-                    // swap
-                    dir.swap( ab );
-
-                    // continue...
-
-                } else {
-
-                    // we have enclosed the origin!
-                    overlap = true;
-                    // fewf... take a break
-                    break;
-                }
-            }
-
-            // woah nelly... that's a lot of iterations.
-            // Stop it!
-            if (iterations > gjkMaxIterations){
-                scratch.done();
-                return {
-                    simplex: simplex,
-                    iterations: iterations,
-                    distance: 0,
-                    maxIterationsReached: true
-                };
-            }
-        }
-
-        // free workspace
-        scratch.done();
-
-        tmp = {
-            overlap: overlap,
-            simplex: simplex,
-            iterations: iterations
-        };
-
-        if ( distance !== false ){
-
-            tmp.distance = distance;
-            tmp.closest = getClosestPoints( simplex );
-        }
-
-        return tmp;
-    };
-
-    Physics.gjk = gjk;
-
-})();
-
-
-// ---
-// inside: src/math/statistics.js
-
-(function(){
-
-    Physics.statistics = {
-        /**
-         * Physics.statistics.pushRunningAvg( v, k, m, s ) -> Array
-         * - v (Number): is value to push
-         * - k (Number): is num elements
-         * - m (Number): is current mean
-         * - s (Number): is current s value
-         * + (Array): Returns a 2 element array containing the next mean, and s value
-         *
-         * Push a value to a running average calculation.
-         * see [http://www.johndcook.com/blog/standard_deviation]
-         *
-         * Note: variance can be calculated from the "s" value by multiplying it by `1/(k-1)`
-         **/
-        pushRunningAvg: function( v, k, m, s ){
-
-            var x = v - m;
-
-            // Mk = Mk-1+ (xk – Mk-1)/k
-            // Sk = Sk-1 + (xk – Mk-1)*(xk – Mk).
-            m += x / k;
-            s += x * (v - m);
-            return [m, s];
-        },
-
-        /**
-        * Physics.statistics.pushRunningVectorAvg( v, k, m[, s] )
-        * - v (Physics.vector): is vector to push
-        * - k (Number): is num elements
-        * - m (Physics.vector): is current mean
-        * - s (Physics.vector): is current s value
-        *
-        * Push a vector to a running vector average calculation.
-        * see [http://www.johndcook.com/blog/standard_deviation]
-        *
-        * Calculations are done in place. The `m` and `s` parameters are altered.
-        *
-        * Note: variance can be calculated from the "s" vector by multiplying it by `1/(k-1)`
-        *
-        * If s value is ommitted it won't be used.
-        **/
-        pushRunningVectorAvg: function( v, k, m, s ){
-            var invK = 1/k
-                ,x = v.get(0) - m.get(0)
-                ,y = v.get(1) - m.get(1)
-                ;
-
-            // Mk = Mk-1+ (xk – Mk-1)/k
-            // Sk = Sk-1 + (xk – Mk-1)*(xk – Mk).
-            m.add( x * invK, y * invK );
-
-            if ( s ){
-                x *= v.get(0) - m.get(0);
-                y *= v.get(1) - m.get(1);
-
-                s.add( x, y );
-            }
-        }
-    };
-})();
-
-
-// ---
-// inside: src/math/transform.js
-
-(function(){
-    
-    /**
-     * class Physics.transform
-     * 
-     * Vector Transformations class for rotating and translating vectors
-     **/
-
-    /**
-     * new Physics.transform( [vect, angle, origin] )
-     * new Physics.transform( transform )
-     * - vect (Vectorish): Translation vector
-     * - transform (Physics.transform): Transform to copy
-     * - angle (Number): Angle (radians) to use for rotation
-     * - origin (Vectorish): Origin of the rotation
-     * 
-     * Transform Constructor / Factory
-     **/
-    var Transform = function Transform( vect, angle, origin ) {
-
-        if (!(this instanceof Transform)){
-            return new Transform( vect, angle );
-        }
-
-        this.v = new Physics.vector();
-        this.o = new Physics.vector(); // origin of rotation
-        
-        if ( vect instanceof Transform ){
-
-            this.clone( vect );
-            return;
-        }
-
-        if (vect){
-            this.setTranslation( vect );
-        }
-
-        this.setRotation( angle || 0, origin );
-    };
-
-    /**
-     * Physics.transform#setTranslation( vect ) -> this
-     * - vect (Vectorish): The translation vector
-     * 
-     * Set the translation portion of the transform.
-     **/
-    Transform.prototype.setTranslation = function( vect ){
-
-        this.v.clone( vect );
-        return this;
-    };
-
-    /**
-     * Physics.transform#setRotation( angle[, origin ] ) -> this
-     * - angle (Number): Angle (radians) to use for rotation
-     * - origin (Vectorish): Origin of the rotation
-     *
-     * Set the rotation portion of the transform
-     **/
-    Transform.prototype.setRotation = function( angle, origin ){
-
-        this.cosA = Math.cos( angle );
-        this.sinA = Math.sin( angle );
-
-        if ( origin ){
-            this.o.clone( origin );
-        } else {
-            this.o.zero();
-        }
-
-        return this;
-    };
-
-    /**
-     * Physics.transform#clone( [transform] ) -> this|Physics.transform
-     * - transform (Physics.transform): Transform to copy
-     * + (this): For chaining
-     * + (Physics.transform): New copy of `this` if none is specified as an argument
-     * 
-     * Clone another transform. Or clone self into new transform.
-     **/
-    Transform.prototype.clone = function( t ){
-
-        if ( t ){
-
-            this.setTranslation( t.v );
-            this.cosA = t.cosA;
-            this.sinA = t.sinA;
-            this.o.clone( t.o );
-
-            return this;
-        }
-
-        return new Transform( this );
-    };
-
-    Physics.transform = Transform;
-
-})();
-
-// ---
-// inside: src/math/vector.js
-
-(function(window){
-
-    // http://jsperf.com/vector-storage-test/2
-
-    // cached math functions
-    // TODO: might be faster not to do this???
-    var sqrt = Math.sqrt
-        ,min = Math.min
-        ,max = Math.max
-        ,acos = Math.acos
-        ,atan2 = Math.atan2
-        ,TWOPI = Math.PI * 2
-        ,typedArrays = !!window.Float64Array
-        ;
-
-    /**
-     * class Physics.vector
-     *
-     * The vector class and factory function.
-     *
-     * Call `Physics.vector` with the same arguments as
-     * [[new Physics.vector]] to create an instance.
-     *
-     * The vector methods mostly modify the vector instance.
-     * This makes computations faster because creating vectors
-     * is avoided.
-     *
-     * Creating vectors is generally an expensive operation
-     * so try to avoid doing this in the simulation loop.
-     * Instead you can use [[Physics.scratchpad]] to get
-     * temporary vectors for use in performance critical
-     * code.
-     *
-     * _Note_: The coordinate system is left-handed, meaning that
-     * the clockwise angular direction is positive. This has implications
-     * for the cross-product rule.
-     **/
-
-    /** section: Special
-     * class Vectorish
-     *
-     * Any object with `.x` and `.y` properties.
-     *
-     * A `Vectorish` isn't really a class. In this documentation, when
-     * an argument is specified as a `Vectorish` it means either a true
-     * [[Physics.vector]] instance, or an object literal with `.x` and `.y`
-     * properties.
-     **/
-
-    /**
-     * new Physics.vector( x, y )
-     * new Physics.vector( vect )
-     * - x (Number): The x coordinate
-     * - y (Number): The y coordinate
-     * - vect (Vectorish): A vector-like object to clone
-     *
-     * Vector Constructor.
-     **/
-    var Vector = function Vector( x, y ) {
-
-        // enforce instantiation
-        if ( !(this instanceof Vector) ){
-
-            return new Vector( x, y );
-        }
-
-        // arrays to store values
-        // x = _[0]
-        // y = _[1]
-        // norm = _[3]
-        // normsq = _[4]
-
-        /** internal
-         * Physics.vector#_
-         *
-         * Private storage array for data.
-         *
-         * Do not access this directly. Private. Keep out.
-         **/
-        if (typedArrays){
-            this._ = new Float64Array(5);
-        } else {
-            this._ = [];
-        }
-
-        if (x && (x.x !== undefined || x._ && x._.length)){
-
-            this.clone( x );
-
-        } else {
-
-            this.recalc = true; //whether or not recalculate norms
-            this.set( x, y );
-        }
-    };
-
-    Object.defineProperties( Vector.prototype, {
-        /**
-         * Physics.vector#x
-         *
-         * Getter/setter property for the x coordinate.
-         **/
-        x: {
-            get: function(){
-                return +this._[0];
-            },
-            set: function( x ){
-                x = +x || 0;
-                this.recalc = ( x === this._[0] );
-                this._[0] = x;
-            }
-        },
-        /**
-         * Physics.vector#y
-         *
-         * Getter/setter property for the y coordinate.
-         **/
-        y: {
-            get: function(){
-                return +this._[1];
-            },
-            set: function( y ){
-                y = +y || 0;
-                this.recalc = ( y === this._[1] );
-                this._[1] = y;
-            }
-        }
-    });
-
-    //
-    // Methods
-    //
-
-    /**
-     * Physics.vector#set( x, y ) -> this
-     * - x (Number): x coordinate
-     * - y (Number): y coordinate
-     *
-     * Sets the x and y components of this vector.
-     **/
-    Vector.prototype.set = function( x, y ) {
-
-        this.recalc = true;
-
-        this._[0] = +x || 0;
-        this._[1] = +y || 0;
-        return this;
-    };
-
-    /** deprecated: 0.6.0..1.0.0
-     * Physics.vector#get( idx ) -> Number
-     * - idx (Number): The coordinate index (0 or 1)
-     *
-     * Get the x or y component by index.
-     **/
-    Vector.prototype.get = function( n ){
-
-        return this._[ n ];
-    };
-
-    /**
-     * Physics.vector#vadd( v ) -> this
-     * - v (Physics.vector): vector to add
-     *
-     * Add a [[Physics.vector]] to `this`.
-     **/
-    Vector.prototype.vadd = function( v ) {
-
-        this.recalc = true;
-
-        this._[0] += v._[0];
-        this._[1] += v._[1];
-        return this;
-    };
-
-    /**
-     * Physics.vector#vsub( v ) -> this
-     * - v (Physics.vector): vector to subtract
-     *
-     * Subtract a [[Physics.vector]] from `this`.
-     **/
-    Vector.prototype.vsub = function( v ) {
-
-        this.recalc = true;
-
-        this._[0] -= v._[0];
-        this._[1] -= v._[1];
-        return this;
-    };
-
-    /**
-     * Physics.vector#add( x, y ) -> this
-     * - x (Number): amount to add to the x coordinate
-     * - y (Number): amount to add to the y coordinate
-     *
-     * Add scalars [[Physics.vector]] to the coordinates.
-     **/
-    Vector.prototype.add = function( x, y ){
-
-        this.recalc = true;
-
-        this._[0] += +x || 0;
-        this._[1] += +y || 0;
-        return this;
-    };
-
-    /**
-     * Physics.vector#sub( x, y ) -> this
-     * - x (Number): amount to subtract from the x coordinate
-     * - y (Number): amount to subtract from the y coordinate
-     *
-     * Subtract scalars [[Physics.vector]] from the coordinates.
-     **/
-    Vector.prototype.sub = function( x, y ){
-
-        this.recalc = true;
-
-        this._[0] -= x;
-        this._[1] -= y === undefined? 0 : y;
-        return this;
-    };
-
-    /**
-     * Physics.vector#mult( m ) -> this
-     * - m (Number): amount to multiply this vector by
-     *
-     * Multiply this by a scalar quantity.
-     *
-     * Same as scaling the vector by an amount `m`.
-     **/
-    Vector.prototype.mult = function( m ) {
-
-        if ( !this.recalc ){
-
-            this._[4] *= m * m;
-            this._[3] *= m;
-        }
-
-        this._[0] *= m;
-        this._[1] *= m;
-        return this;
-    };
-
-    /**
-     * Physics.vector#dot( v ) -> Number
-     * - v (Physics.vector): The other vector
-     *
-     * Compute the dot product of this vector with `v`.
-     **/
-    Vector.prototype.dot = function( v ) {
-
-        return (this._[0] * v._[0]) + (this._[1] * v._[1]);
-    };
-
-    /**
-     * Physics.vector#cross( v ) -> Number
-     * - v (Physics.vector): The other vector
-     *
-     * Compute the (left-handed) cross product of this vector with `v`.
-     **/
-    Vector.prototype.cross = function( v ) {
-
-        return ( - this._[0] * v._[1]) + (this._[1] * v._[0]);
-    };
-
-    /**
-     * Physics.vector#proj( v ) -> Number
-     * - v (Physics.vector): The other vector
-     *
-     * Compute the [scalar projection](http://en.wikipedia.org/wiki/Vector_projection#Scalar_projection_2) of this along `v`.
-     **/
-    Vector.prototype.proj = function( v ){
-
-        return this.dot( v ) / v.norm();
-    };
-
-
-    /**
-     * Physics.vector#vproj( v ) -> this
-     * - v (Physics.vector): The other vector
-     *
-     * Compute the [vector projection](http://en.wikipedia.org/wiki/Vector_projection#Vector_projection_2) of this along `v` and copy the result into this vector.
-     **/
-    Vector.prototype.vproj = function( v ){
-
-        var m = this.dot( v ) / v.normSq();
-        return this.clone( v ).mult( m );
-    };
-
-    /**
-     * Physics.vector#angle( [v] ) -> Number
-     * - v (Physics.vector): The other vector
-     * + (Number): The angle in radians between this vector and the x-axis OR `v` if specified
-     *
-     * Compute the angle between `this` and vector `v` or this and x axis.
-     **/
-    Vector.prototype.angle = function( v ){
-
-        var ang;
-
-        if ( this.equals( Vector.zero ) ){
-
-            if ( v ){
-                return v.angle();
-            } else {
-                return NaN;
-            }
-
-        } else {
-
-            if ( v && !v.equals( Vector.zero ) ){
-                ang = atan2( this._[1] * v._[0] - this._[0] * v._[1], this._[0] * v._[0] + this._[1] * v._[1]);
-            } else {
-                ang = atan2( this._[ 1 ], this._[ 0 ] );
-            }
-        }
-
-        while (ang > Math.PI){
-            ang -= TWOPI;
-        }
-
-        while (ang < -Math.PI){
-            ang += TWOPI;
-        }
-
-        return ang;
-    };
-
-    /**
-     * Physics.vector#angle2( left, right ) -> Number
-     * - left (Physics.vector): The position on the left
-     * - right (Physics.vector): The position on the right
-     *
-     * Compute the angle created between three points; left -> this -> right.
-     **/
-    Vector.prototype.angle2 = function( left, right ){
-
-        var x1 = left._[0] - this._[0]
-            ,y1 = left._[1] - this._[1]
-            ,x2 = right._[0] - this._[0]
-            ,y2 = right._[1] - this._[1]
-            ,ang = atan2( y1 * x2 - x1 * y2, x1 * x2 + y1 * y2)
-            ;
-
-        while (ang > Math.PI){
-            ang -= TWOPI;
-        }
-
-        while (ang < -Math.PI){
-            ang += TWOPI;
-        }
-
-        return ang;
-    };
-
-    /**
-     * Physics.vector#norm() -> Number
-     *
-     * Compute the norm (length) of this vector.
-     **/
-    Vector.prototype.norm = function() {
-
-        if (this.recalc){
-            this.recalc = false;
-            this._[4] = (this._[0] * this._[0] + this._[1] * this._[1]);
-            this._[3] = sqrt( this._[4] );
-        }
-
-        return this._[3];
-    };
-
-    /**
-     * Physics.vector#normSq() -> Number
-     *
-     * Compute the norm (length) squared of this vector.
-     **/
-    Vector.prototype.normSq = function() {
-
-        if (this.recalc){
-            this.recalc = false;
-            this._[4] = (this._[0] * this._[0] + this._[1] * this._[1]);
-            this._[3] = sqrt( this._[4] );
-        }
-
-        return this._[4];
-    };
-
-    /**
-     * Physics.vector#dist( v ) -> Number
-     * - v (Physics.vector): The other vector
-     *
-     * Compute the distance from this vector to another vector `v`.
-     **/
-    Vector.prototype.dist = function( v ) {
-
-        var dx, dy;
-        return sqrt(
-            (dx = (v._[0] - this._[0])) * dx +
-            (dy = (v._[1] - this._[1])) * dy
-        );
-    };
-
-    /**
-     * Physics.vector#distSq( v ) -> Number
-     * - v (Physics.vector): The other vector
-     *
-     * Compute the distance squared from this vector to another vector `v`.
-     **/
-    Vector.prototype.distSq = function( v ) {
-
-        var dx, dy;
-        return (
-            (dx = (v._[0] - this._[0])) * dx +
-            (dy = (v._[1] - this._[1])) * dy
-        );
-    };
-
-    /**
-     * Physics.vector#perp( [ccw] ) -> this
-     * - ccw (Boolean): flag to indicate that we should rotate counterclockwise
-     *
-     * Change this vector into a vector that will be perpendicular.
-     *
-     * In other words, rotate by (+-) 90 degrees.
-     **/
-    Vector.prototype.perp = function( ccw ) {
-
-        var tmp = this._[0]
-            ;
-
-        if ( ccw ){
-
-            // x <-> y
-            // negate y
-            this._[0] = this._[1];
-            this._[1] = -tmp;
-
-        } else {
-
-            // x <-> y
-            // negate x
-            this._[0] = -this._[1];
-            this._[1] = tmp;
-        }
-
-        return this;
-    };
-
-    /**
-     * Physics.vector#normalize() -> this
-     *
-     * Normalise this vector, making it a unit vector.
-     **/
-    Vector.prototype.normalize = function() {
-
-        var m = this.norm();
-
-        // means it's a zero Vector
-        if ( m === 0 ){
-            return this;
-        }
-
-        m = 1/m;
-
-        this._[0] *= m;
-        this._[1] *= m;
-
-        this._[3] = 1.0;
-        this._[4] = 1.0;
-
-        return this;
-    };
-
-    /**
-     * Physics.vector#transform( t ) -> this
-     * - t (Physics.transform): The transformation to apply
-     *
-     * Apply a [[Physics.transform]] to this vector.
-     **/
-    Vector.prototype.transform = function( t ){
-
-        var sinA = t.sinA
-            ,cosA = t.cosA
-            ,x = t.o._[ 0 ]
-            ,y = t.o._[ 1 ]
-            ;
-
-        this._[ 0 ] -= x;
-        this._[ 1 ] -= y;
-
-        // rotate about origin "o" then translate
-        return this.set(
-            this._[ 0 ] * cosA - this._[ 1 ] * sinA + x + t.v._[ 0 ],
-            this._[ 0 ] * sinA + this._[ 1 ] * cosA + y + t.v._[ 1 ]
-        );
-    };
-
-    /**
-     * Physics.vector#transformInv( t ) -> this
-     * - t (Physics.transform): The transformation to apply the inverse of
-     *
-     * Apply an inverse [[Physics.transform]] to this vector.
-     **/
-    Vector.prototype.transformInv = function( t ){
-
-        var sinA = t.sinA
-            ,cosA = t.cosA
-            ,x = t.o._[ 0 ]
-            ,y = t.o._[ 1 ]
-            ;
-
-        this._[ 0 ] -= x + t.v._[ 0 ];
-        this._[ 1 ] -= y + t.v._[ 1 ];
-
-        // inverse translate then inverse rotate about origin "o"
-        return this.set(
-            this._[ 0 ] * cosA + this._[ 1 ] * sinA + x,
-            - this._[ 0 ] * sinA + this._[ 1 ] * cosA + y
-        );
-    };
-
-    /**
-     * Physics.vector#rotate( t ) -> this
-     * Physics.vector#rotate( ang[, o] ) -> this
-     * - t (Physics.transform): The transformation to apply the rotational part of
-     * - ang (Number): The angle (in radians), to rotate by
-     * - o (Vectorish): The point of origin of the rotation
-     *
-     * Rotate this vector.
-     *
-     * An angle and rotation origin can be specified,
-     * or a transform can be specified and only the rotation
-     * portion of that transform will be applied
-     **/
-    Vector.prototype.rotate = function( t, o ){
-
-        var sinA
-            ,cosA
-            ,x = 0
-            ,y = 0
-            ;
-
-        if ( typeof t === 'number' ){
-            sinA = Math.sin( t );
-            cosA = Math.cos( t );
-
-            if ( o ){
-                x = o.x;
-                y = o.y;
-            }
-        } else {
-            sinA = t.sinA;
-            cosA = t.cosA;
-
-            x = t.o._[ 0 ];
-            y = t.o._[ 1 ];
-        }
-
-        this._[ 0 ] -= x;
-        this._[ 1 ] -= y;
-
-        return this.set(
-            this._[ 0 ] * cosA - this._[ 1 ] * sinA + x,
-            this._[ 0 ] * sinA + this._[ 1 ] * cosA + y
-        );
-    };
-
-    /**
-     * Physics.vector#rotateInv( t ) -> this
-     * - t (Physics.transform): The transformation to apply the inverse rotational part of
-     *
-     * Apply the inverse rotation of a transform.
-     *
-     * Only the inverse rotation portion of
-     * that transform will be applied.
-     **/
-    Vector.prototype.rotateInv = function( t ){
-
-        return this.set(
-            (this._[ 0 ] - t.o._[ 0 ]) * t.cosA + (this._[ 1 ] - t.o._[ 1 ]) * t.sinA + t.o._[ 0 ],
-            -(this._[ 0 ] - t.o._[ 0 ]) * t.sinA + (this._[ 1 ] - t.o._[ 1 ]) * t.cosA + t.o._[ 1 ]
-        );
-    };
-
-    /**
-     * Physics.vector#translate( t ) -> this
-     * - t (Physics.transform): The transformation to apply the translational part of
-     *
-     * Apply the translation of a transform.
-     *
-     * Only the translation portion of
-     * that transform will be applied.
-     **/
-    Vector.prototype.translate = function( t ){
-
-        return this.vadd( t.v );
-    };
-
-    /**
-     * Physics.vector#translateInv( t ) -> this
-     * - t (Physics.transform): The transformation to apply the inverse translational part of
-     *
-     * Apply the inverse translation of a transform.
-     *
-     * Only the inverse translation portion of
-     * that transform will be applied.
-     **/
-    Vector.prototype.translateInv = function( t ){
-
-        return this.vsub( t.v );
-    };
-
-
-    /**
-     * Physics.vector#clone( [v] ) -> this|Physics.vector
-     * - v (Vectorish): The vector-like object to clone
-     * + (this): If `v` is specified as an argument
-     * + (Physics.vector): A new vector instance that clones this vector, if no argument is specified
-     *
-     * Create a clone of this vector, or clone another vector into this instance.
-     *
-     * This is especially useful in vector algorithms
-     * that use temporary vectors (which most should).
-     * You can create temporary vectors and then do things like...
-     * ```
-     * temp.clone( otherVector );
-     * // compute things with temp...
-     * // then save the result
-     * result.clone( tmp );
-     * ```
-     **/
-    Vector.prototype.clone = function( v ) {
-
-        // http://jsperf.com/vector-storage-test
-
-        if ( v ){
-
-            if (!v._){
-
-                return this.set( v.x, v.y );
-            }
-
-            this.recalc = v.recalc;
-
-            if (!v.recalc){
-                this._[3] = v._[3];
-                this._[4] = v._[4];
-            }
-
-            this._[0] = v._[0];
-            this._[1] = v._[1];
-
-            return this;
-        }
-
-        return new Vector( this );
-    };
-
-    /**
-     * Physics.vector#swap( v ) -> this
-     * - v (Physics.vector): The other vector
-     *
-     * Swap values with other vector.
-     **/
-    Vector.prototype.swap = function( v ){
-
-        var _ = this._;
-        this._ = v._;
-        v._ = _;
-
-        _ = this.recalc;
-        this.recalc = v.recalc;
-        v.recalc = _;
-        return this;
-    };
-
-    /**
-     * Physics.vector#values() -> Object
-     *
-     * Get the coordinate values as an object literal.
-     **/
-    Vector.prototype.values = function(){
-
-        return {
-            x: this._[0],
-            y: this._[1]
-        };
-    };
-
-
-    /**
-     * Physics.vector#zero() -> this
-     *
-     * Set the coordinates of this vector to zero.
-     **/
-    Vector.prototype.zero = function() {
-
-        this._[3] = 0.0;
-        this._[4] = 0.0;
-
-        this._[0] = 0.0;
-        this._[1] = 0.0;
-        return this;
-    };
-
-    /**
-     * Physics.vector#negate() -> this
-     *
-     * Flip this vector in the opposite direction.
-     **/
-    Vector.prototype.negate = function( component ){
-
-        if (component !== undefined){
-
-            this._[ component ] = -this._[ component ];
-            return this;
-        }
-
-        this._[0] = -this._[0];
-        this._[1] = -this._[1];
-        return this;
-    };
-
-    /**
-     * Physics.vector#clamp( minV, maxV ) -> this
-     * - minV (Vectorish): The minimum vector
-     * - maxV (Vectorish): The maximum vector
-     *
-     * Constrain vector components to minima and maxima.
-     *
-     * The vector analog of [scalar clamping](http://en.wikipedia.org/wiki/Clamping_(graphics)).
-     **/
-    Vector.prototype.clamp = function( minV, maxV ){
-
-        this._[0] = min(max(this._[0], minV.x), maxV.x);
-        this._[1] = min(max(this._[1], minV.y), maxV.y);
-        this.recalc = true;
-        return this;
-    };
-
-    /**
-     * Physics.vector#toString() -> String
-     *
-     * Get a formatted string of this vector's coordinates.
-     **/
-    Vector.prototype.toString = function(){
-
-        return '('+this._[0] + ', ' + this._[1]+')';
-    };
-
-
-    /**
-     * Physics.vector#equals( v ) -> Boolean
-     * - v (Physics.vector): The other vector
-     *
-     * Determine if this vector equals another.
-     **/
-    Vector.prototype.equals = function( v ){
-
-        return this._[0] === v._[0] &&
-            this._[1] === v._[1] &&
-            this._[2] === v._[2];
-    };
-
-    /**
-     * Physics.vector.axis = Array
-     *
-     * Read-only axis vectors for general reference.
-     *
-     * Example:
-     *
-     * ```javascript
-     * Physics.vector.axis[0]; // The x axis unit vector
-     * Physics.vector.axis[1]; // The y axis unit vector
-     * ```
-     **/
-    Vector.axis = [
-        new Vector(1.0, 0.0),
-        new Vector(0.0, 1.0)
-    ];
-
-    /**
-     * Physics.vector.zero = zeroVector
-     *
-     * Read-only zero vector for reference
-     **/
-    Vector.zero = new Vector(0, 0);
-
-    // assign
-    Physics.vector = Vector;
-
-}(this)); // end Vector class
-
-
-// ---
-// inside: src/util/noconflict.js
-
-(function( window ){
-
-    var _Physics = window.Physics;
-
-    /**
-     * Physics.noConflict() -> Physics
-     * 
-     * Restore the original reference to the global window.Physics variable.
-     * 
-     * Does nothing if PhysicsJS doesn't have a reference in global scope
-     **/
-    Physics.noConflict = function(){
-
-        if ( window.Physics === Physics ) {
-            window.Physics = _Physics;
-        }
-        
-        return Physics;
-    };
-
-})( this );
-
-// ---
-// inside: src/util/decorator.js
-
-/** related to: factory
- * Physics.util.decorator( type [, protoDef ] ) -> Function
- * - type (String): The name of the factory you are creating
- * - protoDef (Object): The top-level prototype
- * + (Function): The factory function
- *
- * Facilitates creation of decorator factory functions.
- *
- * See the [[factory]] definition for the factory signatures.
- * [For full documentation and examples, please visit the wiki](https://github.com/wellcaffeinated/PhysicsJS/wiki/Fundamentals#the-factory-pattern).
- *
- * Example:
- *
- * ```javascript
- * var factory = Physics.util.decorator('factory', {
- *      // prototype methods...
- *      method: function( args ){
- *      }
- * });
- *
- * // define
- * factory( 'name', 'parent-name', function( parent ){
- *
- *      // extend further...
- *      return {
- *          // overrides
- *          init: function( cfg ){
- *              parent.init.call(this, cfg);
- *          }
- *      };
- * });
- *
- * // instantiate
- * var options = { key: 'val' };
- * var instance = factory( 'name', options );
- * ```
- **/
-var Decorator = Physics.util.decorator = function Decorator( type, baseProto ){
-
-    var registry = {}
-        ,proto = {}
-        ;
-
-    // extend that supports getters/setters
-    // only extends functions
-    var extend = function extend( to, from ){
-        var desc, key;
-        for ( key in from ){
-            desc = Object.getOwnPropertyDescriptor( from, key );
-            if ( desc.get || desc.set ){
-
-                Object.defineProperty( to, key, desc );
-
-            } else if ( Physics.util.isFunction( desc.value ) ){
-
-                to[ key ] = desc.value;
-            }
-        }
-        return to;
-    };
-
-    // http://ejohn.org/blog/objectgetprototypeof/
-    /* jshint -W103 */
-    var getProto = Object.getPrototypeOf;
-    if ( typeof getProto !== 'function' ) {
-        if ( typeof 'test'.__proto__ === 'object' ) {
-            getProto = function(object){
-                return object.__proto__;
-            };
-        } else {
-            getProto = function(object){
-                // May break if the constructor has been tampered with
-                return object.constructor.prototype;
-            };
-        }
-    }
-    /* jshint +W103 */
-
-    var objectCreate = Object.create;
-    if (typeof objectCreate !== 'function') {
-        objectCreate = function (o) {
-            function F() {}
-            F.prototype = o;
-            return new F();
-        };
-    }
-
-    /*
-     * mixin( key, val )
-     * mixin( obj )
-     * - key (String): The method name
-     * - val (Function): The function to assign
-     * - obj (Object): object with many `key: fn` pairs
-     *
-     * Apply mixin methods to decorator base.
-     */
-    var mixin = function mixin( key, val ){
-
-        if ( typeof key === 'object' ){
-            proto = extend(proto, key);
-            proto.type = type;
-            return;
-        }
-
-        if ( key !== 'type' && Physics.util.isFunction( val ) ){
-            proto[ key ] = val;
-        }
-    };
-
-    // @TODO: not sure of the best way to make the constructor names
-    // transparent and readable in debug consoles...
-    mixin( baseProto );
-
-    /**  belongs to: Physics.util.decorator
-     * factory( name[, parentName], decorator[, cfg] )
-     * factory( name, cfg ) -> Object
-     * -  name       (String):  The class name
-     * -  parentName (String): The name of parent class to extend
-     * -  decorator  (Function): The decorator function that should define and return methods to extend (decorate) the base class
-     * -  cfg        (Object): The configuration to pass to the class initializer
-     *
-     * Factory function for definition and instantiation of subclasses.
-     *
-     * Use the first signature (once) to define it first.
-     * If defining without the "cfg" parameter, void will be returned. Otherwise the class instance will be returned.
-     *
-     * See [[Physics.util.decorator]] for more information.
-     **/
-    var factory = function factory( name, parentName, decorator, cfg ){
-
-        var instance
-            ,result
-            ,parent = proto
-            ,tmp
-            ;
-
-        // set parent if specified
-        if ( typeof parentName !== 'string' ){
-
-            // ... otherwise reassign parameters
-            cfg = decorator;
-            decorator = parentName;
-
-        } else {
-
-            // extend the specified module
-            parent = registry[ parentName ];
-
-            if ( !parent ){
-
-                throw 'Error: "' + parentName + '" ' + type + ' not defined';
-            }
-
-            parent = parent.prototype;
-        }
-
-        if ( typeof decorator === 'function' ){
-
-            result = registry[ name ];
-
-            if ( result ){
-
-                result.prototype = extend(result.prototype, decorator( getProto(result.prototype) ));
-
-            } else {
-                // newly defined
-                // store the new class
-                result = registry[ name ] = function constructor( opts ){
-                    if (this.init){
-                        this.init( opts );
-                    }
-                };
-
-                result.prototype = objectCreate( parent );
-                result.prototype = extend(result.prototype, decorator( parent, result.prototype ));
-            }
-
-            result.prototype.type = type;
-            result.prototype.name = name;
-
-        } else {
-
-            cfg = decorator || {};
-            result = registry[ name ];
-            if (!result){
-
-                throw 'Error: "' + name + '" ' + type + ' not defined';
-            }
-        }
-
-        if ( cfg ) {
-
-            // create a new instance from the provided decorator
-            return new result( cfg );
-        }
-    };
-
-    factory.mixin = mixin;
-
-    return factory;
-};
-
-
-// ---
-// inside: src/util/helpers.js
-
-/**
- * Physics.util.indexOf( arr, value ) -> Number
- * - arr (Array): The array to search
- * - value (Mixed): The value to find
- * + (Number): The index of `value` in the array OR `-1` if not found
- *
- * Fast indexOf implementation.
- **/
-Physics.util.indexOf = function indexOf(arr, value) {
-    var fr = 0, bk = arr.length;
-    while (fr < bk) {
-        bk--;
-        if (arr[ fr ] === value) {
-            return fr;
-        }
-        if (arr[ bk ] === value) {
-            return bk;
-        }
-        fr++;
-    }
-    return -1;
-};
-
-
-// http://jsperf.com/array-destroy/87
-/**
- * Physics.util.clearArray( arr ) -> Array
- * - arr (Array): The array to clear
- * + (Array): The array passed in
- *
- * Quickly clear an array.
- **/
-Physics.util.clearArray = function clearArray(arr){
-    var l = arr.length;
-    while( l-- ){
-        arr.pop();
-    }
-    return arr;
-};
-
-/**
- * Physics.util.throttle( fn, delay ) -> Function
- * - fn (Function): The function to throttle
- * - delay (Number): Time in milliseconds
- *
- * Ensure a function is only called once every specified time span.
- **/
-Physics.util.throttle = function throttle( fn, delay, scope ){
-    var to
-        ,call = false
-        ,args
-        ,cb = function(){
-            clearTimeout( to );
-            if ( call ){
-                call = false;
-                to = setTimeout(cb, delay);
-                fn.apply(scope, args);
-            } else {
-                to = false;
-            }
-        }
-        ;
-
-    scope = scope || null;
-
-    return function(){
-        call = true;
-        args = arguments;
-        if ( !to ){
-            cb();
-        }
-    };
-};
-
-/**
- * Physics.util.options( def[, target] ) -> Function
- * - def (Object): Default options to set
- * - target (Object): Where to copy the options to. Defaults to the returned function.
- * + (Function): The options function
- *
- * Options helper to keep track of options. Call it with a config object. Access options directly on the function.
- *
- * Example:
- *
- * ```javascript
- * this.options = Physics.util.options({ foo: 'bar', opt: 'def' });
- * this.options({ opt: 'myVal' });
- *
- * this.options.foo; // === 'bar'
- * this.options.def; // === 'myVal'
- *
- * // can also change defaults later
- * this.options.defaults({ foo: 'baz' });
- *
- * // can add a change callback
- * this.options.onChange(function( opts ){
- *     // some option changed
- *     // opts is the target
- * });
- * ```
- **/
-// deep copy callback to extend deeper into options
-var deepCopyFn = function( a, b ){
-
-    if ( Physics.util.isPlainObject( b ) ){
-
-        return Physics.util.extend({}, a, b, deepCopyFn );
-    }
-
-    return b !== undefined ? b : a;
-};
-Physics.util.options = function( def, target ){
-
-    var _def = {}
-        ,fn
-        ,callbacks = []
-        ;
-
-    // set options
-    fn = function fn( options, deep ){
-
-        Physics.util.extend(target, options, deep ? deepCopyFn : null);
-        for ( var i = 0, l = callbacks.length; i < l; ++i ){
-            callbacks[ i ]( target );
-        }
-        return target;
-    };
-
-    // add defaults
-    fn.defaults = function defaults( def, deep ){
-        Physics.util.extend( _def, def, deep ? deepCopyFn : null );
-        Physics.util.defaults( target, _def, deep ? deepCopyFn : null );
-        return _def;
-    };
-
-    fn.onChange = function( cb ){
-        callbacks.push( cb );
-    };
-
-    target = target || fn;
-
-    fn.defaults( def );
-
-    return fn;
-};
-
-/**
- * Physics.util.pairHash( id1, id2 ) -> Number
- * - id1 (Number): The id of the first thing
- * - id2 (Number): The id of the second thing
- * + (Number): A unique numeric hash (valid for values < 2^16)
- *
- * Generate a unique numeric hash from two input IDs.
- *
- * Useful for speedy indexing of pairs.
- **/
-Physics.util.pairHash = function( id1, id2 ){
-    id1 = id1|0;
-    id2 = id2|0;
-
-    if ( (id1|0) === (id2|0) ){
-
-        return -1;
-    }
-
-    // valid for values < 2^16
-    return ((id1|0) > (id2|0) ?
-        (id1 << 16) | (id2 & 0xFFFF) :
-        (id2 << 16) | (id1 & 0xFFFF))|0
-        ;
-};
-
-/**
- * Physics.util.bind( fn, scope[, args... ] ) -> Function
- * - fn (Function): The function to bind scope to
- * - scope (Object): The scope to give to `fn`
- * - args (Mixed): Arguments to send to `fn`
- *
- * Bind a scope to a function.
- *
- * Basically the same functionality as [Function.prototype.bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind).
- **/
-if ( !Function.prototype.bind ){
-    Physics.util.bind = function( fn, scope, args ){
-        args = Array.prototype.slice.call( arguments, 2 );
-        return function(){
-            return fn.apply( scope, args.concat( Array.prototype.slice.call(arguments) ) );
-        };
-    };
-} else {
-    Physics.util.bind = function( fn, scope, args ){
-        args = Array.prototype.slice.call( arguments, 1 );
-        return Function.prototype.bind.apply( fn, args );
-    };
-}
-
-/**
- * Physics.util.find( collection, fn( value, index, collection ) ) -> Mixed
- * - collection (Array): Collection of values to test
- * - fn (Function): The test function
- * - value (Mixed): The value to test
- * - index (Number): The index of value in collection
- * - collection (Array): The input collection
- *
- * Test an array of values against a test function
- * and return the first value for which the function
- * returns true.
- **/
-Physics.util.find = function( collection, fn ){
-    var i
-        ,l = collection.length
-        ,val
-        ;
-
-    for ( i = 0; i < l; i++ ){
-        val = collection[ i ];
-        if ( fn( val, i, collection ) ){
-            return val;
-        }
-    }
-};
-
-/**
- * Physics.util.filter( collection, fn( value, index, collection ) ) -> Array
- * - collection (Array): Collection of values to test
- * - fn (Function): The test function
- * - value (Mixed): The value to test
- * - index (Number): The index of value in collection
- * - collection (Array): The input collection
- *
- * Test an array of values against a test function
- * and return another array of values for which
- * the test function returns true.
- **/
-Physics.util.filter = function( collection, fn ){
-    var i
-        ,l = collection.length
-        ,val
-        ,matches = []
-        ;
-
-    for ( i = 0; i < l; i++ ){
-        val = collection[ i ];
-        if ( fn( val, i, collection ) ){
-            matches.push( val );
-        }
-    }
-
-    return matches;
-};
-
-// lodash methods
-
-(function(){
-/*
- * @license
- * Modified version of:
- * Lo-Dash 2.4.1 (Custom Build) <http://lodash.com/>
- * Copyright 2012-2013 The Dojo Foundation <http://dojofoundation.org/>
- * Based on Underscore.js 1.5.2 <http://underscorejs.org/LICENSE>
- * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
- * Available under MIT license <http://lodash.com/license>
- */
-
-/* Used to determine if values are of the language type Object */
-var objectTypes = {
-  'boolean': false,
-  'function': true,
-  'object': true,
-  'number': false,
-  'string': false,
-  'undefined': false
-};
-var identity = function(a){ return a; };
-var arrayClass = '[object Array]';
-var objectClass = '[object Object]';
-var nativeKeys = Object.keys;
-var toString = Object.prototype.toString;
-var hasOwnProperty = Object.prototype.hasOwnProperty;
-/* Used as the size when optimizations are enabled for large arrays */
-var largeArraySize = 75;
-/* Used to pool arrays and objects used internally */
-var arrayPool = [],
-    objectPool = [];
-/* Used as the max size of the `arrayPool` and `objectPool` */
-var maxPoolSize = 40;
-var keyPrefix = +new Date() + '';
-
-function releaseArray(array) {
-  Physics.util.clearArray( array );
-  if (arrayPool.length < maxPoolSize) {
-    arrayPool.push(array);
-  }
-}
-
-function releaseObject(object) {
-  var cache = object.cache;
-  if (cache) {
-    releaseObject(cache);
-  }
-  object.array = object.cache = object.criteria = object.object = object.number = object.string = object.value = null;
-  if (objectPool.length < maxPoolSize) {
-    objectPool.push(object);
-  }
-}
-
-function getObject() {
-  return objectPool.pop() || {
-    'array': null,
-    'cache': null,
-    'criteria': null,
-    'false': false,
-    'index': 0,
-    'null': false,
-    'number': null,
-    'object': null,
-    'push': null,
-    'string': null,
-    'true': false,
-    'undefined': false,
-    'value': null
-  };
-}
-
-function getArray() {
-  return arrayPool.pop() || [];
-}
-
-function cacheIndexOf(cache, value) {
-  var type = typeof value;
-  cache = cache.cache;
-
-  if (type === 'boolean' || value == null) {
-    return cache[value] ? 0 : -1;
-  }
-  if (type !== 'number' && type !== 'string') {
-    type = 'object';
-  }
-  var key = type === 'number' ? value : keyPrefix + value;
-  cache = (cache = cache[type]) && cache[key];
-
-  return type === 'object' ?
-    (cache && Physics.util.indexOf(cache, value) > -1 ? 0 : -1) :
-    (cache ? 0 : -1);
-}
-
-function cachePush(value) {
-  var cache = this.cache,
-      type = typeof value;
-
-  if (type === 'boolean' || value == null) {
-    cache[value] = true;
-  } else {
-    if (type !== 'number' && type !== 'string') {
-      type = 'object';
-    }
-    var key = type === 'number' ? value : keyPrefix + value,
-        typeCache = cache[type] || (cache[type] = {});
-
-    if (type === 'object') {
-      (typeCache[key] || (typeCache[key] = [])).push(value);
-    } else {
-      typeCache[key] = true;
-    }
-  }
-}
-
-function createCache(array) {
-  var index = -1,
-      length = array.length,
-      first = array[0],
-      mid = array[(length / 2) | 0],
-      last = array[length - 1];
-
-  if (first && typeof first === 'object' &&
-      mid && typeof mid === 'object' && last && typeof last === 'object') {
-    return false;
-  }
-  var cache = getObject();
-  cache['false'] = cache['null'] = cache['true'] = cache['undefined'] = false;
-
-  var result = getObject();
-  result.array = array;
-  result.cache = cache;
-  result.push = cachePush;
-
-  while (++index < length) {
-    result.push(array[index]);
-  }
-  return result;
-}
-
-var shimKeys = function(object) {
-  var index, iterable = object, result = [];
-  if (!iterable){ return result; }
-  if (!(objectTypes[typeof object])){ return result; }
-    for (index in iterable) {
-      if (hasOwnProperty.call(iterable, index)) {
-        result.push(index);
-      }
-    }
-  return result;
-};
-
-var keys = !nativeKeys ? shimKeys : function(object) {
-  if (!Physics.util.isObject(object)) {
-    return [];
-  }
-  return nativeKeys(object);
-};
-
-var idCounter = 0;
-/**
- * Physics.util.uniqueId( [prefix] ) -> String
- * - prefix (String): Prefix to the id
- *
- * Generate a unique id, optionally prefixed.
- **/
-Physics.util.uniqueId = function uniqueId(prefix) {
-    var id = ++idCounter;
-    return '' + (prefix || '') + id;
-};
-
-/*
- * The base implementation of `_.random` without argument juggling or support
- * for returning floating-point numbers.
- *
- * @private
- * @param {number} min The minimum possible value.
- * @param {number} max The maximum possible value.
- * @returns {number} Returns a random number.
- */
-function baseRandom(min, max) {
-    return min + Math.floor(Math.random() * (max - min + 1));
-}
-
-/*
- * Creates an array of shuffled values, using a version of the Fisher-Yates
- * shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle.
- *
- * @static
- * @memberOf _
- * @category Collections
- * @param {Array|Object|string} collection The collection to shuffle.
- * @returns {Array} Returns a new shuffled collection.
- * @example
- *
- * _.shuffle([1, 2, 3, 4, 5, 6]);
- * // => [4, 1, 6, 3, 5, 2]
- */
-Physics.util.shuffle = function(collection) {
-    var index = -1
-        ,length = collection ? collection.length : 0
-        ,result = Array(typeof length === 'number' ? length : 0)
-        ,i
-        ,l
-        ,value
-        ,rand
-        ;
-
-    for ( i = 0, l = collection.length; i < l; i++ ){
-        value = collection[ i ];
-        rand = baseRandom(0, ++index);
-        result[index] = result[rand];
-        result[rand] = value;
-    }
-    return result;
-};
-
-/**
- * Physics.util.isObject( val ) -> Boolean
- * - val (Mixed): The value to test
- *
- * Test if a value is an object.
- **/
-Physics.util.isObject = function isObject(value) {
-    // check if the value is the ECMAScript language type of Object
-    // http://es5.github.io/#x8
-    // and avoid a V8 bug
-    // http://code.google.com/p/v8/issues/detail?id=2291
-    return !!(value && objectTypes[typeof value]);
-};
-
-function isFunction(value) {
-    return typeof value === 'function';
-}
-
-/**
- * Physics.util.isFunction( val ) -> Boolean
- * - val (Mixed): The value to test
- *
- * Test if a value is a function.
- **/
-Physics.util.isFunction = isFunction;
-
-/**
- * Physics.util.isArray( val ) -> Boolean
- * - val (Mixed): The value to test
- *
- * Test if a value is an array.
- **/
-Physics.util.isArray = Array.isArray || function(value) {
-  return value && typeof value === 'object' && typeof value.length === 'number' &&
-    toString.call(value) === arrayClass || false;
-};
-
-var reNative = RegExp('^' +
-  String(toString)
-    .replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
-    .replace(/toString| for [^\]]+/g, '.*?') + '$'
-);
-function isNative(value) {
-  return typeof value === 'function' && reNative.test(value);
-}
-
-function shimIsPlainObject(value) {
-  var ctor,
-      result;
-
-  // avoid non Object objects, `arguments` objects, and DOM elements
-  if (!(value && toString.call(value) === objectClass) ||
-      (ctor = value.constructor, isFunction(ctor) && !(ctor instanceof ctor))) {
-    return false;
-  }
-  // In most environments an object's own properties are iterated before
-  // its inherited properties. If the last iterated property is an object's
-  // own property then there are no inherited enumerable properties.
-  for (var key in value){
-    result = key;
-  }
-  return typeof result === 'undefined' || hasOwnProperty.call(value, result);
-}
-
-/**
- * Physics.util.isPlainObject( val ) -> Boolean
- * - val (Mixed): The value to test
- *
- * Test if a value is a plain javascript object.
- **/
-Physics.util.isPlainObject = !Object.getPrototypeOf ? shimIsPlainObject : function(value) {
-  if (!(value && toString.call(value) === objectClass)) {
-    return false;
-  }
-  var valueOf = value.valueOf,
-      objProto = isNative(valueOf) && (objProto = Object.getPrototypeOf(valueOf)) && Object.getPrototypeOf(objProto);
-
-  return objProto ?
-    (value === objProto || Object.getPrototypeOf(value) === objProto) :
-    shimIsPlainObject(value);
-};
-
-function baseUniq(array, isSorted, callback) {
-  var index = -1,
-      indexOf = Physics.util.indexOf,
-      length = array ? array.length : 0,
-      result = [];
-
-  var isLarge = !isSorted && length >= largeArraySize && indexOf === Physics.util.indexOf,
-      seen = (callback || isLarge) ? getArray() : result;
-
-  if (isLarge) {
-    var cache = createCache(seen);
-    indexOf = cacheIndexOf;
-    seen = cache;
-  }
-  while (++index < length) {
-    var value = array[index],
-        computed = callback ? callback(value, index, array) : value;
-
-    if (isSorted ?
-          !index || seen[seen.length - 1] !== computed :
-          indexOf(seen, computed) < 0
-        ) {
-      if (callback || isLarge) {
-        seen.push(computed);
-      }
-      result.push(value);
-    }
-  }
-  if (isLarge) {
-    releaseArray(seen.array);
-    releaseObject(seen);
-  } else if (callback) {
-    releaseArray(seen);
-  }
-  return result;
-}
-
-/**
- * Physics.util.uniq( array, [isSorted, callback] ) -> Array
- * - array (Array): The array
- * - isSorted (Boolean): Flag to indicate the array is sorted
- * - callback (Function): Mapping function
- *
- * Create an array without duplicates.
- **/
-Physics.util.uniq = function uniq(array, isSorted, callback) {
-  // juggle arguments
-  if (typeof isSorted !== 'boolean' && isSorted != null) {
-    callback = isSorted;
-    isSorted = false;
-  }
-  return baseUniq(array, isSorted, callback);
-};
-
-var assign = function(object, source, guard) {
-  var index, iterable = object, result = iterable;
-  if (!iterable) { return result; }
-  var args = arguments,
-      argsIndex = 0,
-      callback,
-      argsLength = typeof guard === 'number' ? 2 : args.length;
-  if (argsLength > 2 && typeof args[argsLength - 1] === 'function') {
-    callback = args[--argsLength];
-  }
-  while (++argsIndex < argsLength) {
-    iterable = args[argsIndex];
-    if (iterable && objectTypes[typeof iterable]) {
-        var ownIndex = -1,
-            ownProps = objectTypes[typeof iterable] && keys(iterable),
-            length = ownProps ? ownProps.length : 0;
-
-        while (++ownIndex < length) {
-          index = ownProps[ownIndex];
-          result[index] = callback ? callback(result[index], iterable[index]) : iterable[index];
-        }
-    }
-  }
-  return result;
-};
-
-/**
- * Physics.util.extend( object, source...[, callback] ) -> Object
- * - object (Object): The destination object
- * - source (Object): The source objects
- * - callback (Function): The function to customize assigning values
- *
- * Implementation of [lodash.extend](http://lodash.com/docs#assign)
- **/
-Physics.util.extend = assign;
-
-/**
- * Physics.util.defaults( object, source...[, callback] ) -> Object
- * - object (Object): The destination object
- * - source (Object): The source objects
- * - callback (Function): The function to customize assigning values
- *
- * Implementation of [lodash.defaults](http://lodash.com/docs#defaults).
- **/
-Physics.util.defaults = function(object, source, guard) {
-  var index, iterable = object, result = iterable;
-  if (!iterable){ return result; }
-  var args = arguments,
-      argsIndex = 0,
-      argsLength = typeof guard === 'number' ? 2 : args.length;
-  while (++argsIndex < argsLength) {
-    iterable = args[argsIndex];
-    if (iterable && objectTypes[typeof iterable]) {
-        var ownIndex = -1,
-            ownProps = objectTypes[typeof iterable] && keys(iterable),
-            length = ownProps ? ownProps.length : 0;
-
-        while (++ownIndex < length) {
-          index = ownProps[ownIndex];
-          if (typeof result[index] === 'undefined') {
-              result[index] = iterable[index];
-          }
-        }
-    }
-  }
-  return result;
-};
-
-/**
- * Physics.util.sortedIndex( array, value[, callback] ) -> Number
- * - array (Array): The array to inspect
- * - value (Mixed): The value to evaluate
- * - callback (Function): Function called per iteration
- *
- * Implementation of [lodash.sortedIndex](http://lodash.com/docs#sortedIndex).
- **/
-Physics.util.sortedIndex = function sortedIndex(array, value, callback) {
-  var low = 0,
-      high = array ? array.length : low;
-
-  // explicitly reference `identity` for better inlining in Firefox
-  callback = callback || identity;
-  value = callback(value);
-
-  /* jshint -W030 */
-  while (low < high) {
-    var mid = (low + high) >>> 1;
-    (callback(array[mid]) < value) ?
-      low = mid + 1 :
-      high = mid;
-  }
-  /* jshint +W030 */
-  return low;
-};
-
-})();
-
-
-// ---
-// inside: src/util/scratchpad.js
-
-/*
- * scratchpad
- * thread-safe management of temporary (voletile)
- * objects for use in calculations
- * https://github.com/wellcaffeinated/scratchpad.js
- */
-Physics.scratchpad = (function(){
-
-    // Errors
-    var SCRATCH_USAGE_ERROR = 'Error: Scratchpad used after .done() called. (Could it be unintentionally scoped?)';
-    var SCRATCH_INDEX_OUT_OF_BOUNDS = 'Error: Scratchpad usage space out of bounds. (Did you forget to call .done()?)';
-    var SCRATCH_MAX_REACHED = 'Error: Too many scratchpads created. (Did you forget to call .done()?)';
-    var ALREADY_DEFINED_ERROR = 'Error: Object is already registered.';
-
-    // cache previously created scratches
-    var scratches = [];
-    var numScratches = 0;
-    var Scratch, Scratchpad;
-
-    var regIndex = 0;
-
-
-    /** belongs to: Physics.scratchpad
-     * class Scratch
-     *
-     * A scratchpad session.
-     *
-     * This class keeps track of temporary objects used
-     * in this session and releases them when finished (call to `.done()`).
-     *
-     * Use this to retrieve temporary objects:
-     * - `.vector()`: retrieve a temporary [[Physics.vector]]
-     * - `.transform()`: retrieve a temporary [[Physics.transform]]
-     *
-     * See [[Physics.scratchpad]] for more info.
-     **/
-    Scratch = function Scratch(){
-
-        // private variables
-        this._active = false;
-        this._indexArr = [];
-
-        if (++numScratches >= Scratchpad.maxScratches){
-            throw SCRATCH_MAX_REACHED;
-        }
-    };
-
-    Scratch.prototype = {
-
-        /**
-         * Scratch#done( [val] ) -> Mixed
-         * - val (Mixed): No effect on this method, just passed on to the return value so you can do things like:
-         return scratch.done( myReturnVal );
-         * + (Mixed): Whatever you specified as `val`
-         *
-         * Declare that your work is finished.
-         *
-         * Release temp objects for use elsewhere. Must be called when immediate work is done.
-         *
-         * You can wrap the return value in scratch.done() so that you don't forget to call it.
-         *
-         * Example:
-         *
-         * ```javascript
-         * return scratch.done( myReturnValue );
-         * ```
-         **/
-        done: function( val ){
-
-            this._active = false;
-            var s;
-            for ( var i = 0; i < regIndex; ++i ){
-
-                this[ i ] = 0;
-            }
-
-            // add it back to the scratch stack for future use
-            scratches.push( this );
-            return val;
-        }
-    };
-
-
-    // API
-
-    /**
-     * Physics.scratchpad( [fn] ) -> Scratch|Function
-     * - fn (Function): Some function you'd like to wrap in a scratch session. First argument is the scratch instance.
-     * + (Function): The wrapped function (if `fn` arg specified) that can be reused like the original minus the first (scratch) parameter.
-     * + (Scratch): The scratch session.
-     *
-     * Get a new scratch session to work from or wrap a function in a scratch session.
-     *
-     * Call `.done()` on it when finished.
-     *
-     * Example:
-     *
-     * ```javascript
-     * // get a scratch session manually
-     * var myAlg = function( scratch, arg1, arg2, ... ){
-     *     var scratch = Physics.scratchpad()
-     *     ,vec = scratch.vector().set( 0, 0 ) // need to reinitialize... it's recycled!
-     *     ;
-     *     // ...
-     *     return scratch.done( result );
-     * };
-     * // later...
-     * while( awesome ){
-     *     myAlg( arg1, arg2, ... );
-     * }
-     * ```
-     *
-     * Example:
-     *
-     * ```javascript
-     * // wrap a function in a scratch session
-     * var myAlg = Physics.scratchpad(function( scratch, arg1, arg2, ... ){
-     *     var vec = scratch.vector().set( 0, 0 ); // need to reinitialize... it's recycled!
-     *     //...
-     *     return result;
-     * });
-     * // later...
-     * while( awesome ){
-     *     myAlg( arg1, arg2, ... );
-     * }
-     * ```
-     **/
-    Scratchpad = function Scratchpad( fn ){
-
-        if ( fn ){
-            return Scratchpad.fn( fn );
-        }
-
-        var scratch = scratches.pop() || new Scratch();
-        scratch._active = true;
-        return scratch;
-    };
-
-    // options
-    Scratchpad.maxScratches = 100; // maximum number of scratches
-    Scratchpad.maxIndex = 20; // maximum number of any type of temp objects
-
-    /**
-     * Physics.scratchpad.fn( fn ) -> Function
-     * - fn (Function): Some function you'd like to wrap in a scratch session. First argument is the scratch instance. See [[Physics.scratchpad]].
-     * + (Function): The wrapped function that can be reused like the original minus the first (scratch) parameter.
-     *
-     * Wrap a function in a scratch session.
-     *
-     * Same as calling `Physics.scratchpad( fn )` with a function specified.
-     **/
-    Scratchpad.fn = function( fn ){
-
-        var args = [];
-        for ( var i = 0, l = fn.length; i < l; i++ ){
-            args.push( i );
-        }
-
-        args = 'a' + args.join(',a');
-        /* jshint -W054 */
-        var handle = new Function('fn, scratches, Scratch', 'return function('+args+'){ '+
-               'var scratch = scratches.pop() || new Scratch( scratches );'+
-               'scratch._active = true;'+
-               'return scratch.done( fn(scratch, '+args+') );'+
-           '};'
-        );
-        /* jshint +W054 */
-
-        return handle(fn, scratches, Scratch);
-    };
-
-    /**
-     * Physics.scratchpad.register( name, constructor )
-     * - name (String): Name of the object class
-     * - constructor (Function): The object constructor
-     *
-     * Register a new object to be included in scratchpads.
-     *
-     * Example:
-     *
-     * ```javascript
-     * // register a hypothetical vector class...
-     * Physics.scratchpad.register('vector', Vector);
-     * ```
-     **/
-    Scratchpad.register = function register( name, constructor, options ){
-
-        var proto = Scratch.prototype
-            ,idx = regIndex++ // increase the scratch type index
-            ,stackname = '_' + name + 'Stack' // the name of the array stack
-            ,useFactory = options && options.useFactory
-            ;
-
-        if ( name in proto ) {
-            throw ALREADY_DEFINED_ERROR;
-        }
-
-        // create a new function on the prototype
-        Scratch.prototype[ name ] = function(){
-
-            // get the stack (or initialize it)
-            var stack = this[ stackname ] || (this[ stackname ] = [])
-                // we increase this index every time a voletile object is requested
-                // seems weird to store it on this as a number (ie: this.0, this.1)...
-                // but actually it's faster...
-                ,stackIndex = this[ idx ] | 0
-                ;
-
-            this[ idx ] = stackIndex + 1;
-
-            // if used after calling done...
-            if (!this._active){
-                throw SCRATCH_USAGE_ERROR;
-            }
-
-            // if too many objects created...
-            if (stackIndex >= Scratchpad.maxIndex){
-                throw SCRATCH_INDEX_OUT_OF_BOUNDS;
-            }
-
-            // return or create new instance
-            return stack[ stackIndex ] ||
-                    (stack[ stackIndex ] = useFactory ? constructor() : new constructor() );
-        };
-
-    };
-
-    // register some classes
-    Scratchpad.register('vector', Physics.vector);
-    Scratchpad.register('transform', Physics.transform);
-
-    return Scratchpad;
-
-})();
-
-
-// ---
-// inside: src/util/pubsub.js
-
-(function(){
-
-    var defaultPriority = 1;
-
-    function getPriority( val ){
-        return val._priority_;
-    }
-
-    // register a new scratch object so we can reuse event data
-    Physics.scratchpad.register('event', function(){ return {}; }, { useFactory: true });
-
-    /**
-     * class Physics.util.pubsub
-     *
-     * Fast pubsub implementation.
-     *
-     * Can be mixed into other classes easily.
-     **/
-    var PubSub = function PubSub(){
-
-        if (!(this instanceof PubSub)){
-            return new PubSub();
-        }
-    };
-
-    PubSub.prototype = {
-
-        /**
-         * Physics.util.pubsub#on( topic, fn( data, event )[, scope, priority] ) -> this
-         * Physics.util.pubsub#on( topicConfig[, scope, priority] ) -> this
-         * - topic (String): The topic name
-         * - topicConfig (Object): A config with key/value pairs of `{ topic: callbackFn, ... }`
-         * - fn (Function): The callback function (if not using Object as previous argument)
-         * - data (Mixed): The data sent from the call to `.emit()`
-         * - event (Object): Event data, holding `.topic`, the topic, and `.handler`, the `fn` callback.
-         * - scope (Object): The scope to bind callback to
-         * - priority (Number): The priority of the callback (higher is earlier)
-         *
-         * Subscribe callback(s) to a topic(s).
-         **/
-        on: function( topic, fn, scope, priority ){
-
-            var listeners
-                ,orig
-                ,idx
-                ;
-
-            // ensure topics hash is initialized
-            this._topics = this._topics || (this._topics = {});
-
-            // check if we're subscribing to multiple topics
-            // with an object
-            if ( Physics.util.isObject( topic ) ){
-
-                for ( var t in topic ){
-
-                    this.on( t, topic[ t ], fn, scope );
-                }
-
-                return this;
-            }
-
-            listeners = this._topics[ topic ] || (this._topics[ topic ] = []);
-            orig = fn;
-
-            if ( Physics.util.isObject( scope ) ){
-
-                fn = Physics.util.bind( fn, scope );
-                fn._bindfn_ = orig;
-                fn._one_ = orig._one_;
-                fn._scope_ = scope;
-
-            } else if ( priority === undefined ) {
-
-                priority = scope;
-            }
-
-            fn._priority_ = priority === undefined ? defaultPriority : priority;
-
-            idx = Physics.util.sortedIndex( listeners, fn, getPriority );
-
-            listeners.splice( idx, 0, fn );
-            return this;
-        },
-
-        /**
-         * Physics.util.pubsub#off( topic, fn[, scope] ) -> this
-         * Physics.util.pubsub#off( topicCfg ) -> this
-         * - topic (String): topic The topic name. Specify `true` to remove all listeners for all topics
-         * - topicCfg (Object): A config with key/value pairs of `{ topic: callbackFn, ... }`
-         * - fn (Function): The original callback function. Specify `true` to remove all listeners for specified topic
-         * - scope (Object): The scope the callback was bound to. This is important if you are binding methods that come from object prototypes.
-         *
-         * Unsubscribe callback(s) from topic(s).
-         **/
-        off: function( topic, fn, scope ){
-
-            var listeners
-                ,listn
-                ;
-
-            if ( !this._topics ){
-                // nothing subscribed
-                return this;
-            }
-
-            if ( topic === true ){
-                // purge all listeners
-                this._topics = {};
-                return this;
-            }
-
-            // check if we're subscribing to multiple topics
-            // with an object
-            if ( Physics.util.isObject( topic ) ){
-
-                for ( var t in topic ){
-
-                    this.off( t, topic[ t ] );
-                }
-
-                return this;
-            }
-
-            listeners = this._topics[ topic ];
-
-            if (!listeners){
-                return this;
-            }
-
-            if ( fn === true ){
-                // purge all listeners for topic
-                this._topics[ topic ] = [];
-                return this;
-            }
-
-            for ( var i = 0, l = listeners.length; i < l; i++ ){
-
-                listn = listeners[ i ];
-
-                if (
-                    (listn._bindfn_ === fn || listn === fn) &&
-                    ( (!scope) || listn._scope_ === scope) // check the scope too if specified
-                ){
-                    listeners.splice( i, 1 );
-                    break;
-                }
-            }
-
-            return this;
-        },
-
-        /**
-         * Physics.util.pubsub#emit( topic[, data] ) -> this
-         * - topic (String): The topic name
-         * - data (Mixed): The data to send
-         *
-         * Publish data to a topic.
-         **/
-        emit: function( topic, data ){
-
-            if ( !this._topics ){
-                // nothing subscribed
-                return this;
-            }
-
-            var listeners = this._topics[ topic ]
-                ,l = listeners && listeners.length
-                ,handler
-                ,e
-                ,scratch = Physics.scratchpad()
-                ;
-
-            if ( !l ){
-                return scratch.done(this);
-            }
-
-            e = scratch.event();
-            // event data
-            e.topic = topic;
-            e.handler = handler;
-
-            // reverse iterate so priorities work out correctly
-            while ( l-- ){
-
-                handler = listeners[ l ];
-                handler( data, e );
-
-                // if _one_ flag is set, the unsubscribe
-                if ( handler._one_ ){
-                    listeners.splice( l, 1 );
-                }
-            }
-
-            return scratch.done(this);
-        },
-
-        /**
-         * Physics.util.pubsub#one( topic, fn( data, event )[, scope, priority] ) -> this
-         * Physics.util.pubsub#one( topicConfig[, scope, priority] ) -> this
-         * - topic (String): The topic name
-         * - topicConfig (Object): A config with key/value pairs of `{ topic: callbackFn, ... }`
-         * - fn (Function): The callback function (if not using Object as previous argument)
-         * - data (Mixed): The data sent from the call to `.emit()`
-         * - event (Object): Event data, holding `.topic`, the topic, and `.handler`, the `fn` callback.
-         * - scope (Object): The scope to bind callback to
-         * - priority (Number): The priority of the callback (higher is earlier)
-         *
-         * Subscribe callback(s) to a topic(s), but only ONCE.
-         **/
-        one: function( topic, fn, scope ){
-
-            // check if we're subscribing to multiple topics
-            // with an object
-            if ( Physics.util.isObject( topic ) ){
-
-                for ( var t in topic ){
-
-                    this.one( t, topic[ t ], fn, scope );
-                }
-
-                return this;
-            }
-
-            // set the _one_ flag
-            fn._one_ = true;
-            this.on( topic, fn, scope );
-
-            return this;
-        }
-    };
-
-    Physics.util.pubsub = PubSub;
-})();
-
-
-// ---
-// inside: src/util/ticker.js
-
-/**
- * class Physics.util.ticker
- *
- * The Ticker _singleton_ for easily binding callbacks to animation loops (requestAnimationFrame).
- *
- * Requires window.requestAnimationFrame... so polyfill it if you need to.
- **/
-(function(window){
-
-    var active = true
-        ,ps = Physics.util.pubsub()
-        ,perf = window.performance
-        ;
-
-    function now(){
-        // http://updates.html5rocks.com/2012/05/requestAnimationFrame-API-now-with-sub-millisecond-precision
-        return (perf && perf.now) ?
-            (perf.now() + perf.timing.navigationStart) :
-            Date.now();
-    }
-
-    /*
-     * step( time )
-     * - time (Number): The current time
-     *
-     * Publish a tick to subscribed callbacks
-     */
-    function step(){
-
-        var time;
-
-        window.requestAnimationFrame( step );
-
-        if (!active){
-            return;
-        }
-
-        time = now();
-
-        if (!time){
-            return;
-        }
-
-        ps.emit( 'tick', time );
-    }
-
-    // start stepping if we can
-    if ( window.requestAnimationFrame ){
-        step();
-    } else {
-        active = false;
-    }
-
-    /**
-     * Physics.util.ticker.start() -> this
-     *
-     * Start the ticker
-     **/
-    function start(){
-
-        active = true;
-        return this;
-    }
-
-    /**
-     * Physics.util.ticker.stop() -> this
-     *
-     * Stop the ticker
-     **/
-    function stop(){
-
-        active = false;
-        return this;
-    }
-
-    /**
-     * Physics.util.ticker.on( listener( time ) ) -> this
-     * - listener (Function): The callback function
-     * - time (Number): The current timestamp
-     *
-     * Subscribe a callback to the ticker.
-     **/
-    function on( listener ){
-
-        ps.on('tick', listener);
-        return this;
-    }
-
-    /**
-     * Physics.util.ticker.off( listener ) -> this
-     * - listener (Function): The callback function previously bound
-     *
-     * Unsubscribe a callback from the ticker.
-     **/
-    function off( listener ){
-
-        ps.off('tick', listener);
-        return this;
-    }
-
-    /**
-     * Physics.util.ticker.isActive() -> Boolean
-     * + (Boolean): `true` if running, `false` otherwise.
-     *
-     * Determine if ticker is currently running.
-     **/
-    function isActive(){
-
-        return !!active;
-    }
-
-    // API
-    Physics.util.ticker = {
-        now: now,
-        start: start,
-        stop: stop,
-        on: on,
-        off: off,
-        isActive: isActive
-    };
-
-}(this));
-
-
-// ---
-// inside: src/core/query.js
-
-(function (window) {
-
-    /*
-     * Group helpers
-     */
-    var fnTrue = function(){ return !0; }; // return true
-    
-    var indexOf = Physics.util.indexOf;
-
-    /** hide
-     * wrapRule( fn( propVal ), prop ) -> Function
-     * - fn (Function): The test function
-     * - prop (String): The property name to test
-     * - propVal (Mixed): The property value
-     * 
-     * Get test function to test on sub property.
-     **/
-    var wrapRule = function wrapRule( fn, prop ){
-        return function( thing ){
-            return fn( thing[ prop ] );
-        };
-    };
-
-    /** hide
-     * $eq( toMatch[, prop] ) -> Function
-     * - toMatch (Mixed): The value to match
-     * - prop (String): The property name to test
-     * 
-     * Get an equality test function.
-     **/
-    var $eq = function $eq( toMatch, prop ){
-        return function( thing ){
-            
-            thing = prop ? thing[ prop ] : thing;
-
-            var fr = 0
-                ,bk
-                ;
-            
-            if ( Physics.util.isArray( thing ) ){
-
-                if ( Physics.util.isArray( toMatch ) ){
-                    // match all
-                    bk = thing.length;
-
-                    // check lengths
-                    if ( bk !== toMatch.length ){
-                        return false;
-                    }
-
-                    while ( fr < bk ){
-                        bk--;
-                        if (
-                            // check front
-                            (indexOf(toMatch, thing[ fr ]) === -1) ||
-                            // check back
-                            (indexOf(toMatch, thing[ bk ]) === -1)
-                        ) {
-                            return false;
-                        }
-                        fr++;
-                    }
-                    return true;
-                } else {
-                    // find in array
-                    return (indexOf( thing, toMatch ) > -1);
-                }
-            }
-
-            // exact match
-            return (thing === toMatch);
-        };
-    };
-
-    /** hide
-     * $ne( toMatch[, prop] ) -> Function
-     * - toMatch (Mixed): The value to match
-     * - prop (String): The property name to test
-     * 
-     * Get a NOT equality test function.
-     **/
-    var $ne = function $ne( toMatch, prop ){
-        var fn = $eq( toMatch, prop );
-        return function( thing ){
-            return !fn( thing );
-        };
-    };
-
-    /** hide
-     * $in( toMatch[, prop] ) -> Function
-     * - toMatch (Array): The array to match
-     * - prop (String): The property name to test
-     * 
-     * Get a test function for matching ANY in array
-     **/
-    var $in = function $in( toMatch, prop ){
-        return function( thing ){
-
-            thing = prop ? thing[ prop ] : thing;
-            
-            var fr = 0
-                ,bk
-                ;
-
-            if ( Physics.util.isArray( thing ) ){
-                bk = thing.length;
-
-                while( fr < bk ){
-                    bk--;
-                    if (
-                        // check front
-                        (indexOf(toMatch, thing[ fr ]) > -1) ||
-                        // check back
-                        (indexOf(toMatch, thing[ bk ]) > -1)
-                    ) {
-                        return true;
-                    }
-                    fr++;
-                }
-                return false;
-            }
-
-            // if thing matches any in array
-            return (indexOf(toMatch, thing) > -1);
-        };
-    };
-
-    /** hide
-     * $nin( toMatch[, prop] ) -> Function
-     * - toMatch (Array): The array to match
-     * - prop (String): The property name to test
-     * 
-     * Get a test function for matching NOT ANY in array
-     **/
-    var $nin = function $nin( toMatch, prop ){
-        var fn = $in( toMatch, prop );
-        return function( thing ){
-            return !fn( thing );
-        };
-    };
-
-    /** hide
-     * $at( point ) -> Function
-     * - point (Vectorish): The point to check
-     * 
-     * Get a test function to match any body who's aabb intersects point
-     **/
-    var $at = function $at( point ){
-        point = new Physics.vector( point );
-        return function( body ){
-            var aabb = body.aabb();
-            return Physics.aabb.contains( aabb, point );
-        };
-    };
-
-    /** hide
-     * $and( first ) -> Function
-     * - first (Function): First function node. `first.next` should have the next function, and so on.
-     * 
-     * Get an AND test function.
-     **/
-    var $and = function $and( first ){
-        return first.next ? function( thing ){
-            var fn = first;
-            while ( fn ){
-
-                if ( !fn( thing ) ){
-                    return false;
-                }
-                fn = fn.next;
-            }
-            return true;
-        } : first;
-    };
-
-    /** hide
-     * $or( first ) -> Function
-     * - first (Function): First function node. `first.next` should have the next function, and so on.
-     * 
-     * Get an OR test function.
-     **/
-    var $or = function $or( first ){
-        return first.next ? function( thing ){
-            var fn = first;
-            while ( fn ){
-
-                if ( fn( thing ) ){
-                    return true;
-                }
-                fn = fn.next;
-            }
-            return false;
-        } : first;
-    };
-
-    // operation hash
-    var operations = {
-        // $and and $or are separate
-        $eq: $eq
-        ,$ne: $ne
-        ,$in: $in
-        ,$nin: $nin
-        ,$at: $at
-    };
-
-    /** related to: Physics.world#find
-     * Physics.query( rules ) -> Function
-     * - rules (Object): The mongodb-like search rules. (See description).
-     * + (Function): The test function
-     * 
-     * Creates a function that can be used to perform tests on objects.
-     *
-     * The test function will return a [[Boolean]]; `true` if the object matches the tests.
-     *
-     * Query rules are mongodb-like. You can specify a hash of values to match like this:
-     *
-     * ```javascript
-     * {
-     *     foo: 'bar',
-     *     baz: 2,
-     *     some: {
-     *         nested: 'value'
-     *     }
-     * }
-     * ```
-     *
-     * And they will all need to match (it's an AND rule).
-     *
-     * You can also use operators for more versatility. The operators you can use include:
-     *
-     * - $eq: Test if some property is equal to a value (this is done by default, and is thus redundant)
-     * - $ne: Test if some property is _NOT_ equal to a value
-     * - $in: Test if some value (or array of values) is one of the specified array of values
-     * - $nin: Test if some value (or array of values) is _NOT_ one of the specified array of values
-     * - $at: Test if a body's [[Physics.aabb]] includes specified point. It's a primative hit-test.
-     * 
-     * Example:
-     *
-     * ```javascript
-     * var wheelsArray = [];
-     * 
-     * var queryFn = Physics.query({
-     *     name: 'circle', // only circles
-     *     $nin: wheelsArray, // not in the wheelsArray
-     *     labels: { $in: [ 'player', 'monster' ] } // that have player OR monster labels
-     * });
-     *
-     * var obj = {
-     *     name: 'circle',
-     *     labels: [ 'round' ]
-     * };
-     *
-     * queryFn( obj ); // -> false
-     * // give it a player tag
-     * obj.labels.push('player');
-     * queryFn( obj ); // -> true
-     * // put it inside the wheelsArray
-     * wheelsArray.push( obj );
-     * queryFn( obj ); // -> false
-     * ```
-     **/
-    var Query = function Query( rules, /* internal use */ $op ){
-
-        var op
-            ,l
-            ,rule
-            ,first
-            ,list
-            ,fn
-            ;
-
-        if ( $op ){
-            
-            // parse operation choice
-            if ( $op === '$or' || $op === '$and' ){
-
-                // expect a rules array
-                for ( op = 0, l = rules.length; op < l; ++op ){
-                    
-                    fn = Query( rules[ op ] );
-                    // if first hasn't been set yet, set it and start the list there
-                    // otherwise set the next node of the list
-                    list = list ? list.next = fn : first = fn;
-                }
-
-                return ($op === '$or') ? $or( first ) : $and( first );
-            } else if ( op = operations[ $op ] ){
-
-                return op( rules );
-
-            } else {
-                // does not compute...
-                throw 'Unknown query operation: ' + $op;
-            }
-        }
-
-        // loop through rules
-        for ( op in rules ){
-            rule = rules[ op ];
-   
-            if ( op[0] === '$' ){
-                // it's an operation rule
-                fn = Query( rule, op );
-                
-            } else if ( Physics.util.isPlainObject( rule ) ) {
-                // it's an object so parse subrules
-                fn = wrapRule( Query( rule ), op );
-            } else {
-                // simple equality rule
-                fn = $eq( rule, op );
-            }
-
-            // if first hasn't been set yet, set it and start the list there
-            // otherwise set the next node of the list
-            list = list ? list.next = fn : first = fn;
-        }
-
-        // return the rules test
-        return $and( first || fnTrue );
-    };
-
-    Physics.query = Query;
-
-})(this);
-
-
-// ---
-// inside: src/core/behavior.js
-
-(function(){
-
-    var defaults = {
-        priority: 0
-    };
-
-    /** related to: Physics.util.decorator
-     * Physics.behavior( name[, options] ) -> Behavior
-     * - name (String): The name of the behavior to create
-     * - options (Object): The configuration for that behavior ( depends on behavior ).
-       Available options and defaults:
-       
-       ```javascript
-        {
-           priority: 0 // the priority of this body
-        }
-       ```
-     *
-     * Factory function for creating Behaviors.
-     *
-     * Visit [the PhysicsJS wiki on Behaviors](https://github.com/wellcaffeinated/PhysicsJS/wiki/Behaviors)
-     * for usage documentation.
-     **/
-    Physics.behavior = Decorator('behavior', {
-
-        /** belongs to: Physics.behavior
-         * class Behavior
-         *
-         * The base class for behaviors created by [[Physics.behavior]] factory function.
-         **/
-
-        /** internal
-         * Behavior#init( options )
-         * - options (Object): The configuration options passed by the factory
-         * 
-         * Initialization. Internal use.
-         **/
-        init: function( options ){
-            
-            /** related to: Physics.util.options
-             * Behavior#options( options ) -> Object
-             * - options (Object): The options to set as an object
-             * + (Object): The options
-             * 
-             * Set options on this instance. 
-             * 
-             * Access options directly from the options object.
-             * 
-             * Example:
-             *
-             * ```javascript
-             * this.options.someOption;
-             * ```
-             * 
-             **/
-            this.options = Physics.util.options( defaults );
-            this.options( options );
-        },
-
-        /**
-         * Behavior#applyTo( arr ) -> this
-         * - arr (Array): Array of bodies to apply this behavior to. Specify `true` for all objects in world.
-         * 
-         * Apply the behavior to a group of bodies.
-         **/
-        applyTo: function( arr ){
-
-            if ( arr === true ){
-                this._targets = null;
-            } else {
-                this._targets = Physics.util.uniq( arr );
-            }
-            return this;
-        },
-
-        /**
-         * Behavior#getTargets() -> Array
-         * + (Array): The array of bodies (by reference!) this behavior is applied to.
-         * 
-         * Get the array of bodies (by reference!) this behavior is applied to.
-         **/
-        getTargets: function(){
-            
-            return this._targets || ( this._world ? this._world._bodies : [] );
-        },
-
-        /**
-         * Behavior#setWorld( world ) -> this
-         * - world (Object): The world (or null)
-         *
-         * Set which world to apply to.
-         *
-         * Usually this is called internally. Shouldn't be a need to call this yourself usually.
-         **/
-        setWorld: function( world ){
-
-            if ( this.disconnect && this._world ){
-                this.disconnect( this._world );
-            }
-
-            this._world = world;
-
-            if ( this.connect && world ){
-                this.connect( world );
-            }
-
-            return this;
-        },
-
-        /**
-         * Behavior#connect( world )
-         * - world (Physics.world): The world to connect to
-         * 
-         * Connect to a world.
-         *
-         * Extend this when creating behaviors if you need to specify pubsub management.
-         * Automatically called when added to world by the [[Behavior#setWorld]] method.
-         **/
-        connect: function( world ){
-
-            if (this.behave){
-                world.on('integrate:positions', this.behave, this, this.options.priority);
-            }
-        },
-
-        /**
-         * Behavior#disconnect( world )
-         * - world (Physics.world): The world to disconnect from
-         * 
-         * Disconnect from a world.
-         *
-         * Extend this when creating behaviors if you need to specify pubsub management.
-         * Automatically called when added to world by the [[Behavior#setWorld]] method.
-         **/
-        disconnect: function( world ){
-
-            if (this.behave){
-                world.off('integrate:positions', this.behave, this);
-            }
-        },
-
-        /**
-         * Behavior#behave( data )
-         * - data (Object): The pubsub `integrate:positions` event data
-         * 
-         * Default method run on every world integration.
-         *
-         * You _must_ extend this when creating a behavior,
-         * unless you extend the [[Behavior#connect]] and [[Behavior#disconnect]] methods.
-         **/
-        behave: null
-    });
-
-}());
-
-// ---
-// inside: src/core/body.js
-
-(function(){
-
-    var defaults = {
-
-        // is the body hidden (not to be rendered)?
-        hidden: false,
-        // is the body `dynamic`, `kinematic` or `static`?
-        // http://www.box2d.org/manual.html#_Toc258082973
-        treatment: 'dynamic',
-        // body mass
-        mass: 1.0,
-        // body restitution. How "bouncy" is it?
-        restitution: 1.0,
-        // what is its coefficient of friction with another surface with COF = 1?
-        cof: 0.8,
-        // what is the view object (mixed) that should be used when rendering?
-        view: null
-    };
-
-    var uidGen = 1;
-
-    var Pi2 = Math.PI * 2;
-    function cycleAngle( ang ){
-        return ((ang % Pi2) + Pi2) % Pi2;
-    }
-
-    /** related to: Physics.util.decorator
-     * Physics.body( name[, options] ) -> Body
-     * - name (String): The name of the body to create
-     * - options (Object): The configuration for that body ( depends on body ).
-       Available options and defaults:
-
-       ```javascript
-        {
-            // is the body hidden (not to be rendered)?
-            hidden: false,
-            // is the body `dynamic`, `kinematic` or `static`?
-            // http://www.box2d.org/manual.html#_Toc258082973
-            treatment: 'dynamic',
-            // body mass
-            mass: 1.0,
-            // body restitution. How "bouncy" is it?
-            restitution: 1.0,
-            // what is its coefficient of friction with another surface with COF = 1?
-            cof: 0.8,
-            // what is the view object (mixed) that should be used when rendering?
-            view: null,
-            // the vector offsetting the geometry from its center of mass
-            offset: Physics.vector(0,0)
-        }
-       ```
-     *
-     * Factory function for creating Bodies.
-     *
-     * Visit [the PhysicsJS wiki on Bodies](https://github.com/wellcaffeinated/PhysicsJS/wiki/Bodies)
-     * for usage documentation.
-     **/
-    Physics.body = Decorator('body', {
-
-        /** belongs to: Physics.body
-         * class Body
-         *
-         * The base class for bodies created by [[Physics.body]] factory function.
-         **/
-
-        /** internal
-         * Body#init( options )
-         * - options (Object): The configuration options passed by the factory
-         *
-         * Initialization. Internal use.
-         **/
-        init: function( options ){
-
-            var self = this;
-            var vector = Physics.vector;
-
-            /** related to: Physics.util.options
-             * Body#options( options ) -> Object
-             * - options (Object): The options to set as an object
-             * + (Object): The options
-             *
-             * Set options on this instance.
-             *
-             * Access options directly from the options object.
-             *
-             * Example:
-             *
-             * ```javascript
-             * this.options.someOption;
-             * ```
-             *
-             **/
-            // all options get copied onto the body.
-            this.options = Physics.util.options( defaults, this );
-            this.options.onChange(function( opts ){
-                self.offset = new vector( opts.offset );
-            });
-            this.options( options );
-
-            /**
-             * Body#state
-             *
-             * The physical state container.
-             *
-             * - ``this.state.pos`` ([[Physics.vector]]) The position vector.
-             * - ``this.state.vel`` ([[Physics.vector]]) The velocity vector.
-             * - ``this.state.acc`` ([[Physics.vector]]) The acceleration vector.
-             * - ``this.state.angular.pos`` ([[Number]]) The angular position (in radians, positive is clockwise starting along the x axis)
-             * - ``this.state.angular.vel`` ([[Number]]) The angular velocity
-             * - ``this.state.angular.acc`` ([[Number]]) The angular acceleration
-             *
-             * Properties from the previous timestep are stored in:
-             * ```javascript
-             * this.state.old; // .pos, .vel, ...
-             * ```
-             **/
-            this.state = {
-                pos: new vector( this.x, this.y ),
-                vel: new vector( this.vx, this.vy ),
-                acc: new vector(),
-                angular: {
-                    pos: this.angle || 0.0,
-                    vel: this.angularVelocity || 0.0,
-                    acc: 0.0
-                },
-                old: {
-                    pos: new vector(),
-                    vel: new vector(),
-                    acc: new vector(),
-                    angular: {
-                        pos: 0.0,
-                        vel: 0.0,
-                        acc: 0.0
-                    }
-                }
-            };
-
-            // private storage for sleeping
-            this._sleepAngPosMean = 0;
-            this._sleepAngPosVariance = 0;
-            this._sleepPosMean = new vector();
-            this._sleepPosVariance = new vector();
-            this._sleepMeanK = 0;
-
-            // cleanup
-            delete this.x;
-            delete this.y;
-            delete this.vx;
-            delete this.vy;
-            delete this.angle;
-            delete this.angularVelocity;
-
-            if (this.mass === 0){
-                throw "Error: Bodies must have non-zero mass";
-            }
-
-            /**
-             * Body#uid = Number
-             *
-             * The unique id for the body
-             **/
-            this.uid = uidGen++;
-
-            /** related to: Physics.geometry
-             * Body#geometry
-             *
-             * The geometry for this body.
-             *
-             * By default it is a `point` geometry which gets overridden.
-             **/
-            this.geometry = Physics.geometry('point');
-
-            /**
-             * Body#mass = 1.0
-             *
-             * The mass.
-             **/
-
-            /**
-             * Body#offset
-             *
-             * The vector offsetting the body's shape from its center of mass.
-             **/
-
-             /**
-              * Body#restitution = 1.0
-              *
-              * The restitution.
-              *
-              * This is the "bounciness" of the body.
-              * It's a number between `0` and `1`.
-              *
-              * A restitution of 1 is the bounciest.
-              *
-              * A restitution of 0 is not bouncy.
-              *
-              * When colliding the restitutions of bodies are
-              * multiplied together to get the restitution between two
-              * bodies.
-              *
-              **/
-
-              /**
-               * Body#cof = 0.8
-               *
-               * The coefficient of friction of the body.
-               *
-               * It's how much "slide" it has during collisions.
-               *
-               * A `cof` of `0` will really slidy.
-               *
-               * A `cof` of `1` has no slide.
-               *
-               * This is a very simplistic implementation at the moment.
-               * What would be better is to have both static and kinetic
-               * friction. But that's not done yet.
-               **/
-
-               /**
-                * Body#treatment = String
-                *
-                * How the body is treated by the simulation.
-                *
-                * The body can be `dynamic`, `kinematic` or `static` as
-                * described by the [analogous box2d docs](http://www.box2d.org/manual.html#_Toc258082973).
-                *
-                * * _dynamic_ bodies are treated "normally". They are integrated, and collide, and all that.
-                * * _kinematic_ bodies are bodies that move at a specified velocity. Other bodies collide with them, but they don't bounce off of other bodies.
-                * * _static_ bodies just stand still. They are like obstacles.
-                **/
-
-                /**
-                 * Body#hidden = false
-                 *
-                 * Determines whether the body should be hidden by the renderer.
-                 **/
-
-                /** related to: Physics.renderer
-                 * Body#view = it_depends
-                 *
-                 * Storage for use by the renderer.
-                 *
-                 * The type of renderer will put different things in the view property.
-                 * Basically, this is how the body "looks". It could be a HTMLElement, or
-                 * an Image, etc...
-                 *
-                 * If your body changes appearance (shape), you should modify this somehow
-                 * otherwise the renderer will keep using this same view. If you're letting
-                 * the renderer create the view for you, just set this to `undefined` if the
-                 * body gets modified in shape during the simulation.
-                 **/
-
-                /** related to: Physics.renderer
-                 * Body#styles
-                 *
-                 * The styles the renderer should use for creating the view.
-                 *
-                 * The styles depend on the renderer. See [[Renderer#createView]] for style options.
-                 **/
-        },
-
-        /**
-         * Body#sleep( [dt] ) -> Boolean
-         * - dt (Number): Time to advance the idle time
-         * - dt (Boolean): If `true`, the body will be forced to sleep. If `false`, the body will be forced to awake.
-         *
-         * Get and/or set whether the body is asleep.
-         *
-         * If called with a time (in ms), the time will be added to the idle time and sleep conditions will be checked.
-         **/
-        sleep: function( dt ){
-
-            if ( dt === true ){
-                // force sleep
-                this.asleep = true;
-
-            } else if ( dt === false ){
-                // force wakup
-                this.asleep = false;
-                this._sleepMeanK = 0;
-                this._sleepAngPosMean = 0;
-                this._sleepAngPosVariance = 0;
-                this._sleepPosMean.zero();
-                this._sleepPosVariance.zero();
-                this.sleepIdleTime = 0;
-
-            } else if ( dt && !this.asleep ) {
-
-                this.sleepCheck( dt );
-            }
-
-            return this.asleep;
-        },
-
-        /**
-         * Body#sleepCheck( [dt] )
-         * - dt (Number): Time to advance the idle time
-         *
-         * Check if the body should be sleeping.
-         *
-         * Call with no arguments if some event could possibly wake up the body. This will force the body to recheck.
-         **/
-        sleepCheck: function( dt ){
-
-            var opts = this._world && this._world.options;
-
-            // if sleeping disabled. stop.
-            if ( this.sleepDisabled || (opts && opts.sleepDisabled) ){
-                return;
-            }
-
-            var limit
-                ,v
-                ,d
-                ,r
-                ,aabb
-                ,scratch = Physics.scratchpad()
-                ,diff = scratch.vector()
-                ,diff2 = scratch.vector()
-                ,kfac
-                ,stats
-                ;
-
-            dt = dt || 0;
-            aabb = this.geometry.aabb();
-            r = Math.max(aabb.hw, aabb.hh);
-
-            if ( this.asleep ){
-                // check velocity
-                v = this.state.vel.norm() + Math.abs(r * this.state.angular.vel);
-                limit = this.sleepSpeedLimit || (opts && opts.sleepSpeedLimit) || 0;
-
-                if ( v >= limit ){
-                    this.sleep( false );
-                    return scratch.done();
-                }
-            }
-
-            this._sleepMeanK++;
-            kfac = this._sleepMeanK > 1 ? 1/(this._sleepMeanK - 1) : 0;
-            Physics.statistics.pushRunningVectorAvg( this.state.pos, this._sleepMeanK, this._sleepPosMean, this._sleepPosVariance );
-            // we take the sin because that maps the discontinuous angle to a continuous value
-            // then the statistics calculations work better
-            stats = Physics.statistics.pushRunningAvg( Math.sin(this.state.angular.pos), this._sleepMeanK, this._sleepAngPosMean, this._sleepAngPosVariance );
-            this._sleepAngPosMean = stats[0];
-            this._sleepAngPosVariance = stats[1];
-            v = this._sleepPosVariance.norm() + Math.abs(r * Math.asin(stats[1]));
-            v *= kfac;
-            limit = this.sleepVarianceLimit || (opts && opts.sleepVarianceLimit) || 0;
-            // console.log(v, limit, kfac, this._sleepPosVariance.norm(), stats[1])
-            if ( v <= limit ){
-                // check idle time
-                limit = this.sleepTimeLimit || (opts && opts.sleepTimeLimit) || 0;
-                this.sleepIdleTime = (this.sleepIdleTime || 0) + dt;
-
-                if ( this.sleepIdleTime > limit ){
-                    this.asleep = true;
-                }
-            } else {
-                this.sleep( false );
-            }
-
-            scratch.done();
-        },
-
-        /**
-         * Body#setWorld( world ) -> this
-         * - world (Object): The world (or null)
-         *
-         * Set which world to apply to.
-         *
-         * Usually this is called internally. Shouldn't be a need to call this yourself usually.
-         **/
-        setWorld: function( world ){
-
-            if ( this.disconnect && this._world ){
-                this.disconnect( this._world );
-            }
-
-            this._world = world;
-
-            if ( this.connect && world ){
-                this.connect( world );
-            }
-
-            return this;
-        },
-
-        /**
-         * Body#accelerate( acc ) -> this
-         * - acc (Physics.vector): The acceleration vector
-         *
-         * Accelerate the body by adding supplied vector to its current acceleration
-         **/
-        accelerate: function( acc ){
-
-            if ( this.treatment === 'dynamic' ){
-                this.state.acc.vadd( acc );
-            }
-
-            return this;
-        },
-
-        /**
-         * Body#applyForce( force[, p] ) -> this
-         * - force (Vectorish): The force vector
-         * - p (Vectorish): The point vector from the COM at which to apply the force
-         *
-         * Apply a force at center of mass, or at point `p` relative to the center of mass
-         **/
-        applyForce: function( force, p ){
-
-            if ( this.treatment !== 'dynamic' ){
-                return this;
-            }
-
-            var scratch = Physics.scratchpad()
-                ,r = scratch.vector()
-                ,state
-                ;
-
-            // if no point at which to apply the force... apply at center of mass
-            if ( p && this.moi ){
-
-                // apply torques
-                state = this.state;
-                r.clone( p );
-                // r cross F
-                this.state.angular.acc -= r.cross( force ) / this.moi;
-            }
-
-            this.accelerate( r.clone( force ).mult( 1/this.mass ) );
-
-            scratch.done();
-            return this;
-        },
-
-        /** related to: Body#offset
-         * Body#getGlobalOffset( [out] ) -> Physics.vector
-         * - out (Physics.vector): A vector to use to put the result into. One is created if `out` isn't specified.
-         * + (Physics.vector): The offset in global coordinates
-         *
-         * Get the body offset vector (from the center of mass) for the body's shape in global coordinates.
-         **/
-        getGlobalOffset: function( out ){
-
-            out = out || new Physics.vector();
-            out.clone( this.offset ).rotate( this.state.angular.pos );
-            return out;
-        },
-
-        /** related to: Physics.aabb
-         * Body#aabb() -> Object
-         * + (Object): The aabb of this body
-         *
-         * Get the Axis aligned bounding box for the body in its current position and rotation
-         **/
-        aabb: function(){
-
-            var angle = this.state.angular.pos
-                ,scratch = Physics.scratchpad()
-                ,v = scratch.vector()
-                ,aabb = this.geometry.aabb( angle )
-                ;
-
-            this.getGlobalOffset( v );
-
-            aabb.x += this.state.pos._[0] + v._[0];
-            aabb.y += this.state.pos._[1] + v._[1];
-
-            return scratch.done( aabb );
-        },
-
-        /**
-         * Body#toBodyCoords( v ) -> Physics.vector
-         * - v (Physics.vector): The vector to transform
-         * + (Physics.vector): The transformed vector
-         *
-         * Transform a vector into coordinates relative to this body.
-         **/
-        toBodyCoords: function( v ){
-            return v.vsub( this.state.pos ).rotate( -this.state.angular.pos );
-        },
-
-        /**
-          * Body#toWorldCoords( v ) -> Physics.vector
-          * - v (Physics.vector): The vector to transform
-          * + (Physics.vector): The transformed vector
-          *
-          * Transform a vector from body coordinates into world coordinates.
-          **/
-        toWorldCoords: function( v ){
-            return v.rotate( this.state.angular.pos ).vadd( this.state.pos );
-        },
-
-        /**
-         * Body#recalc() -> this
-         *
-         * Recalculate properties.
-         *
-         * Intended to be overridden by subclasses. Call when body physical properties are changed.
-         **/
-        recalc: function(){
-            // override to recalculate properties
-            return this;
-        }
-    });
-
-    /**
-     * Body.getCOM( bodies[, com] ) -> Physics.vector
-     * - bodies (Array): The list of bodies
-     * - com (Physics.vector): The vector to put result into. A new vector will be created if not provided.
-     * + (Physics.vector): The center of mass position
-     *
-     * Get center of mass position from list of bodies.
-     **/
-    Physics.body.getCOM = function( bodies, com ){
-        // @TODO add a test for this fn
-        var b
-            ,pos
-            ,i
-            ,l = bodies && bodies.length
-            ,M = 0
-            ;
-
-        com = com || new Physics.vector();
-
-        if ( !l ){
-            return com.zero();
-        }
-
-        if ( l === 1 ){
-            return com.clone( bodies[0].state.pos );
-        }
-
-        com.zero();
-
-        for ( i = 0; i < l; i++ ){
-            b = bodies[ i ];
-            pos = b.state.pos;
-            com.add( pos._[0] * b.mass, pos._[1] * b.mass );
-            M += b.mass;
-        }
-
-        com.mult( 1 / M );
-
-        return com;
-    };
-
-}());
-
-
-// ---
-// inside: src/core/geometry.js
-
-(function(){
-    /** related to: Physics.util.decorator
-     * Physics.geometry( name[, options] ) -> Geometry
-     * - name (String): The name of the geometry to create
-     * - options (Object): The configuration for that geometry ( depends on geometry ).
-     *
-     * Factory function for creating Geometries.
-     *
-     * Visit [the PhysicsJS wiki on Geometries](https://github.com/wellcaffeinated/PhysicsJS/wiki/Geometries)
-     * for usage documentation.
-     **/
-    Physics.geometry = Decorator('geometry', {
-
-        /** belongs to: Physics.geometry
-         * class Geometry
-         *
-         * The base class for geometries created by [[Physics.geometry]] factory function.
-         **/
-
-        /** internal
-         * Geometry#init( options )
-         * - options (Object): The configuration options passed by the factory
-         * 
-         * Initialization. Internal use.
-         **/
-        init: function( options ){
-
-            /** related to: Physics.util.options
-             * Geometry#options( options ) -> Object
-             * - options (Object): The options to set as an object
-             * + (Object): The options
-             * 
-             * Set options on this instance. 
-             * 
-             * Access options directly from the options object.
-             * 
-             * Example:
-             *
-             * ```javascript
-             * this.options.someOption;
-             * ```
-             * 
-             **/
-            this.options = Physics.util.options();
-            this.options( options );
-
-            this._aabb = new Physics.aabb();
-        },
-        
-        /** related to: Physics.aabb
-         * Geometry#aabb( angle ) -> Object
-         * - angle (Number): The angle to rotate the geometry
-         * + (Object): Bounding box values
-         * 
-         * Get axis-aligned bounding box for this object (rotated by angle if specified).
-         **/
-        aabb: function( angle ){
-
-            return Physics.aabb.clone(this._aabb);
-        },
-
-        /**
-         * Geometry#getFarthestHullPoint( dir[, result] ) -> Physics.vector
-         * - dir (Physics.vector): Direction to look
-         * - result (Physics.vector): A vector to write result to. Speeds up calculations.
-         * + (Physics.vector): The farthest hull point in local coordinates
-         * 
-         * Get farthest point on the hull of this geometry
-         * along the direction vector `dir`
-         * returns local coordinates. Replaces result if provided.
-         *
-         * Assume all coordinates are relative to the geometry 
-         * centroid (IE: in the body frame).
-         * 
-         * This should take a direction vector then it should
-         * calculate the location (in that frame of reference)
-         * of the point on the perimeter (hull) if you traveled
-         * in a straight line from the centroid in the provided
-         * direction. The result should be returned/set just like
-         * it is in the other geometries.
-         **/
-        getFarthestHullPoint: function( dir, result ){
-
-            result = result || new Physics.vector();
-
-            // not implemented.
-            return result.set( 0, 0 );
-        },
-
-        /** related to: Geometry#getFarthestHullPoint
-         * Geometry#getFarthestCorePoint( dir[, result] ) -> Physics.vector
-         * - dir (Physics.vector): Direction to look
-         * - result (Physics.vector): A vector to write result to. Speeds up calculations.
-         * + (Physics.vector): The farthest hull point in local coordinates
-         * 
-         * Get farthest point on the core shape of this geometry
-         * along the direction vector `dir`
-         * returns local coordinates. Replaces result if provided.
-         *
-         * This does almost the same thing as [[Geometry#getFarthestHullPoint]]
-         * but shrinks the shape by subtracting "margin" from it.
-         * Return the position of the point on the "core" shape.
-         **/
-        getFarthestCorePoint: function( dir, result, margin ){
-
-            result = result || new Physics.vector();
-
-            // not implemented.
-            return result.set( 0, 0 );
-        }
-    });
-
-}());
-
-// ---
-// inside: src/core/geometry-helpers.js
-
-/*
- * Geometry helper functions
- */
-
-/**
- * Physics.geometry.regularPolygonVertices( sides, radius ) -> Array
- * - sides (Number): Number of sides the polygon has
- * - radius (Number): Size from center to a vertex
- * + (Array): A list of [[Vectorish]] objects representing the vertices
- *
- * Generate a list of vertices for a regular polygon of any number of sides.
- **/
-Physics.geometry.regularPolygonVertices = function( sides, radius ){
-    var verts = []
-        ,angle = Math.PI * 2 / sides
-        ,a = 0
-        ,i
-        ;
-
-    for ( i = 0; i < sides; i++ ){
-        verts.push({
-            x: radius * Math.cos( a )
-            ,y: radius * Math.sin( a )
-        });
-
-        a += angle;
-    }
-
-    return verts;
-};
-
-/**
- * Physics.geometry.isPolygonConvex( hull ) -> Boolean
- * - hull (Array): Array of ([[Vectorish]]) vertices
- * + (Boolean): `true` if the polygon is convex. `false` otherwise.
- *
- * Determine if polygon hull is convex
- **/
-Physics.geometry.isPolygonConvex = function( hull ){
-
-    var scratch = Physics.scratchpad()
-        ,prev = scratch.vector()
-        ,next = scratch.vector()
-        ,tmp = scratch.vector()
-        ,ret = true
-        ,sign = false
-        ,l = hull.length
-        ;
-
-    if ( !hull || !l ){
-        return false;
-    }
-
-    if ( l < 3 ){
-        // it must be a point or a line...
-        // which are convex
-        scratch.done();
-        return ret;
-    }
-
-    prev.clone( hull[ 0 ] ).vsub( tmp.clone( hull[ l - 1 ] ) );
-
-    // loop over the edges of the hull and construct vectors of the current
-    // edge and retain the last edge
-    // add two to the length to do a full cycle
-    for ( var i = 1; i <= l; ++i ){
-
-        next.clone( hull[ i % l ] ).vsub( tmp.clone( hull[ (i - 1) % l ] ) );
-
-        if ( sign === false ){
-
-            // first check the sign of the first cross product
-            sign = prev.cross( next );
-
-        } else if ( (sign > 0) ^ (prev.cross( next ) > 0) ){
-
-            // if the cross products are different signs it's not convex
-            ret = false;
-            break;
-        }
-
-        // remember the last edge
-        next.swap( prev );
-    }
-
-    scratch.done();
-    return ret;
-};
-
-/**
- * Physics.geometry.getPolygonMOI( hull ) -> Number
- * - hull (Array): Array of ([[Vectorish]]) vertices
- * + (Number): The polygon's moment of inertia
- *
- * Gets the moment of inertia of a convex polygon
- *
- * See [List of moments of inertia](http://en.wikipedia.org/wiki/List_of_moments_of_inertia)
- * for more information.
- *
- * _Note_: we make the following assumpations:
- * * mass is unitary (== 1)
- * * axis of rotation is the origin
- **/
-Physics.geometry.getPolygonMOI = function( hull ){
-
-    var scratch = Physics.scratchpad()
-        ,prev = scratch.vector()
-        ,next = scratch.vector()
-        ,num = 0
-        ,denom = 0
-        ,tmp
-        ,l = hull.length
-        ;
-
-    if ( l < 2 ){
-        // it must be a point
-        // moi = 0
-        scratch.done();
-        return 0;
-    }
-
-    if ( l === 2 ){
-        // it's a line
-        // get length squared
-        tmp = next.clone( hull[ 1 ] ).distSq( prev.clone( hull[ 0 ] ) );
-        scratch.done();
-        return tmp / 12;
-    }
-
-    prev.clone( hull[ 0 ] );
-
-    for ( var i = 1; i < l; ++i ){
-
-        next.clone( hull[ i ] );
-
-        tmp = Math.abs( next.cross( prev ) );
-        num += tmp * ( next.normSq() + next.dot( prev ) + prev.normSq() );
-        denom += tmp;
-
-        prev.swap( next );
-    }
-
-    scratch.done();
-    return num / ( 6 * denom );
-};
-
-/**
- * Physics.geometry.isPointInPolygon( pt, hull ) -> Boolean
- * - pt (Vectorish): The point to test
- * - hull (Array): Array of ([[Vectorish]]) vertices
- * + (Boolean): `true` if point `pt` is inside the polygon
- *
- * Check if point is inside polygon hull.
- **/
-Physics.geometry.isPointInPolygon = function( pt, hull ){
-
-    var scratch = Physics.scratchpad()
-        ,point = scratch.vector().clone( pt )
-        ,prev = scratch.vector()
-        ,next = scratch.vector()
-        ,ang = 0
-        ,l = hull.length
-        ;
-
-    if ( l < 2 ){
-        // it's a point...
-        ang = point.equals( prev.clone( hull[ 0 ] ));
-        scratch.done();
-        return ang;
-    }
-
-    if ( l === 2 ){
-        // it's a line
-        ang = point.angle( prev.clone( hull[ 0 ] ));
-        ang += point.angle( prev.clone( hull[ 1 ] ));
-        scratch.done();
-        return ( Math.abs(ang) === Math.PI );
-    }
-
-    prev.clone( hull[ 0 ] ).vsub( point );
-
-    // calculate the sum of angles between vector pairs
-    // from point to vertices
-    for ( var i = 1; i <= l; ++i ){
-
-        next.clone( hull[ i % l ] ).vsub( point );
-        ang += next.angle( prev );
-        prev.swap( next );
-    }
-
-    scratch.done();
-    return ( Math.abs(ang) > 1e-6 );
-};
-
-/**
- * Physics.geometry.getPolygonArea( hull ) -> Number
- * - hull (Array): Array of ([[Vectorish]]) vertices
- * + (Number): The area (positive for clockwise ordering)
- *
- * Get the signed area of the polygon.
- **/
-Physics.geometry.getPolygonArea = function getPolygonArea( hull ){
-
-    var scratch = Physics.scratchpad()
-        ,prev = scratch.vector()
-        ,next = scratch.vector()
-        ,ret = 0
-        ,l = hull.length
-        ;
-
-    if ( l < 3 ){
-        // it must be a point or a line
-        // area = 0
-        scratch.done();
-        return 0;
-    }
-
-    prev.clone( hull[ l - 1 ] );
-
-    for ( var i = 0; i < l; ++i ){
-
-        next.clone( hull[ i ] );
-
-        ret += prev.cross( next );
-
-        prev.swap( next );
-    }
-
-    scratch.done();
-    return ret / 2;
-};
-
-/**
- * Physics.geometry.getPolygonCentroid( hull ) -> Physics.vector
- * - hull (Array): Array of ([[Vectorish]]) vertices
- * + (Physics.vector): The centroid
- *
- * Get the coordinates of the centroid.
- **/
-Physics.geometry.getPolygonCentroid = function getPolygonCentroid( hull ){
-
-    var scratch = Physics.scratchpad()
-        ,prev = scratch.vector()
-        ,next = scratch.vector()
-        ,ret = new Physics.vector()
-        ,tmp
-        ,l = hull.length
-        ;
-
-    if ( l < 2 ){
-        // it must be a point
-        scratch.done();
-        return new Physics.vector( hull[0] );
-    }
-
-    if ( l === 2 ){
-        // it's a line
-        // get the midpoint
-        scratch.done();
-        return new Physics.vector((hull[ 1 ].x + hull[ 0 ].x)/2, (hull[ 1 ].y + hull[ 0 ].y)/2 );
-    }
-
-    prev.clone( hull[ l - 1 ] );
-
-    for ( var i = 0; i < l; ++i ){
-
-        next.clone( hull[ i ] );
-
-        tmp = prev.cross( next );
-        prev.vadd( next ).mult( tmp );
-        ret.vadd( prev );
-
-        prev.swap( next );
-    }
-
-    tmp = 1 / (6 * Physics.geometry.getPolygonArea( hull ));
-
-    scratch.done();
-    return ret.mult( tmp );
-};
-
-/**
- * Physics.geometry.nearestPointOnLine( pt, linePt1, linePt2 ) -> Physics.vector
- * - pt (Vectorish): The point
- * - linePt1 (Vectorish): The first endpoint of the line
- * - linePt2 (Vectorish): The second endpoint of the line
- * + (Vector): The closest point
- *
- * Get the closest point on a discrete line to specified point.
- **/
-Physics.geometry.nearestPointOnLine = function nearestPointOnLine( pt, linePt1, linePt2 ){
-
-    var scratch = Physics.scratchpad()
-        ,p = scratch.vector().clone( pt )
-        ,A = scratch.vector().clone( linePt1 ).vsub( p )
-        ,L = scratch.vector().clone( linePt2 ).vsub( p ).vsub( A )
-        ,lambdaB
-        ,lambdaA
-        ;
-
-    if ( L.equals(Physics.vector.zero) ){
-        // oh.. it's a zero vector. So A and B are both the closest.
-        // just use one of them
-        scratch.done();
-        return new Physics.vector( linePt1 );
-    }
-
-    lambdaB = - L.dot( A ) / L.normSq();
-    lambdaA = 1 - lambdaB;
-
-    if ( lambdaA <= 0 ){
-        // woops.. that means the closest simplex point
-        // isn't on the line it's point B itself
-        scratch.done();
-        return new Physics.vector( linePt2 );
-    } else if ( lambdaB <= 0 ){
-        // vice versa
-        scratch.done();
-        return new Physics.vector( linePt1 );
-    }
-
-    // guess we'd better do the math now...
-    p = new Physics.vector( linePt2 ).mult( lambdaB ).vadd( A.clone( linePt1 ).mult( lambdaA ) );
-    scratch.done();
-    return p;
-};
-
-
-// ---
-// inside: src/core/integrator.js
-
-(function(){
-
-    var defaults = {
-
-        // drag applied during integration
-        // 0 means vacuum
-        // 0.9 means molasses
-        drag: 0
-    };
-
-    /** related to: Physics.util.decorator
-     * Physics.integrator( name[, options] ) -> Integrator
-     * - name (String): The name of the integrator to create
-     * - options (Object): The configuration for that integrator ( depends on integrator ).
-       Available options and defaults:
-
-       ```javascript
-        {
-            // drag applied during integration
-            // 0 means vacuum
-            // 0.9 means molasses
-            drag: 0
-        }
-       ```
-     *
-     * Factory function for creating Integrators.
-     *
-     * Visit [the PhysicsJS wiki on Integrators](https://github.com/wellcaffeinated/PhysicsJS/wiki/Integrators)
-     * for usage documentation.
-     **/
-    Physics.integrator = Decorator('integrator', {
-
-        /** belongs to: Physics.integrator
-         * class Integrator
-         *
-         * The base class for integrators created by [[Physics.integrator]] factory function.
-         **/
-
-        /** internal
-         * Integrator#init( options )
-         * - options (Object): The configuration options passed by the factory
-         *
-         * Initialization. Internal use.
-         **/
-        init: function( options ){
-
-            /** related to: Physics.util.options
-             * Integrator#options( options ) -> Object
-             * - options (Object): The options to set as an object
-             * + (Object): The options
-             *
-             * Set options on this instance.
-             *
-             * Access options directly from the options object.
-             *
-             * Example:
-             *
-             * ```javascript
-             * this.options.someOption;
-             * ```
-             *
-             **/
-            this.options = Physics.util.options( defaults );
-            this.options( options );
-        },
-
-        /**
-         * Integrator#setWorld( world ) -> this
-         * - world (Object): The world (or null)
-         *
-         * Set which world to apply to.
-         *
-         * Usually this is called internally. Shouldn't be a need to call this yourself usually.
-         **/
-        setWorld: function( world ){
-
-            if ( this.disconnect && this._world ){
-                this.disconnect( this._world );
-            }
-
-            this._world = world;
-
-            if ( this.connect && world ){
-                this.connect( world );
-            }
-
-            return this;
-        },
-
-        /**
-         * Integrator#integrate( bodies, dt ) -> this
-         * - bodies (Array): List of bodies to integrate
-         * - dt (Number): Timestep size
-         *
-         * Integrate bodies by timestep.
-         *
-         * Will emit `integrate:velocities` and `integrate:positions`
-         * events on the world.
-         **/
-        integrate: function( bodies, dt ){
-
-            var world = this._world;
-
-            this.integrateVelocities( bodies, dt );
-
-            if ( world ){
-                world.emit('integrate:velocities', {
-                    bodies: bodies,
-                    dt: dt
-                });
-            }
-
-            this.integratePositions( bodies, dt );
-
-            if ( world ){
-                world.emit('integrate:positions', {
-                    bodies: bodies,
-                    dt: dt
-                });
-            }
-
-            return this;
-        },
-
-        /**
-         * Integrator#connect( world )
-         * - world (Physics.world): The world to connect to
-         *
-         * Connect to a world.
-         *
-         * Extend this when creating integrators if you need to specify pubsub management.
-         * Automatically called when added to world by the [[Integrator#setWorld]] method.
-         **/
-        connect: null,
-
-        /**
-         * Integrator#disconnect( world )
-         * - world (Physics.world): The world to disconnect from
-         *
-         * Disconnect from a world.
-         *
-         * Extend this when creating integrators if you need to specify pubsub management.
-         * Automatically called when added to world by the [[Integrator#setWorld]] method.
-         **/
-        disconnect: null,
-
-        /**
-         * Integrator#integrateVelocities( bodies, dt )
-         * - bodies (Array): List of bodies to integrate
-         * - dt (Number): Timestep size
-         *
-         * Just integrate the velocities.
-         *
-         * Should be overridden when creating integrators.
-         **/
-        integrateVelocities: function( bodies, dt ){
-
-            throw 'The integrator.integrateVelocities() method must be overriden';
-        },
-
-        /**
-         * Integrator#integratePositions( bodies, dt )
-         * - bodies (Array): List of bodies to integrate
-         * - dt (Number): Timestep size
-         *
-         * Just integrate the positions.
-         *
-         * Called after [[Integrator#integrateVelocities]].
-         *
-         * Should be overridden when creating integrators.
-         **/
-        integratePositions: function( bodies, dt ){
-
-            throw 'The integrator.integratePositions() method must be overriden';
-        }
-    });
-
-}());
-
-
-// ---
-// inside: src/core/renderer.js
-
-(function(){
-
-    var defaults = {
-        // draw meta data (fps, steps, etc)
-        meta: false,
-        // refresh rate of meta info
-        metaRefresh: 200,
-
-        // width of viewport
-        width: 600,
-        // height of viewport
-        height: 600,
-        // automatically resize the renderer
-        autoResize: true
-    };
-
-    /** related to: Physics.util.decorator
-     * Physics.renderer( name[, options] ) -> Renderer
-     * - name (String): The name of the renderer to create
-     * - options (Object): The configuration for that renderer ( depends on renderer ).
-       Available options and defaults:
-
-       ```javascript
-        {
-            // draw meta data (fps, steps, etc)
-            meta: false,
-            // refresh rate of meta info
-            metaRefresh: 200,
-
-            // width of viewport
-            width: 600,
-            // height of viewport
-            height: 600
-            // automatically resize the renderer
-            autoResize: true
-        }
-       ```
-     *
-     * Factory function for creating Renderers.
-     *
-     * Visit [the PhysicsJS wiki on Renderers](https://github.com/wellcaffeinated/PhysicsJS/wiki/Renderers)
-     * for usage documentation.
-     **/
-    Physics.renderer = Decorator('renderer', {
-
-        /** belongs to: Physics.renderer
-         * class Renderer
-         *
-         * The base class for renderers created by [[Physics.renderer]] factory function.
-         **/
-
-        /** internal
-         * Renderer#init( options )
-         * - options (Object): The configuration options passed by the factory
-         *
-         * Initialization. Internal use.
-         **/
-        init: function( options ){
-
-            var self = this
-                ,el = typeof options.el === 'string' ? document.getElementById(options.el) : options.el
-                ;
-
-            this.options = Physics.util.options(defaults);
-            this.options( options );
-
-            this.el = el ? el : document.body;
-            this.container = el && el.parentNode ? el.parentNode : document.body;
-            this.drawMeta = Physics.util.throttle( Physics.util.bind(this.drawMeta, this), this.options.metaRefresh );
-
-            window.addEventListener('resize', Physics.util.throttle(function(){
-                if ( self.options.autoResize ){
-                    self.resize();
-                }
-            }), 100);
-        },
-
-        /**
-         * Renderer#resize( [width, height] ) -> this
-         * - width (Number): The width in px
-         * - height (Number): The height in px
-         *
-         * Set the dimensions of the renderer.
-         *
-         * If no dimensions are specified it will auto resize.
-         **/
-        resize: function( width, height ){
-
-            if ( width === undefined && height === undefined ){
-                width = this.container.offsetWidth;
-                height = this.container.offsetHeight;
-            }
-
-            this.width = width || 0;
-            this.height = height || 0;
-            // should be implemented in renderers
-        },
-
-        /**
-         * Renderer#setWorld( world ) -> this
-         * - world (Object): The world (or null)
-         *
-         * Set which world to apply to.
-         *
-         * Usually this is called internally. Shouldn't be a need to call this yourself usually.
-         **/
-        setWorld: function( world ){
-
-            if ( this.disconnect && this._world ){
-                this.disconnect( this._world );
-            }
-
-            this._world = world;
-
-            if ( this.connect && world ){
-                this.connect( world );
-            }
-
-            return this;
-        },
-
-        /**
-         * Renderer#render( bodies, meta ) -> this
-         * - bodies (Array): Array of bodies in the world (by reference!)
-         * - meta (Object): meta information
-         *
-         * Render the world bodies and meta. Called by world.render()
-         **/
-        render: function( bodies, meta ){
-
-            var body
-                ,view
-                ,pos
-                ;
-
-            if (this.beforeRender){
-
-                this.beforeRender();
-            }
-
-            this._world.emit('beforeRender', {
-                renderer: this,
-                bodies: bodies,
-                meta: meta
-            });
-
-            if (this.options.meta){
-                this.drawMeta( meta );
-            }
-
-            this._interpolateTime = meta.interpolateTime;
-
-            for ( var i = 0, l = bodies.length; i < l; ++i ){
-
-                body = bodies[ i ];
-                view = body.view || ( body.view = this.createView(body.geometry, body.styles) );
-
-                if ( !body.hidden ){
-                    this.drawBody( body, view );
-                }
-            }
-
-            return this;
-        },
-
-        /**
-         * Renderer#createView( geometry, styles ) -> Mixed
-         * - geometry (Geometry): geometry The geometry
-         * - styles (Object|String): The styles configuration
-         * + (Mixed): Whatever the renderer needs to render the body.
-         *
-         * Create a view for the specified geometry.
-         *
-         * The view is used to render the body. It is a cached version
-         * of the body that gets moved and rotated according to the simulation.
-         *
-         * The styles are used to modify the appearance of the view.
-         * They depend on the renderer.
-         *
-         * Override this when creating renderers.
-         **/
-        createView: function( geometry, styles ){
-
-            // example:
-            // var el = document.createElement('div');
-            // el.style.height = geometry.height + 'px';
-            // el.style.width = geometry.width + 'px';
-            // return el;
-            throw 'You must override the renderer.createView() method.';
-        },
-
-        /**
-         * Renderer#drawMeta( meta )
-         * - meta (Object): The meta data
-         *
-         * Draw the meta data.
-         *
-         * The meta data will look like this:
-         *
-         * ```javascript
-         * meta = {
-         *     fps: 60, // the frames per second
-         *     ipf: 4 // the number of iterations per frame
-         * };
-         * ```
-         *
-         * Override this when creating renderers.
-         **/
-        drawMeta: function( meta ){
-
-            // example:
-            // this.els.fps.innerHTML = meta.fps.toFixed(2);
-            // this.els.steps.innerHTML = meta.steps;
-            throw 'You must override the renderer.drawMeta() method.';
-        },
-
-        /**
-         * Renderer#drawBody( body, view )
-         * - body (Object): The body to draw
-         * - view (Object): The view for the body
-         *
-         * Draw specified body using specified view.
-         *
-         * Override this when creating renderers.
-         **/
-        drawBody: function( body, view ){
-
-            // example (pseudocode):
-            // view.angle = body.state.angle
-            // view.position = body.state.position
-            throw 'You must override the renderer.drawBody() method.';
-        }
-
-
-    });
-
-}());
-
-
-// ---
-// inside: src/core/world.js
-
-/** related to: Physics
- * class Physics.world
- *
- * The world class and factory function.
- *
- * Use [[Physics]] to create worlds.
- **/
-(function(){
-
-    var execCallbacks = function execCallbacks( fns, scope, args ){
-
-        var fn
-            ,ret
-            ,cb = function(){
-                return execCallbacks( fns, scope, args );
-            }
-            ;
-
-        while ( fn = fns.shift() ){
-
-            ret = fn.apply(scope, args);
-
-            if (ret && ret.then){
-                return ret.then( cb );
-            }
-        }
-    };
-
-    var defaults = {
-
-        // default timestep
-        timestep: 6,
-        // maximum number of iterations per step
-        maxIPF: 4,
-        webworker: false, // NOT YET IMPLEMENTED
-
-        // default integrator
-        integrator: 'verlet',
-
-        // is sleeping disabled?
-        sleepDisabled: false,
-        // speed at which bodies wake up
-        sleepSpeedLimit: 0.05,
-        // variance in position below which bodies fall asleep
-        sleepVarianceLimit: 0.02,
-        // time (ms) before sleepy bodies fall asleep
-        sleepTimeLimit: 500
-    };
-
-    // begin world definitions
-
-    /** alias of: Physics
-     * new Physics.world([options, fn(world, Physics)])
-     * - options (Object): configuration options (see description)
-     * - fn (Function|Array): Callback function or array of callbacks called with this === world
-     * - world (Physics.world): The current world created
-     * - Physics (Physics): The Physics namespace
-     *
-     * World Constructor.
-     *
-     * Use [[Physics]] to create worlds.
-     *
-     * Configuration options and defaults:
-     *
-     * ```javascript
-     * {
-     *  // default timestep
-     *  timestep: 6,
-     *  // maximum number of iterations per step
-     *  maxIPF: 4,
-     *
-     *  // default integrator
-     *  integrator: 'verlet',
-     *
-     *  // is sleeping disabled?
-     *  sleepDisabled: false,
-     *  // speed at which bodies wake up
-     *  sleepSpeedLimit: 0.1,
-     *  // variance in position below which bodies fall asleep
-     *  sleepVarianceLimit: 2,
-     *  // time (ms) before sleepy bodies fall asleep
-     *  sleepTimeLimit: 500
-     * }
-     * ```
-     *
-     * If called with an array of functions, and any functions
-     * return a [promise-like object](http://promises-aplus.github.io/promises-spec/),
-     * each remaining callback will be called only when that promise is resolved.
-     *
-     * Example:
-     *
-     * ```javascript
-     * // hypothetical resources need to be loaded...
-     * Physics( cfg, [
-     *     function( world ){
-     *         var dfd = $.Deferred()
-     *             ,images = []
-     *             ,toLoad = myImages.length
-     *             ,callback = function(){
-     *                 toLoad--;
-     *                 // wait for all images to be loaded
-     *                 if ( toLoad <= 0 ){
-     *                     dfd.resolve();
-     *                 }
-     *             }
-     *             ;
-     *
-     *         // load images
-     *         $.each(myImages, function( src ){
-     *             var img = new Image();
-     *             img.onload = callback;
-     *             img.src = src;
-     *         });
-     *
-     *         return dfd.promise();
-     *     },
-     *     function( world ){
-     *         // won't be executed until images are loaded
-     *         // initialize world... etc...
-     *     }
-     * ]);
-     * ```
-     **/
-    var World = function World( cfg, fn ){
-
-        // allow creation of world without "new"
-        if (!(this instanceof World)){
-            return new World( cfg, fn );
-        }
-
-        this.init( cfg, fn );
-    };
-
-    // extend pubsub
-    World.prototype = Physics.util.extend({}, Physics.util.pubsub.prototype, {
-
-        /** internal, see: new Physics.world
-         * Physics.world#init( [options, fn(world, Physics)] )
-         * - options (Object): configuration options (see constructor)
-         * - fn (Function|Array): Callback function or array of callbacks called with this === world
-         *
-         * Initialization
-         **/
-        init: function( cfg, fn ){
-
-            var self = this;
-
-            if ( Physics.util.isFunction( cfg ) || Physics.util.isArray( cfg ) ){
-                fn = cfg;
-                cfg = {};
-            }
-
-            this._meta = {
-               // statistics (fps, etc)
-               fps: 0,
-               ipf: 0
-            };
-            this._bodies = [];
-            this._behaviors = [];
-            this._integrator = null;
-            this._renderer = null;
-            this._paused = false;
-            this._warp = 1;
-            this._time = 0;
-
-            // set options
-            this.options = Physics.util.options( defaults );
-            this.options.onChange(function( opts ){
-
-                // set timestep
-                self.timestep( opts.timestep );
-            });
-            this.options( cfg );
-
-            // add integrator
-            this.add(Physics.integrator( this.options.integrator ));
-
-            // apply the callback function
-            if ( Physics.util.isFunction( fn ) ){
-
-                execCallbacks([ fn ], this, [this, Physics] );
-
-            } else if ( Physics.util.isArray( fn ) ){
-
-                execCallbacks(fn, this, [this, Physics] );
-            }
-        },
-
-        /**
-         * Physics.world#options( cfg ) -> Object
-         * - options (Object): configuration options (see constructor)
-         * + (Object): Options container
-         *
-         * Set config options. Also access options by `.options.<option>`.
-         **/
-        options: null,
-
-        /** chainable
-         * Physics.world#add( things ) -> this
-         * - things (Object|Array): The thing, or array of things (body, behavior, integrator, or renderer) to add.
-         *
-         * Multipurpose add method. Add one or many bodies, behaviors, integrators, renderers...
-         **/
-        add: function( arg ){
-
-            var i = 0
-                ,len = arg && arg.length || 0
-                ,thing = Physics.util.isArray( arg ) ? arg[ 0 ] : arg
-                ;
-
-            if ( !thing ){
-                return this;
-            }
-
-            // we'll either cycle through an array
-            // or just run this on the arg itself
-            do {
-                switch (thing.type){
-
-                    case 'behavior':
-                        this.addBehavior(thing);
-                    break; // end behavior
-
-                    case 'integrator':
-                        this.integrator(thing);
-                    break; // end integrator
-
-                    case 'renderer':
-                        this.renderer(thing);
-                    break; // end renderer
-
-                    case 'body':
-                        this.addBody(thing);
-                    break; // end body
-
-                    default:
-                        throw 'Error: failed to add item of unknown type "'+ thing.type +'" to world';
-                    // end default
-                }
-
-            } while ( ++i < len && (thing = arg[ i ]) );
-
-            return this;
-        },
-
-        /** chainable
-         * Physics.world#remove( things ) -> this
-         * - things (Object|Array): The thing, or array of things (body, behavior, integrator, or renderer) to remove.
-         *
-         * Multipurpose remove method. Remove one or many bodies, behaviors, integrators, renderers...
-         **/
-        remove: function( arg ){
-
-            var i = 0
-                ,len = arg && arg.length || 0
-                ,thing = Physics.util.isArray( arg ) ? arg[ 0 ] : arg
-                ;
-
-            if ( !thing ){
-                return this;
-            }
-
-            // we'll either cycle through an array
-            // or just run this on the arg itself
-            do {
-                switch (thing.type){
-
-                    case 'behavior':
-                        this.removeBehavior( thing );
-                    break; // end behavior
-
-                    case 'integrator':
-                        if (thing === this._integrator){
-                            this.integrator( null );
-                        }
-                    break; // end integrator
-
-                    case 'renderer':
-                        if (thing === this._renderer){
-                            this.renderer( null );
-                        }
-                    break; // end renderer
-
-                    case 'body':
-                        this.removeBody( thing );
-                    break; // end body
-
-                    default:
-                        throw 'Error: failed to remove item of unknown type "'+ thing.type +'" from world';
-                    // end default
-                }
-
-            } while ( ++i < len && (thing = arg[ i ]) );
-
-            return this;
-        },
-
-        /** chainable
-         * Physics.world#has( thing ) -> Boolean
-         * - thing (Object): The thing to test
-         * + (Boolean): `true` if thing is in the world, `false` otherwise.
-         *
-         * Determine if a thing has been added to world.
-         **/
-        has: function( thing ){
-
-            var arr
-                ,i
-                ,l
-                ;
-
-            if ( !thing ){
-                return false;
-            }
-
-            switch (thing.type){
-
-                case 'behavior':
-                    arr = this._behaviors;
-                break; // end behavior
-
-                case 'integrator':
-                return ( this._integrator === thing );
-                // end integrator
-
-                case 'renderer':
-                return ( this._renderer === thing );
-                // end renderer
-
-                case 'body':
-                    arr = this._bodies;
-                break; // end body
-
-                default:
-                    throw 'Error: unknown type "'+ thing.type +'"';
-                // end default
-            }
-
-            // check array
-            return (Physics.util.indexOf( arr, thing ) > -1);
-        },
-
-        /** chainable
-         * Physics.world#integrator( [integrator] ) -> Integrator|this
-         * - integrator (Integrator): The integrator to set on the world
-         * + (Integrator): The currently set integrator if `integrator` not specified
-         * + (this): for chaining if `integrator` specified
-         *
-         * Get or Set the integrator
-         **/
-        integrator: function( integrator ){
-
-            if ( integrator === undefined ){
-                return this._integrator;
-            }
-
-            // do nothing if already added
-            if ( this._integrator === integrator ){
-                return this;
-            }
-
-            if ( this._integrator ){
-
-                this._integrator.setWorld( null );
-
-                this.emit( 'remove:integrator', {
-                    integrator: this._integrator
-                });
-            }
-
-            if ( integrator ){
-                this._integrator = integrator;
-                this._integrator.setWorld( this );
-
-                this.emit( 'add:integrator', {
-                    integrator: this._integrator
-                });
-            }
-
-            return this;
-        },
-
-        /** chainable
-         * Physics.world#renderer( [renderer] ) -> Renderer|this
-         * - renderer (Renderer): The renderer to set on the world
-         * + (Renderer): The currently set renderer if `renderer` not specified
-         * + (this): for chaining if `renderer` specified
-         *
-         * Get or Set the renderer
-         **/
-        renderer: function( renderer ){
-
-            if ( renderer === undefined ){
-                return this._renderer;
-            }
-
-            // do nothing if renderer already added
-            if ( this._renderer === renderer ){
-                return this;
-            }
-
-            if ( this._renderer ){
-
-                this._renderer.setWorld( null );
-
-                this.emit( 'remove:renderer', {
-                    renderer: this._renderer
-                });
-            }
-
-            if ( renderer ){
-                this._renderer = renderer;
-                this._renderer.setWorld( this );
-
-                this.emit( 'add:renderer', {
-                    renderer: this._renderer
-                });
-            }
-
-            return this;
-        },
-
-        /** chainable
-         * Physics.world#timestep( [dt] ) -> Number|this
-         * - dt (Number): The time step for the world
-         * + (Number): The currently set time step if `dt` not specified
-         * + (this): for chaining if `dt` specified
-         *
-         * Get or Set the timestep
-         **/
-        timestep: function( dt ){
-
-            if ( dt ){
-
-                this._dt = +dt.toPrecision(4); // only keep 4 decimal places of precision otherwise we get rounding errors
-                // calculate the maximum jump in time over which to do iterations
-                this._maxJump = dt * this.options.maxIPF;
-
-                return this;
-            }
-
-            return this._dt;
-        },
-
-        /** chainable
-         * Physics.world#wakeUpAll() -> this
-         * + (this): for chaining
-         *
-         * Wake up all bodies in world.
-         **/
-        wakeUpAll: function(){
-            var i = 0
-                ,l = this._bodies.length
-                ;
-
-            for ( i = 0; i < l; i++ ){
-                this._bodies[ i ].sleep( false );
-            }
-        },
-
-        /** chainable
-         * Physics.world#addBehavior( behavior ) -> this
-         * - behavior (Behavior): The behavior to add
-         *
-         * Add a behavior to the world
-         **/
-        addBehavior: function( behavior ){
-
-            var notify;
-
-            // don't allow duplicates
-            if ( this.has( behavior ) ){
-                return this;
-            }
-
-            behavior.setWorld( this );
-            this._behaviors.push( behavior );
-
-            this.emit( 'add:behavior', {
-                behavior: behavior
-            });
-
-            return this;
-        },
-
-        /**
-         * Physics.world#getBehaviors() -> Array
-         * + (Array): Array of behaviors
-         *
-         * Get copied list of behaviors in the world
-         **/
-        getBehaviors: function(){
-
-            // return the copied array
-            return [].concat(this._behaviors);
-        },
-
-        /** chainable
-         * Physics.world#removeBehavior( behavior ) -> this
-         * - behavior (Behavior): The behavior to remove
-         *
-         * Remove a behavior from the world
-         **/
-        removeBehavior: function( behavior ){
-
-            var behaviors = this._behaviors;
-
-            if (behavior){
-
-                for ( var i = 0, l = behaviors.length; i < l; ++i ){
-
-                    if (behavior === behaviors[ i ]){
-
-                        behaviors.splice( i, 1 );
-                        behavior.setWorld( null );
-
-                        this.emit( 'remove:behavior', {
-                            behavior: behavior
-                        });
-
-                        break;
-                    }
-                }
-            }
-
-            return this;
-        },
-
-        /** chainable
-         * Physics.world#addBody( body ) -> this
-         * - body (Body): The behavior to add
-         *
-         * Add a body to the world
-         **/
-        addBody: function( body ){
-
-            var notify;
-
-            // don't allow duplicates
-            if ( this.has( body ) ){
-                return this;
-            }
-
-            body.setWorld( this );
-            this._bodies.push( body );
-
-            this.emit( 'add:body', {
-                body: body
-            });
-
-            return this;
-        },
-
-        /**
-         * Physics.world#getBodies() -> Array
-         * + (Array): Array of bodies
-         *
-         * Get copied list of bodies in the world
-         **/
-        getBodies: function(){
-
-            // return the copied array
-            return [].concat(this._bodies);
-        },
-
-        /** chainable
-         * Physics.world#removeBody( body ) -> this
-         * - body (Body): The body to remove
-         *
-         * Remove a body from the world
-         **/
-        removeBody: function( body ){
-
-            var bodies = this._bodies;
-
-            if (body){
-
-                for ( var i = 0, l = bodies.length; i < l; ++i ){
-
-                    if (body === bodies[ i ]){
-
-                        bodies.splice( i, 1 );
-                        body.setWorld( null );
-
-                        this.emit( 'remove:body', {
-                            body: body
-                        });
-
-                        break;
-                    }
-                }
-            }
-
-            return this;
-        },
-
-        /** see: Physics.query
-         * Physics.world#findOne( rules ) -> Body | false
-         * Physics.world#findOne( filter(body) ) -> Body | false
-         * - rules (Object): Query rules.
-         * - filter (Function): Filter function called to check bodies
-         * - body (Body): Each body in the world
-         *
-         * Find first matching body based on query rules.
-         **/
-        findOne: function( rules ){
-
-            var self = this
-                ,fn = (typeof rules === 'function') ? rules : Physics.query( rules )
-                ;
-
-            return Physics.util.find( self._bodies, fn ) || false;
-        },
-
-        /** see: Physics.query
-         * Physics.world#find( rules ) -> Array
-         * Physics.world#find( filter(body) ) -> Array
-         * - rules (Object): Query rules
-         * - filter (Function): Filter function called to check bodies
-         * - body (Body): Each body in the world
-         *
-         * Find all matching bodies based on query rules.
-         **/
-        find: function( rules ){
-
-            var self = this
-                ,fn = (typeof rules === 'function') ? rules : Physics.query( rules )
-                ;
-
-            return Physics.util.filter( self._bodies, fn );
-        },
-
-        /** internal
-         * Physics.world#iterate( dt )
-         * - dt (Number): The timestep
-         *
-         * Do a single iteration.
-         **/
-        iterate: function( dt ){
-
-            this._integrator.integrate( this._bodies, dt );
-        },
-
-        /** chainable
-         * Physics.world#step( [now] ) -> this
-         * - now (Number): Current unix timestamp
-         *
-         * Step the world up to specified time or do one step if no time is specified.
-         **/
-        step: function( now ){
-
-            var time = this._time
-                ,warp = this._warp
-                ,invWarp = 1 / warp
-                ,dt = this._dt
-                ,animDt = dt * invWarp
-                ,animMaxJump = this._maxJump * invWarp
-                ,animDiff
-                ,worldDiff
-                ,target
-                ,meta = this._meta
-                ;
-
-            // if it's paused, don't step
-            // or if it's the first step...
-            if ( this._paused || this._animTime === undefined ){
-                this._animTime = now || this._animTime || Physics.util.ticker.now();
-
-                if ( !this._paused ){
-                    this.emit('step', meta);
-                }
-                return this;
-            }
-
-            // new time is specified, or just one iteration ahead
-            now = now || (this._animTime + animDt);
-            // the time between this step and the last
-            animDiff = now - this._animTime;
-
-            // if the time difference is too big... adjust
-            if ( animDiff > animMaxJump ){
-                this._animTime = now - animMaxJump;
-                animDiff = animMaxJump;
-            }
-
-            // the "world" time between this step and the last. Adjusts for warp
-            worldDiff = animDiff * warp;
-
-            // the target time for the world time to step to
-            target = time + worldDiff - dt;
-
-            this.emit('beforeStep');
-
-            if ( time <= target ){
-
-                while ( time <= target ){
-                    // increment world time
-                    time += dt;
-                    // increment animation time
-                    this._animTime += animDt;
-                    // record the world time
-                    this._time = time;
-                    // iterate by one timestep
-                    this.iterate( dt );
-                }
-            }
-
-            // set some meta
-            meta.fps = 1000 / (now - this._lastTime); // frames per second
-            meta.ipf = (worldDiff / dt).toFixed(2); // iterations per frame
-            meta.interpolateTime = dt + target - time;
-
-            // record the time this was called
-            this._lastTime = now;
-
-            this.emit('step', meta);
-            return this;
-        },
-
-        /**
-         * Physics.world#warp( [warp] ) -> this|Number
-         * - warp (Number): The time warp factor
-         *
-         * Speed up or slow down the iteration by this factor.
-         *
-         * Example:
-         * ```javascript
-         * // slow motion... 10x slower
-         * world.warp( 0.01 );
-         * ```
-         **/
-        warp: function( warp ){
-            if ( warp === undefined ){
-                return this._warp;
-            }
-
-            this._warp = warp || 1;
-
-            return this;
-        },
-
-        /** chainable
-         * Physics.world#render() -> this
-         *
-         * Render current world state using the renderer
-         **/
-        render: function(){
-
-            if ( !this._renderer ){
-                throw "No renderer added to world";
-            }
-
-            this._renderer.render( this._bodies, this._meta );
-            this.emit('render', {
-                bodies: this._bodies,
-                meta: this._meta,
-                renderer: this._renderer
-            });
-            return this;
-        },
-
-        /** chainable
-         * Physics.world#pause() -> this
-         *
-         * Pause the world (step calls do nothing).
-         **/
-        pause: function(){
-
-            this._paused = true;
-            this.emit('pause');
-            return this;
-        },
-
-        /** chainable
-         * Physics.world#unpause() -> this
-         *
-         * Unpause the world (step calls continue as usual).
-         **/
-        unpause: function(){
-
-            this._paused = false;
-            this.emit('unpause');
-            return this;
-        },
-
-        /**
-         * Physics.world#isPaused() -> Boolean
-         * + (Boolean): Returns `true` if world is paused, `false` otherwise.
-         *
-         * Determine if world is paused.
-         **/
-        isPaused: function(){
-
-            return !!this._paused;
-        },
-
-        /**
-         * Physics.world#destroy()
-         *
-         * Destroy the world.
-         * (Bwahahahahaha!)
-         **/
-        destroy: function(){
-
-            var self = this;
-            self.pause();
-
-            // notify before
-            this.emit('destroy');
-
-            // remove all listeners
-            self.off( true );
-            // remove everything
-            self.remove( self.getBodies() );
-            self.remove( self.getBehaviors() );
-            self.integrator( null );
-            self.renderer( null );
-        }
-
-    });
-
-    Physics.world = World;
-
-}());
-
-
-// ---
-// inside: src/integrators/verlet.js
-
-Physics.integrator('verlet', function( parent ){
-
-    // for this integrator we need to know if the object has been integrated before
-    // so let's add a mixin to bodies
-
-    Physics.body.mixin({
-
-        started: function( val ){
-            if ( val !== undefined ){
-                this._started = true;
-            }
-
-            return !!this._started;
-        }
-    });
-
-
-    return {
-        /**
-         * class Verlet < Integrator
-         *
-         * `Physics.integrator('verlet')`.
-         *
-         * The verlet integrator.
-         **/
-
-        // extended
-        init: function( options ){
-
-            // call parent init
-            parent.init.call(this, options);
-        },
-
-        // extended
-        integrateVelocities: function( bodies, dt ){
-
-            // half the timestep
-            var dtdt = dt * dt
-                ,drag = 1 - this.options.drag
-                ,body = null
-                ,state
-                ,prevDt = this.prevDt || dt
-                ,dtMul = (dtdt + dt * prevDt) * 0.5
-                ;
-
-            for ( var i = 0, l = bodies.length; i < l; ++i ){
-
-                body = bodies[ i ];
-                state = body.state;
-
-                // only integrate if the body isn't static
-                if ( body.treatment !== 'static' && !body.sleep( dt ) ){
-
-                    // Inspired from https://github.com/soulwire/Coffee-Physics
-                    // @licence MIT
-                    //
-                    // v = x - ox
-                    // x = x + (v + a * dt * dt)
-
-                    // use the velocity in vel if the velocity has been changed manually
-                    if (state.vel.equals( state.old.vel ) && body.started()){
-
-                        // Get velocity by subtracting old position from curr position
-                        state.vel.clone( state.pos ).vsub( state.old.pos );
-
-                    } else {
-
-                        state.old.pos.clone( state.pos ).vsub( state.vel );
-                        // so we need to scale the value by dt so it
-                        // complies with other integration methods
-                        state.vel.mult( dt );
-                    }
-
-                    // Apply "air resistance".
-                    if ( drag ){
-
-                        state.vel.mult( drag );
-                    }
-
-                    // Apply acceleration
-                    // v += a * dt * dt
-                    state.vel.vadd( state.acc.mult( dtMul ) );
-
-                    // restore velocity
-                    state.vel.mult( 1/dt );
-
-                    // store calculated velocity
-                    state.old.vel.clone( state.vel );
-
-                    // Reset accel
-                    state.acc.zero();
-
-                    //
-                    // Angular components
-                    //
-
-                    if (state.angular.vel === state.old.angular.vel && body.started()){
-
-                        state.angular.vel = (state.angular.pos - state.old.angular.pos);
-
-                    } else {
-
-                        state.old.angular.pos = state.angular.pos - state.angular.vel;
-                        state.angular.vel *= dt;
-                    }
-
-                    state.angular.vel += state.angular.acc * dtMul;
-                    state.angular.vel /= dt;
-                    state.old.angular.vel = state.angular.vel;
-                    state.angular.acc = 0;
-
-                    body.started( true );
-
-                } else {
-                    // set the velocity and acceleration to zero!
-                    state.vel.zero();
-                    state.acc.zero();
-                    state.angular.vel = 0;
-                    state.angular.acc = 0;
-                }
-            }
-        },
-
-        // extended
-        integratePositions: function( bodies, dt ){
-
-            // half the timestep
-            var dtdt = dt * dt
-                ,body = null
-                ,state
-                ,prevDt = this.prevDt || dt
-                ,dtcorr = dt/prevDt
-                ;
-
-            for ( var i = 0, l = bodies.length; i < l; ++i ){
-
-                body = bodies[ i ];
-                state = body.state;
-
-                // only integrate if the body isn't static
-                if ( body.treatment !== 'static' && !body.sleep() ){
-
-                    // so we need to scale the value by dt so it
-                    // complies with other integration methods
-                    state.vel.mult( dt * dtcorr );
-
-                    // Store old position.
-                    // xold = x
-                    state.old.pos.clone( state.pos );
-
-                    state.pos.vadd( state.vel );
-
-                    // restore velocity
-                    state.vel.mult( 1 / (dt * dtcorr) );
-
-                    // store calculated velocity
-                    state.old.vel.clone( state.vel );
-
-                    //
-                    // Angular components
-                    //
-
-
-                    state.angular.vel *= dt * dtcorr;
-
-                    state.old.angular.pos = state.angular.pos;
-
-                    state.angular.pos += state.angular.vel;
-                    state.angular.vel /= dt * dtcorr;
-                    state.old.angular.vel = state.angular.vel;
-                }
-            }
-
-            this.prevDt = dt;
-        }
-    };
-});
-
-
-// ---
-// inside: src/geometries/point.js
-
-/** alias of: Geometry
- * class PointGeometry < Geometry
- *
- * Physics.geometry('point')
- *
- * The point geometry represents a point.
- **/
-Physics.geometry('point', function( parent ){});
-
-
-// ---
-// inside: src/bodies/point.js
-
-/** alias of: Body
- * class PointBody < Body
- *
- * Physics.body('point')
- *
- * The point body represents a point.
- **/
-Physics.body('point', function( parent ){
-    return {
-        init: function( opts ){
-            parent.init.call( this, opts );
-            this.moi = 0;
-        }
-    };
-});
-
-
-// ---
-// inside: src/geometries/circle.js
-
-/** 
- * class CircleGeometry < Geometry
- *
- * Physics.geometry('circle')
- *
- * The circle geometry has a circular shape.
- *
- * Additional options include:
- * - radius: the radius
- *
- * Example:
- *
- * ```javascript
- * var round = Physics.body('circle', {
- *     x: 30,
- *     y: 20,
- *     radius: 5
- * });
- * ```
- **/
-Physics.geometry('circle', function( parent ){
-
-    var defaults = {
-
-        radius: 1.0
-    };
-
-    return {
-
-        // extended
-        init: function( options ){
-
-            var self = this;
-            // call parent init method
-            parent.init.call(this, options);
-
-            this.options.defaults( defaults );
-            this.options.onChange(function( opts ){
-                this.radius = opts.radius;
-            });
-            this.options( options );
-
-            this._aabb = Physics.aabb();
-            this.radius = this.options.radius;
-        },
-                
-        // extended
-        aabb: function( angle ){
-
-            var r = this.radius
-                ;
-
-            // circles are symetric... so angle has no effect
-            if ( this._aabb.hw !== r ){
-                // recalculate
-                this._aabb = Physics.aabb( -r, -r, r, r );
-            }
-
-            return Physics.aabb.clone( this._aabb );
-        },
-
-        // extended
-        getFarthestHullPoint: function( dir, result ){
-
-            result = result || new Physics.vector();
-
-            return result.clone( dir ).normalize().mult( this.radius );
-        },
-
-        // extended
-        getFarthestCorePoint: function( dir, result, margin ){
-
-            result = result || new Physics.vector();
-
-            // we can use the center of the circle as the core object
-            // because we can project a point to the hull in any direction
-            // ... yay circles!
-            // but since the caller is expecting a certain margin... give it
-            // to them
-            return result.clone( dir ).normalize().mult( this.radius - margin );
-        }
-    };
-});
-
-
-// ---
-// inside: src/geometries/compound.js
-
-/**
- * class CompoundGeometry < Geometry
- *
- * Physics.geometry('compound')
- *
- * Geometry for compound shapes.
- *
- * Example:
- *
- * ```javascript
- * var thing = Physics.geometry('compound');
- * thing.addChild( child, pos, rotation );
- * ```
- **/
-Physics.geometry('compound', function( parent ){
-
-    var defaults = {
-
-    };
-
-    return {
-
-        // extended
-        init: function( options ){
-
-            var self = this;
-
-            // call parent init method
-            parent.init.call(this, options);
-
-            this.options.defaults( defaults );
-            this.options( options );
-
-            this.children = [];
-        },
-
-        /**
-         * CompoundGeometry#addChild( geometry, pos ) -> this
-         * - geometry (Geometry): The child to add.
-         * - pos (Physics.vector): The position to add the child at.
-         * - angle (Number): The rotation angle
-         *
-         * Add a child at relative position.
-         **/
-        addChild: function( geometry, pos, angle ){
-
-            this._aabb = null;
-            this.children.push({
-                g: geometry
-                ,pos: new Physics.vector( pos )
-                ,angle: angle
-            });
-
-            return this;
-        },
-
-        /**
-         * CompoundGeometry#clear() -> this
-         *
-         * Remove all children.
-         **/
-        clear: function(){
-
-            this._aabb = null;
-            this.children = [];
-
-            return this;
-        },
-
-        // extended
-        aabb: function( angle ){
-
-            if (!angle && this._aabb){
-                return Physics.aabb.clone( this._aabb );
-            }
-
-            var b
-                ,aabb
-                ,ch
-                ,ret
-                ,scratch = Physics.scratchpad()
-                ,pos = Physics.vector()
-                ;
-
-            angle = angle || 0;
-
-            for ( var i = 0, l = this.children.length; i < l; i++ ) {
-                ch = this.children[ i ];
-                // the aabb rotated by overall angle and the child rotation
-                aabb = ch.g.aabb( angle + ch.angle );
-                pos.clone( ch.pos );
-                if ( angle ){
-                    // get the child's position rotated if needed
-                    pos.rotate( angle );
-                }
-                // move the aabb to the child's position
-                aabb.x += pos._[0];
-                aabb.y += pos._[1];
-                ret = ret ? Physics.aabb.union(ret, aabb, true) : aabb;
-            }
-
-            if ( !angle ){
-                // if we don't have an angle specified (or it's zero)
-                // then we can cache this result
-                this._aabb = Physics.aabb.clone( ret );
-            }
-
-            return scratch.done( ret );
-        },
-
-        // extended
-        // NOTE: unlike other geometries this can't be used in the
-        // GJK algorithm because the shape isn't garanteed to be convex
-        getFarthestHullPoint: function( dir, result ){
-
-            var ch
-                ,i
-                ,l = this.children.length
-                ,scratch = Physics.scratchpad()
-                ,v = scratch.vector()
-                ,len = 0
-                ,maxlen = 0
-                ;
-
-            result = result || new Physics.vector();
-
-            // find the one with the largest projection along dir
-            for ( i = 0; i < l; i++ ) {
-                ch = this.children[ i ];
-                ch.g.getFarthestHullPoint( dir.rotate(-ch.angle), v );
-                len = v.rotate(ch.angle).vadd( ch.pos ).proj( dir.rotate(ch.angle) );
-
-                if ( len > maxlen ){
-                    maxlen = len;
-                    result.swap( v );
-                }
-            }
-
-            return scratch.done( result );
-        },
-
-        // extended
-        // NOTE: unlike other geometries this can't be used in the
-        // GJK algorithm because the shape isn't garanteed to be convex
-        getFarthestCorePoint: function( dir, result, margin ){
-
-            var ch
-                ,i
-                ,l = this.children.length
-                ,scratch = Physics.scratchpad()
-                ,v = scratch.vector()
-                ,len = 0
-                ,maxlen = 0
-                ;
-
-            result = result || new Physics.vector();
-
-            // find the one with the largest projection along dir
-            for ( i = 0; i < l; i++ ) {
-                ch = this.children[ i ];
-                ch.g.getFarthestCorePoint(dir.rotate(-ch.angle), v, margin );
-                len = v.rotate(ch.angle).vadd( ch.pos ).proj( dir.rotate(ch.angle) );
-
-                if ( len > maxlen ){
-                    maxlen = len;
-                    result.swap( v );
-                }
-            }
-
-            return scratch.done( result );
-        }
-    };
-});
-
-
-// ---
-// inside: src/geometries/convex-polygon.js
-
-/**
- * class ConvexPolygonGeometry < Geometry
- *
- * Physics.geometry('convex-polygon')
- *
- * Geometry for convex polygons.
- *
- * Additional config options:
- *
- * - vertices: Array of [[Vectorish]] objects representing the polygon vertices in clockwise (or counterclockwise) order.
- *
- * Example:
- *
- * ```javascript
- * var pentagon = Physics.geometry('convex-polygon', {
- *     // the centroid is automatically calculated and used to position the shape
- *     vertices: [
- *         { x: 0, y: -30 },
- *         { x: -29, y: -9 },
- *         { x: -18, y: 24 },
- *         { x: 18, y: 24 },
- *         { x: 29, y: -9 }
- *     ]
- * });
- * ```
- **/
-Physics.geometry('convex-polygon', function( parent ){
-
-    var ERROR_NOT_CONVEX = 'Error: The vertices specified do not match that of a _convex_ polygon.';
-
-    var defaults = {
-
-    };
-
-    return {
-
-        // extended
-        init: function( options ){
-
-            var self = this;
-
-            // call parent init method
-            parent.init.call(this, options);
-
-            this.options.defaults( defaults );
-            this.options.onChange(function( opts ){
-                self.setVertices( opts.vertices || [] );
-            });
-            this.options( options );
-
-            self.setVertices( this.options.vertices || [] );
-
-        },
-
-        /**
-         * ConvexPolygonGeometry#setVertices( hull ) -> this
-         * - hull (Array): Vertices represented by an array of [[Vectorish]] objects, in either clockwise or counterclockwise order
-         *
-         * Set the vertices of this polygon.
-         **/
-        setVertices: function( hull ){
-
-            var scratch = Physics.scratchpad()
-                ,transl = scratch.transform()
-                ,verts = this.vertices = []
-                ;
-
-            if ( !Physics.geometry.isPolygonConvex( hull ) ){
-                throw ERROR_NOT_CONVEX;
-            }
-
-            transl.setRotation( 0 );
-            transl.setTranslation( Physics.geometry.getPolygonCentroid( hull ).negate() );
-
-            // translate each vertex so that the centroid is at the origin
-            // then add the vertex as a vector to this.vertices
-            for ( var i = 0, l = hull.length; i < l; ++i ){
-
-                verts.push( new Physics.vector( hull[ i ] ).translate( transl ) );
-            }
-
-            this._area = Physics.geometry.getPolygonArea( verts );
-            this._aabb = false;
-            return scratch.done(this);
-        },
-
-        // extended
-        aabb: function( angle ){
-
-            if (!angle && this._aabb){
-                return Physics.aabb.clone( this._aabb );
-            }
-
-            var scratch = Physics.scratchpad()
-                ,p = scratch.vector()
-                ,trans = scratch.transform().setRotation( angle || 0 )
-                ,xaxis = scratch.vector().set( 1, 0 ).rotateInv( trans )
-                ,yaxis = scratch.vector().set( 0, 1 ).rotateInv( trans )
-                ,xmax = this.getFarthestHullPoint( xaxis, p ).proj( xaxis )
-                ,xmin = - this.getFarthestHullPoint( xaxis.negate(), p ).proj( xaxis )
-                ,ymax = this.getFarthestHullPoint( yaxis, p ).proj( yaxis )
-                ,ymin = - this.getFarthestHullPoint( yaxis.negate(), p ).proj( yaxis )
-                ,aabb
-                ;
-
-            aabb = Physics.aabb( xmin, ymin, xmax, ymax );
-
-            if (!angle){
-                // if we don't have an angle specified (or it's zero)
-                // then we can cache this result
-                this._aabb = Physics.aabb.clone( aabb );
-            }
-
-            scratch.done();
-            return aabb;
-        },
-
-        // extended
-        getFarthestHullPoint: function( dir, result, data ){
-
-            var verts = this.vertices
-                ,val
-                ,prev
-                ,l = verts.length
-                ,i = 2
-                ,idx
-                ;
-
-            result = result || new Physics.vector();
-
-            if ( l < 2 ){
-                if ( data ){
-                    data.idx = 0;
-                }
-                return result.clone( verts[0] );
-            }
-
-            prev = verts[ 0 ].dot( dir );
-            val = verts[ 1 ].dot( dir );
-
-            if ( l === 2 ){
-                idx = (val >= prev) ? 1 : 0;
-                if ( data ){
-                    data.idx = idx;
-                }
-                return result.clone( verts[ idx ] );
-            }
-
-            if ( val >= prev ){
-                // go up
-                // search until the next dot product
-                // is less than the previous
-                while ( i < l && val >= prev ){
-                    prev = val;
-                    val = verts[ i ].dot( dir );
-                    i++;
-                }
-
-                if (val >= prev){
-                    i++;
-                }
-
-                // return the previous (furthest with largest dot product)
-                idx = i - 2;
-                if ( data ){
-                    data.idx = i - 2;
-                }
-                return result.clone( verts[ idx ] );
-
-            } else {
-                // go down
-
-                i = l;
-                while ( i > 1 && prev >= val ){
-                    i--;
-                    val = prev;
-                    prev = verts[ i ].dot( dir );
-                }
-
-                // return the previous (furthest with largest dot product)
-                idx = (i + 1) % l;
-                if ( data ){
-                    data.idx = idx;
-                }
-                return result.clone( verts[ idx ] );
-            }
-        },
-
-        // extended
-        getFarthestCorePoint: function( dir, result, margin ){
-
-            var norm
-                ,scratch = Physics.scratchpad()
-                ,next = scratch.vector()
-                ,prev = scratch.vector()
-                ,verts = this.vertices
-                ,l = verts.length
-                ,mag
-                ,sign = this._area > 0
-                ,data = {}
-                ;
-
-            result = this.getFarthestHullPoint( dir, result, data );
-
-            // get normalized directions to next and previous vertices
-            next.clone( verts[ (data.idx + 1) % l ] ).vsub( result ).normalize().perp( sign );
-            prev.clone( verts[ (data.idx - 1 + l) % l ] ).vsub( result ).normalize().perp( !sign );
-
-            // get the magnitude of a vector from the result vertex
-            // that splits down the middle
-            // creating a margin of "m" to each edge
-            mag = margin / (1 + next.dot(prev));
-
-            result.vadd( next.vadd( prev ).mult( mag ) );
-            scratch.done();
-            return result;
-        }
-    };
-});
-
-
-// ---
-// inside: src/geometries/rectangle.js
-
-/**
- * class RectangleGeometry < Geometry
- *
- * Physics.geometry('rectangle')
- *
- * Geometry for rectangles.
- *
- * Additional config options:
- *
- * - width: The width
- * - height: The height
- *
- * Example:
- *
- * ```javascript
- * var rectGeo = Physics.geometry('rectangle', {
- *     width: 30,
- *     height: 40
- * });
- * ```
- **/
-Physics.geometry('rectangle', function( parent ){
-
-    var defaults = {
-
-    };
-
-    return {
-
-        // extended
-        init: function( options ){
-
-            var self = this;
-
-            // call parent init method
-            parent.init.call(this, options);
-
-            this.options.defaults( defaults );
-            this.options.onChange(function( opts ){
-                /**
-                 * RectangleGeometry#width = Number
-                 *
-                 * The width
-                 **/
-                self.width = self.options.width || 1;
-                /**
-                 * RectangleGeometry#height = Number
-                 *
-                 * The height
-                 **/
-                self.height = self.options.height || 1;
-            });
-            this.options( options );
-        },
-
-        // extended
-        aabb: function( angle ){
-
-            if (!angle){
-                return Physics.aabb( this.width, this.height );
-            }
-
-            var scratch = Physics.scratchpad()
-                ,p = scratch.vector()
-                ,trans = scratch.transform().setRotation( angle || 0 )
-                ,xaxis = scratch.vector().set( 1, 0 ).rotateInv( trans )
-                ,yaxis = scratch.vector().set( 0, 1 ).rotateInv( trans )
-                ,xmax = this.getFarthestHullPoint( xaxis, p ).proj( xaxis )
-                ,xmin = - this.getFarthestHullPoint( xaxis.negate(), p ).proj( xaxis )
-                ,ymax = this.getFarthestHullPoint( yaxis, p ).proj( yaxis )
-                ,ymin = - this.getFarthestHullPoint( yaxis.negate(), p ).proj( yaxis )
-                ;
-
-            scratch.done();
-            return Physics.aabb( xmin, ymin, xmax, ymax );
-        },
-
-        // extended
-        getFarthestHullPoint: function( dir, result ){
-
-            result = result || new Physics.vector();
-
-            var x = dir.x
-                ,y = dir.y
-                ;
-
-            x = x === 0 ? 0 : x < 0 ? -this.width * 0.5 : this.width * 0.5;
-            y = y === 0 ? 0 : y < 0 ? -this.height * 0.5 : this.height * 0.5;
-
-            return result.set( x, y );
-        },
-
-        // extended
-        getFarthestCorePoint: function( dir, result, margin ){
-
-            var x, y;
-            result = this.getFarthestHullPoint( dir, result );
-            x = result.x;
-            y = result.y;
-            result.x = x === 0 ? 0 : x < 0 ? x + margin : x - margin;
-            result.y = y === 0 ? 0 : y < 0 ? y + margin : y - margin;
-
-            return result;
-        }
-    };
-});
-
-
-// ---
-// inside: src/bodies/circle.js
-
-/*
- * @requires geometries/circle
- */
-/** 
- * class CircleBody < Body
- *
- * Physics.body('circle')
- *
- * The circle body has a circular shape.
- *
- * Additional options include:
- * - radius: the radius
- *
- * Example:
- *
- * ```javascript
- * var round = Physics.body('circle', {
- *     x: 30,
- *     y: 20,
- *     radius: 5
- * });
- * ```
- **/
-Physics.body('circle', function( parent ){
-
-    var defaults = {
-        radius: 1.0
-    };
-
-    return {
-
-        // extended
-        init: function( options ){
-
-            // call parent init method
-            parent.init.call(this, options);
-
-            options = Physics.util.extend({}, defaults, options);
-
-            this.geometry = Physics.geometry('circle', {
-                radius: options.radius
-            });
-
-            this.recalc();
-        },
-
-        // extended
-        recalc: function(){
-            parent.recalc.call(this);
-            // moment of inertia
-            this.moi = this.mass * this.geometry.radius * this.geometry.radius / 2;
-        }
-    };
-});
-
-
-// ---
-// inside: src/bodies/compound.js
-
-/*
- * @requires geometries/compound
- */
- /**
-  * class CompoundBody < Body
-  *
-  * Physics.body('compound')
-  *
-  * Not a body in itself. It's a container to group other bodies. The position of the body is the center of mass.
-  * It must have at least one child before being added to the world.
-  *
-  * Additional config options:
-  *
-  * - children: Array of [[Body]] objects.
-  *
-  * Example:
-  *
-  * ```javascript
-  * var thing = Physics.body('compound', {
-  *     // place the center of mass at (300, 200)
-  *     x: 300,
-  *     y: 200,
-  *     // the center of mass is automatically calculated and used to position the shape
-  *     children: [
-  *         body1,
-  *         body2,
-  *         // ...
-  *     ]
-  * });
-  * ```
-  **/
-Physics.body('compound', function( parent ){
-
-    var defaults = {
-
-    };
-
-    return {
-
-        // extended
-        init: function( options ){
-
-            // call parent init method
-            parent.init.call(this, options);
-
-            this.mass = 0;
-            this.moi = 0;
-
-            this.children = [];
-            this.geometry = Physics.geometry('compound');
-            this.addChildren( options.children );
-        },
-
-        // extended
-        connect: function( world ){
-            // sanity check
-            if ( this.mass <= 0 ){
-                throw 'Can not add empty compound body to world.';
-            }
-        },
-
-        /**
-         * CompoundBody#addChild( body ) -> this
-         * - body (Body): The child to add
-         *
-         * Add a body as a child.
-         **/
-        addChild: function( body ){
-
-            this.addChildren([ body ]);
-            return this;
-        },
-
-        /**
-         * CompoundBody#addChildren( bodies ) -> this
-         * - bodies (Array): The list of children to add
-         *
-         * Add an array of children to the compound.
-         **/
-        addChildren: function( bodies ){
-
-            var self = this
-                ,scratch = Physics.scratchpad()
-                ,com = scratch.vector().zero()
-                ,b
-                ,pos
-                ,i
-                ,l = bodies && bodies.length
-                ,M = 0
-                ;
-
-            if ( !l ){
-                return scratch.done( this );
-            }
-
-            for ( i = 0; i < l; i++ ){
-                b = bodies[ i ];
-                // remove body from world if applicable
-                if ( b._world ){
-                    b._world.remove( b );
-                }
-                // add child
-                this.children.push( b );
-                // add child to geometry
-                this.geometry.addChild(
-                    b.geometry,
-                    new Physics.vector(b.offset)
-                        .rotate(b.state.angular.pos)
-                        .vadd(b.state.pos),
-                    b.state.angular.pos
-                );
-                // calc com contribution
-                pos = b.state.pos;
-                com.add( pos._[0] * b.mass, pos._[1] * b.mass );
-                M += b.mass;
-            }
-
-            // add mass
-            this.mass += M;
-            // com adjustment (assuming com is currently at (0,0) body coords)
-            com.mult( 1 / this.mass );
-
-            // shift the center of mass
-            this.offset.vsub( com );
-
-            // refresh view on next render
-            if ( this._world ){
-                this._world.one('render', function(){
-                    self.view = null;
-                });
-            }
-            this.recalc();
-
-            return scratch.done( this );
-        },
-
-        /**
-         * CompoundBody#clear() -> this
-         *
-         * Remove all children.
-         **/
-        clear: function(){
-
-            this._aabb = null;
-            this.moi = 0;
-            this.mass = 0;
-            this.offset.zero();
-            this.children = [];
-            this.geometry.clear();
-
-            return this;
-        },
-
-        /**
-         * CompoundBody#refreshGeometry() -> this
-         *
-         * If the children's positions change, `refreshGeometry()` should be called to fix the shape.
-         **/
-        refreshGeometry: function(){
-
-            this.geometry.clear();
-
-            for ( var i = 0, b, l = this.children.length; i < l; i++ ) {
-                b = this.children[ i ];
-                this.geometry.addChild( b.geometry, new Physics.vector(b.state.pos).vadd(b.offset), b.state.angular.pos );
-            }
-
-            return this;
-        },
-
-        // extended
-        recalc: function(){
-
-            parent.recalc.call(this);
-            // moment of inertia
-            var b
-                ,moi = 0
-                ;
-
-            for ( var i = 0, l = this.children.length; i < l; i++ ) {
-                b = this.children[ i ];
-                b.recalc();
-                // parallel axis theorem
-                moi += b.moi + b.mass * b.state.pos.normSq();
-            }
-
-            this.moi = moi;
-            return this;
-        }
-    };
-});
-
-
-// ---
-// inside: src/bodies/convex-polygon.js
-
-/*
- * @requires geometries/convex-polygon
- */
- /**
-  * class ConvexPolygonBody < Body
-  *
-  * Physics.body('convex-polygon')
-  *
-  * Body for convex polygons. The position of the body is the centroid of the polygon.
-  *
-  * Additional config options:
-  *
-  * - vertices: Array of [[Vectorish]] objects representing the polygon vertices in clockwise (or counterclockwise) order.
-  *
-  * Example:
-  *
-  * ```javascript
-  * var pentagon = Physics.body('convex-polygon', {
-  *     // place the centroid of the polygon at (300, 200)
-  *     x: 300,
-  *     y: 200,
-  *     // the centroid is automatically calculated and used to position the shape
-  *     vertices: [
-  *         { x: 0, y: -30 },
-  *         { x: -29, y: -9 },
-  *         { x: -18, y: 24 },
-  *         { x: 18, y: 24 },
-  *         { x: 29, y: -9 }
-  *     ]
-  * });
-  * ```
-  **/
-Physics.body('convex-polygon', function( parent ){
-
-    var defaults = {
-
-    };
-
-    return {
-
-        // extended
-        init: function( options ){
-
-            // call parent init method
-            parent.init.call(this, options);
-
-            options = Physics.util.extend({}, defaults, options);
-
-            this.geometry = Physics.geometry('convex-polygon', {
-                vertices: options.vertices
-            });
-
-            this.recalc();
-        },
-
-        // extended
-        recalc: function(){
-            parent.recalc.call(this);
-            // moment of inertia
-            this.moi = Physics.geometry.getPolygonMOI( this.geometry.vertices );
-        }
-    };
-});
-
-
-// ---
-// inside: src/bodies/rectangle.js
-
-/*
- * @requires geometries/rectangle
- */
- /**
-  * class RectangleBody < Body
-  *
-  * Physics.body('rectangle')
-  *
-  * Body for rectangles. The position of the body is the centroid of the rectangle.
-  *
-  * Additional config options:
-  *
-  * - width: The width
-  * - height: The height
-  *
-  * Example:
-  *
-  * ```javascript
-  * var rect = Physics.body('rectangle', {
-  *     // place the centroid of the rectangle at (300, 200)
-  *     x: 300,
-  *     y: 200,
-  *     width: 30,
-  *     height: 40
-  * });
-  * ```
-  **/
-Physics.body('rectangle', function( parent ){
-
-    var defaults = {
-
-    };
-
-    return {
-
-        // extended
-        init: function( options ){
-
-            // call parent init method
-            parent.init.call(this, options);
-
-            options = Physics.util.extend({}, defaults, options);
-
-            this.geometry = Physics.geometry('rectangle', {
-                width: options.width,
-                height: options.height
-            });
-
-            this.recalc();
-        },
-
-        // extended
-        recalc: function(){
-            var w = this.geometry.width;
-            var h = this.geometry.height;
-            parent.recalc.call(this);
-            // moment of inertia
-            this.moi = ( w*w + h*h ) * this.mass / 12;
-        }
-    };
-});
-
-
-// ---
-// inside: src/behaviors/attractor.js
-
-/** 
- * class AttractorBehavior < Behavior
- *
- * `Physics.behavior('attractor')`.
- *
- * Attractor behavior attracts bodies to a specific point.
- *
- * Additional options include:
- * - pos: The position of the attraction point
- * - strength: How strong the attraction is (default: `1`)
- * - order: The power of the inverse distance (default: `2` because that is newtonian gravity... inverse square)
- * - max: The maximum distance in which to apply the attraction (default: Infinity)
- * - min: The minimum distance above which to apply the attraction (default: very small non-zero)
- **/
-Physics.behavior('attractor', function( parent ){
-
-    var defaults = {
-
-        pos: null, // default to (0, 0)
-        // how strong the attraction is
-        strength: 1,
-        // power of the inverse distance (2 is inverse square)
-        order: 2,
-        // max distance to apply it to
-        max: false, // infinite
-        // min distance to apply it to
-        min: false // auto calc
-    };
-
-    return {
-
-        // extended
-        init: function( options ){
-
-            var self = this;
-            this._pos = new Physics.vector();
-            // call parent init method
-            parent.init.call( this );
-            this.options.defaults( defaults );
-            this.options.onChange(function( opts ){
-                self._maxDist = opts.max === false ? Infinity : opts.max;
-                self._minDist = opts.min ? opts.min : 10;
-                self.position( opts.pos );
-            });
-            this.options( options );
-        },
-
-        /**
-         * AttractorBehavior#position( [pos] ) -> this|Object
-         * - pos (Vectorish): The position to set
-         * + (Object): Returns the [[Vectorish]] position if no arguments provided
-         * + (this): For chaining
-         *
-         * Get or set the position of the attractor.
-         **/
-        position: function( pos ){
-            
-            var self = this;
-
-            if ( pos ){
-                this._pos.clone( pos );
-                return self;
-            }
-
-            return this._pos.values();
-        },
-        
-        // extended
-        behave: function( data ){
-
-            var bodies = this.getTargets()
-                ,body
-                ,order = this.options.order
-                ,strength = this.options.strength
-                ,minDist = this._minDist
-                ,maxDist = this._maxDist
-                ,scratch = Physics.scratchpad()
-                ,acc = scratch.vector()
-                ,norm
-                ,g
-                ;
-
-            for ( var j = 0, l = bodies.length; j < l; j++ ){
-                
-                body = bodies[ j ];
-
-                // clone the position
-                acc.clone( this._pos );
-                acc.vsub( body.state.pos );
-                // get the distance
-                norm = acc.norm();
-
-                if (norm > minDist && norm < maxDist){
-
-                    g = strength / Math.pow(norm, order);
-
-                    body.accelerate( acc.normalize().mult( g ) );
-                }
-            }
-
-            scratch.done();
-        }
-    };
-});
-
-
-// ---
-// inside: src/behaviors/body-collision-detection.js
-
-/**
- * class BodyCollisionDetectionBehavior < Behavior
- *
- * `Physics.behavior('body-collision-detection')`.
- *
- * Detect collisions of bodies.
- *
- * Publishes collision events to the world as a group of detected collisions per iteration.
- *
- * The event data will have a `.collisions` property that is an array of collisions of the form:
- *
- * ```javascript
- * {
- *     bodyA: // the first body
- *     bodyB: // the second body
- *     norm: // the normal vector (Vectorish)
- *     mtv: // the minimum transit vector. (the direction and length needed to extract bodyB from bodyA)
- *     pos: // the collision point relative to bodyA
- *     overlap: // the amount bodyA overlaps bodyB
- * }
- * ```
- *
- * Additional options include:
- * - check: channel to listen to for collision candidates (default: `collisions:candidates`). set to `true` to force check every pair of bodies in the world
- * - channel: channel to publish events to (default: `collisions:detected`)
- **/
-Physics.behavior('body-collision-detection', function( parent ){
-
-    var supportFnStack = [];
-
-    /*
-     * getSupportFn( bodyA, bodyB ) -> Function
-     * - bodyA (Object): First body
-     * - bodyB (Object): Second body
-     * + (Function): The support function
-     *
-     * Get a general support function for use with GJK algorithm
-     */
-    var getSupportFn = function getSupportFn( bodyA, bodyB ){
-
-        var hash = Physics.util.pairHash( bodyA.uid, bodyB.uid )
-            ,fn = supportFnStack[ hash ]
-            ;
-
-        if ( !fn ){
-            fn = supportFnStack[ hash ] = function pairSupportFunction( searchDir ){
-
-                var tA = fn.tA
-                    ,tB = fn.tB
-                    ,vA = fn.tmpv1
-                    ,vB = fn.tmpv2
-                    ;
-
-                if ( fn.useCore ){
-                    vA = bodyA.geometry.getFarthestCorePoint( searchDir.rotateInv( tA ), vA, fn.marginA );
-                    vB = bodyB.geometry.getFarthestCorePoint( searchDir.rotate( tA ).rotateInv( tB ).negate(), vB, fn.marginB );
-                } else {
-                    vA = bodyA.geometry.getFarthestHullPoint( searchDir.rotateInv( tA ), vA );
-                    vB = bodyB.geometry.getFarthestHullPoint( searchDir.rotate( tA ).rotateInv( tB ).negate(), vB );
-                }
-
-                vA.vadd( bodyA.offset ).transform( tA );
-                vB.vadd( bodyB.offset ).transform( tB );
-                searchDir.negate().rotate( tB );
-
-                return {
-                    a: vA.values(),
-                    b: vB.values(),
-                    pt: vA.vsub( vB ).values()
-                };
-            };
-
-            // transforms for coordinate transformations
-            fn.tA = new Physics.transform();
-            fn.tB = new Physics.transform();
-
-            // temp vectors (used too frequently to justify scratchpad)
-            fn.tmpv1 = new Physics.vector();
-            fn.tmpv2 = new Physics.vector();
-        }
-
-        fn.useCore = false;
-        fn.margin = 0;
-        fn.tA.setRotation( bodyA.state.angular.pos ).setTranslation( bodyA.state.pos );
-        fn.tB.setRotation( bodyB.state.angular.pos ).setTranslation( bodyB.state.pos );
-        fn.bodyA = bodyA;
-        fn.bodyB = bodyB;
-
-        return fn;
-    };
-
-    /*
-     * checkGJK( bodyA, bodyB ) -> Object
-     * - bodyA (Object): First body
-     * - bodyB (Object): Second body
-     * + (Object): Collision result
-     *
-     * Use GJK algorithm to check arbitrary bodies for collisions
-     */
-    var checkGJK = function checkGJK( bodyA, bodyB ){
-
-        var scratch = Physics.scratchpad()
-            ,d = scratch.vector()
-            ,tmp = scratch.vector()
-            ,os = scratch.vector()
-            ,overlap
-            ,result
-            ,support
-            ,inc
-            ,collision = false
-            ,aabbA = bodyA.aabb()
-            ,dimA = Math.min( aabbA.hw, aabbA.hh )
-            ,aabbB = bodyB.aabb()
-            ,dimB = Math.min( aabbB.hw, aabbB.hh )
-            ;
-
-        // just check the overlap first
-        support = getSupportFn( bodyA, bodyB );
-        d.clone( bodyA.state.pos )
-            .vadd( bodyA.getGlobalOffset( os ) )
-            .vsub( bodyB.state.pos )
-            .vsub( bodyB.getGlobalOffset( os ) )
-            ;
-        result = Physics.gjk(support, d, true);
-
-        if ( result.overlap ){
-
-            // there is a collision. let's do more work.
-            collision = {
-                bodyA: bodyA,
-                bodyB: bodyB
-            };
-
-            // inc by 1% of the smallest dim.
-            inc = 1e-2 * Math.min(dimA || 1, dimB || 1);
-
-            // first get the min distance of between core objects
-            support.useCore = true;
-            support.marginA = 0;
-            support.marginB = 0;
-
-            // while there's still an overlap (or we don't have a positive distance)
-            // and the support margins aren't bigger than the shapes...
-            // search for the distance data
-            while ( (result.overlap || result.distance === 0) && (support.marginA < dimA || support.marginB < dimB) ){
-                if ( support.marginA < dimA ){
-                    support.marginA += inc;
-                }
-                if ( support.marginB < dimB ){
-                    support.marginB += inc;
-                }
-
-                result = Physics.gjk(support, d);
-            }
-
-            if ( result.overlap || result.maxIterationsReached ){
-                // This implementation can't deal with a core overlap yet
-                return scratch.done(false);
-            }
-
-            // calc overlap
-            overlap = (support.marginA + support.marginB) - result.distance;
-
-            if ( overlap <= 0 ){
-                return scratch.done(false);
-            }
-
-            collision.overlap = overlap;
-            // @TODO: for now, just let the normal be the mtv
-            collision.norm = d.clone( result.closest.b ).vsub( tmp.clone( result.closest.a ) ).normalize().values();
-            collision.mtv = d.mult( overlap ).values();
-            // get a corresponding hull point for one of the core points.. relative to body A
-            collision.pos = d.clone( collision.norm ).mult( support.marginA ).vadd( tmp.clone( result.closest.a ) ).vsub( bodyA.state.pos ).values();
-        }
-
-        return scratch.done( collision );
-    };
-
-    /*
-     * checkCircles( bodyA, bodyB ) -> Object
-     * - bodyA (Object): First body
-     * - bodyB (Object): Second body
-     * + (Object): Collision result
-     *
-     * Check two circles for collisions.
-     */
-    var checkCircles = function checkCircles( bodyA, bodyB ){
-
-        var scratch = Physics.scratchpad()
-            ,d = scratch.vector()
-            ,tmp = scratch.vector()
-            ,overlap
-            ,collision = false
-            ;
-
-        d.clone( bodyB.state.pos )
-            .vadd( bodyB.getGlobalOffset( tmp ) )
-            .vsub( bodyA.state.pos )
-            .vsub( bodyA.getGlobalOffset( tmp ) ) // save offset for later
-            ;
-        overlap = d.norm() - (bodyA.geometry.radius + bodyB.geometry.radius);
-
-        // hmm... they overlap exactly... choose a direction
-        if ( d.equals( Physics.vector.zero ) ){
-
-            d.set( 1, 0 );
-        }
-
-        if ( overlap <= 0 ){
-
-            collision = {
-                bodyA: bodyA,
-                bodyB: bodyB,
-                norm: d.normalize().values(),
-                mtv: d.mult( -overlap ).values(),
-                pos: d.mult( -bodyA.geometry.radius/overlap ).vadd( tmp ).values(),
-                overlap: -overlap
-            };
-        }
-
-        return scratch.done( collision );
-    };
-
-    /*
-     * checkPair( bodyA, bodyB[, disp] ) -> Object
-     * - bodyA (Object): First body
-     * - bodyB (Object): Second body
-     * + (Object): Collision result
-     *
-     * Check a pair for collisions
-     */
-    var checkPair = function checkPair( bodyA, bodyB ){
-
-        // filter out bodies that don't collide with each other
-        if (
-            ( bodyA.treatment === 'static' || bodyA.treatment === 'kinematic' ) &&
-            ( bodyB.treatment === 'static' || bodyB.treatment === 'kinematic' )
-        ){
-            return false;
-        }
-
-        if ( bodyA.geometry.name === 'circle' && bodyB.geometry.name === 'circle' ){
-
-            return checkCircles( bodyA, bodyB );
-
-        } else if ( bodyA.geometry.name === 'compound' || bodyB.geometry.name === 'compound' ){
-            // compound bodies are special. We can't use gjk because
-            // they could have concavities. so we do the pieces individually
-            var test = (bodyA.geometry.name === 'compound')
-                ,compound = test ? bodyA : bodyB
-                ,other = test ? bodyB : bodyA
-                ,cols
-                ,ch
-                ,ret = []
-                ,scratch = Physics.scratchpad()
-                ,vec = scratch.vector()
-                ,oldPos = scratch.vector()
-                ,otherAABB = other.aabb()
-                ,i
-                ,l
-                ;
-
-            for ( i = 0, l = compound.children.length; i < l; i++ ){
-
-                ch = compound.children[ i ];
-                // move body to fake position
-                oldPos.clone( ch.state.pos );
-                ch.offset.vadd( oldPos.vadd( compound.offset ).rotate( -ch.state.angular.pos ) );
-                ch.state.pos.clone( compound.state.pos );
-                ch.state.angular.pos += compound.state.angular.pos;
-
-                // check it if the aabbs overlap
-                if ( Physics.aabb.overlap(otherAABB, ch.aabb()) ){
-
-                    cols = checkPair( other, ch );
-
-                    if ( cols instanceof Array ){
-                        for ( var j = 0, c, ll = cols.length; j < ll; j++ ){
-                            c = cols[j];
-                            // set body to be the compound body
-                            if ( c.bodyA === ch ){
-                                c.bodyA = compound;
-                            } else {
-                                c.bodyB = compound;
-                            }
-                            ret.push( c );
-                        }
-
-                    } else if ( cols ) {
-                        // set body to be the compound body
-                        if ( cols.bodyA === ch ){
-                            cols.bodyA = compound;
-                        } else {
-                            cols.bodyB = compound;
-                        }
-                        ret.push( cols );
-                    }
-                }
-
-                // transform it back
-                ch.state.angular.pos -= compound.state.angular.pos;
-                ch.offset.vsub( oldPos );
-                ch.state.pos.clone( oldPos.rotate( ch.state.angular.pos ).vsub( compound.offset ) );
-            }
-
-            return scratch.done( ret );
-
-        } else {
-
-            return checkGJK( bodyA, bodyB );
-        }
-    };
-
-    var defaults = {
-
-        // channel to listen to for collision candidates
-        // set to "true" to force check every pair of bodies in the world
-        check: 'collisions:candidates',
-
-        // channel to publish events to
-        channel: 'collisions:detected'
-    };
-
-    return {
-
-        // extended
-        init: function( options ){
-
-            parent.init.call( this );
-            this.options.defaults( defaults );
-            this.options( options );
-        },
-
-        // extended
-        connect: function( world ){
-
-            if ( this.options.check === true ){
-
-                world.on( 'integrate:velocities', this.checkAll, this );
-
-            } else {
-
-                world.on( this.options.check, this.check, this );
-            }
-        },
-
-        // extended
-        disconnect: function( world ){
-
-            if ( this.options.check === true ){
-
-                world.off( 'integrate:velocities', this.checkAll, this );
-
-            } else {
-
-                world.off( this.options.check, this.check, this );
-            }
-        },
-
-        /** internal
-         * BodyCollisionDetectionBehavior#check( data )
-         * - data (Object): The event data
-         *
-         * Event callback to check pairs of objects that have been flagged by broad phase for possible collisions.
-         **/
-        check: function( data ){
-
-            var candidates = data.candidates
-                ,pair
-                ,targets = this.getTargets()
-                ,collisions = []
-                ,ret
-                ,prevContacts = this.prevContacts || {}
-                ,contactList = {}
-                ,pairHash = Physics.util.pairHash
-                ,hash
-                ;
-
-            for ( var i = 0, l = candidates.length; i < l; ++i ){
-
-                pair = candidates[ i ];
-
-                if ( targets === this._world._bodies ||
-                    // only check if the members are targeted by this behavior
-                    (Physics.util.indexOf( targets, pair.bodyA ) > -1) &&
-                    (Physics.util.indexOf( targets, pair.bodyB ) > -1)
-                ){
-                    ret = checkPair( pair.bodyA, pair.bodyB );
-
-                    if ( ret instanceof Array ){
-
-                        for ( var j = 0, r, ll = ret.length; j < ll; j++ ){
-                            r = ret[j];
-                            if ( r ){
-                                hash = pairHash( pair.bodyA.uid, pair.bodyB.uid );
-                                contactList[ hash ] = true;
-                                r.collidedPreviously = prevContacts[ hash ];
-                                collisions.push( r );
-                            }
-                        }
-
-                    } else if ( ret ){
-                        hash = pairHash( pair.bodyA.uid, pair.bodyB.uid );
-                        contactList[ hash ] = true;
-                        ret.collidedPreviously = prevContacts[ hash ];
-
-                        collisions.push( ret );
-                    }
-                }
-            }
-
-            this.prevContacts = contactList;
-
-            if ( collisions.length ){
-
-                this._world.emit( this.options.channel, {
-                    collisions: collisions
-                });
-            }
-        },
-
-        /** internal
-         * BodyCollisionDetectionBehavior#checkAll( data )
-         * - data (Object): The event data
-         *
-         * Event callback to check all pairs of objects in the list for collisions
-         **/
-        checkAll: function( data ){
-
-            var bodies = this.getTargets()
-                ,dt = data.dt
-                ,bodyA
-                ,bodyB
-                ,collisions = []
-                ,ret
-                ,prevContacts = this.prevContacts || {}
-                ,contactList = {}
-                ,pairHash = Physics.util.pairHash
-                ,hash
-                ;
-
-            for ( var j = 0, l = bodies.length; j < l; j++ ){
-
-                bodyA = bodies[ j ];
-
-                for ( var i = j + 1; i < l; i++ ){
-
-                    bodyB = bodies[ i ];
-
-                    ret = checkPair( bodyA, bodyB );
-
-                    if ( ret instanceof Array ){
-
-                        for ( var k = 0, r, ll = ret.length; k < ll; k++ ){
-                            r = ret[k];
-                            if ( r ){
-                                hash = pairHash( bodyA.uid, bodyB.uid );
-                                contactList[ hash ] = true;
-                                r.collidedPreviously = prevContacts[ hash ];
-                                collisions.push( r );
-                            }
-                        }
-
-                    } else if ( ret ){
-                        hash = pairHash( bodyA.uid, bodyB.uid );
-                        contactList[ hash ] = true;
-                        ret.collidedPreviously = prevContacts[ hash ];
-
-                        collisions.push( ret );
-                    }
-                }
-            }
-
-            this.prevContacts = contactList;
-
-            if ( collisions.length ){
-
-                this._world.emit( this.options.channel, {
-                    collisions: collisions
-                });
-            }
-        }
-    };
-
-});
-
-
-// ---
-// inside: src/behaviors/body-impulse-response.js
-
-/**
- * class BodyImpulseResponseBehavior < Behavior
- *
- * `Physics.behavior('body-impulse-response')`.
- *
- * Responds to collisions by applying impulses.
- *
- * Additional options include:
- * - check: channel to listen to for collisions (default: `collisions:detected`).
- * - mtvThreshold: apply partial extraction of bodies if the minimum transit vector is less than this value ( default: `1`)
- *   this will depend on your simulation characteristic length scale
- * - bodyExtractDropoff: every body overlap correction (underneith mtvThreshold) will only extract by this fraction (0..1). Helps with stablizing contacts. (default: `0.5`)
- * - forceWakeupAboveOverlapThreshold: force bodies to wake up if the overlap is above mtvThreshold ( default: `true` )
- **/
-Physics.behavior('body-impulse-response', function( parent ){
-
-    var defaults = {
-        // channel to listen to for collisions
-        check: 'collisions:detected'
-        // apply partial extraction of bodies if the minimum transit vector is less than this value
-        // this will depend on your simulation characteristic length scale
-        ,mtvThreshold: 1
-        // every body overlap correction (underneith mtvThreshold) will only extract by this fraction (0..1)
-        // helps with stablizing contacts.
-        ,bodyExtractDropoff: 0.5
-        // force bodies to wake up if the overlap is above mtvThreshold
-        ,forceWakeupAboveOverlapThreshold: true
-    };
-
-    function getUid( b ){
-        return b.uid;
-    }
-
-    function clampMTV( totalV, mtv, into ){
-
-        var m, n;
-        n = mtv.norm();
-        m = n - totalV.proj( mtv );
-        m = Math.max( 0, Math.min( n, m ) );
-
-        if ( n === 0 ){
-            into.zero();
-        } else {
-            into.clone( mtv ).mult( m/n );
-        }
-
-        return into;
-    }
-
-    return {
-
-        // extended
-        init: function( options ){
-
-            parent.init.call( this );
-            this.options.defaults( defaults );
-            this.options( options );
-
-            this._bodyList = [];
-        },
-
-        // no applyTo method
-        applyTo: false,
-
-        // extended
-        connect: function( world ){
-
-            world.on( this.options.check, this.respond, this );
-        },
-
-        // extended
-        disconnect: function( world ){
-
-            world.off( this.options.check, this.respond, this );
-        },
-
-        /** internal
-         * BodyImpulseResponseBehavior#collideBodes( bodyA, bodyB, normal, point, mtrans, contact )
-         * - bodyA (Object): First Body
-         * - bodyB (Object): Second body
-         * - normal (Vector): Normal vector of the collision surface
-         * - point (Vector): Contact point of the collision
-         * - mtrans (Vector): Minimum transit vector that is the smallest displacement to separate the bodies
-         * - contact (Boolean): Are the bodies in resting contact relative to each other
-         *
-         * Collide two bodies by modifying their positions and velocities to conserve momentum
-         **/
-        collideBodies: function(bodyA, bodyB, normal, point, mtrans, contact){
-
-            var fixedA = bodyA.treatment === 'static' || bodyA.treatment === 'kinematic'
-                ,fixedB = bodyB.treatment === 'static' || bodyB.treatment === 'kinematic'
-                ,scratch = Physics.scratchpad()
-                // minimum transit vector for each body
-                ,mtv = scratch.vector().clone( mtrans )
-                ;
-
-            // do nothing if both are fixed
-            if ( fixedA && fixedB ){
-                scratch.done();
-                return;
-            }
-
-            // inverse masses and moments of inertia.
-            // give fixed bodies infinite mass and moi
-            var invMoiA = fixedA ? 0 : 1 / bodyA.moi
-                ,invMoiB = fixedB ? 0 : 1 / bodyB.moi
-                ,invMassA = fixedA ? 0 : 1 / bodyA.mass
-                ,invMassB = fixedB ? 0 : 1 / bodyB.mass
-                // coefficient of restitution between bodies
-                ,cor = bodyA.restitution * bodyB.restitution
-                // coefficient of friction between bodies
-                ,cof = bodyA.cof * bodyB.cof
-                // normal vector
-                ,n = scratch.vector().clone( normal )
-                // vector perpendicular to n
-                ,perp = scratch.vector().clone( n ).perp()
-                ,tmp = scratch.vector()
-                // collision point from A's center
-                ,rA = scratch.vector().clone( point )
-                // collision point from B's center
-                ,rB = scratch.vector().clone( point )
-                    .vadd( bodyA.state.pos )
-                    .vsub( bodyB.state.pos )
-                ,angVelA = bodyA.state.angular.vel
-                ,angVelB = bodyB.state.angular.vel
-                // relative velocity towards B at collision point
-                ,vAB = scratch.vector().clone( bodyB.state.vel )
-                        .vadd( tmp.clone(rB).perp().mult( angVelB ) )
-                        .vsub( bodyA.state.vel )
-                        .vsub( tmp.clone(rA).perp().mult( angVelA ) )
-                // break up components along normal and perp-normal directions
-                ,rAproj = rA.proj( n )
-                ,rAreg = rA.proj( perp )
-                ,rBproj = rB.proj( n )
-                ,rBreg = rB.proj( perp )
-                ,vproj = vAB.proj( n ) // projection of vAB along n
-                ,vreg = vAB.proj( perp ) // rejection of vAB along n (perp of proj)
-                ,impulse
-                ,sign
-                ,max
-                ,ratio
-                ,inContact = contact
-                ;
-
-            if ( contact ){
-
-                if ( fixedA ){
-
-                    clampMTV( bodyB._mtvTotal, mtv, tmp );
-                    bodyB._mtvTotal.vadd( tmp );
-
-                } else if ( fixedB ){
-
-                    clampMTV( bodyA._mtvTotal, mtv.negate(), tmp );
-                    bodyA._mtvTotal.vadd( tmp );
-                    mtv.negate();
-
-                } else {
-
-                    ratio = 0.5; //bodyA.mass / ( bodyA.mass + bodyB.mass );
-                    mtv.mult( ratio );
-                    clampMTV( bodyB._mtvTotal, mtv, tmp );
-                    bodyB._mtvTotal.vadd( tmp );
-
-                    mtv.clone( mtrans ).mult( ratio - 1 );
-                    clampMTV( bodyA._mtvTotal, mtv, tmp );
-                    bodyA._mtvTotal.vadd( tmp );
-
-                }
-            }
-
-            // if moving away from each other... don't bother.
-            if (vproj >= 0){
-                scratch.done();
-                return;
-            }
-
-            invMoiA = invMoiA === Infinity ? 0 : invMoiA;
-            invMoiB = invMoiB === Infinity ? 0 : invMoiB;
-
-            impulse =  - ((1 + cor) * vproj) / ( invMassA + invMassB + (invMoiA * rAreg * rAreg) + (invMoiB * rBreg * rBreg) );
-            // vproj += impulse * ( invMass + (invMoi * rreg * rreg) );
-            // angVel -= impulse * rreg * invMoi;
-
-
-            if ( fixedA ){
-
-                // apply impulse
-                bodyB.state.vel.vadd( n.mult( impulse * invMassB ) );
-                bodyB.state.angular.vel -= impulse * invMoiB * rBreg;
-
-            } else if ( fixedB ){
-
-                // apply impulse
-                bodyA.state.vel.vsub( n.mult( impulse * invMassA ) );
-                bodyA.state.angular.vel += impulse * invMoiA * rAreg;
-
-            } else {
-
-                // apply impulse
-                bodyB.state.vel.vadd( n.mult( impulse * invMassB ) );
-                bodyB.state.angular.vel -= impulse * invMoiB * rBreg;
-                bodyA.state.vel.vsub( n.mult( invMassA * bodyB.mass ) );
-                bodyA.state.angular.vel += impulse * invMoiA * rAreg;
-            }
-
-            // inContact = (impulse < 0.004);
-
-            // if we have friction and a relative velocity perpendicular to the normal
-            if ( cof && vreg ){
-
-
-                // TODO: here, we could first assume static friction applies
-                // and that the tangential relative velocity is zero.
-                // Then we could calculate the impulse and check if the
-                // tangential impulse is less than that allowed by static
-                // friction. If not, _then_ apply kinetic friction.
-
-                // instead we're just applying kinetic friction and making
-                // sure the impulse we apply is less than the maximum
-                // allowed amount
-
-                // maximum impulse allowed by kinetic friction
-                max = Math.abs(vreg) / ( invMassA + invMassB + (invMoiA * rAproj * rAproj) + (invMoiB * rBproj * rBproj) );
-                // the sign of vreg ( plus or minus 1 )
-                sign = vreg < 0 ? -1 : 1;
-
-                // get impulse due to friction
-                impulse = cof * Math.abs( impulse );
-                // constrain the impulse within the "friction cone" ( max < mu * impulse)
-                impulse = Math.min( impulse, max );
-                impulse *= sign;
-
-                if ( fixedA ){
-
-                    // apply frictional impulse
-                    bodyB.state.vel.vsub( perp.mult( impulse * invMassB ) );
-                    bodyB.state.angular.vel -= impulse * invMoiB * rBproj;
-
-                } else if ( fixedB ){
-
-                    // apply frictional impulse
-                    bodyA.state.vel.vadd( perp.mult( impulse * invMassA ) );
-                    bodyA.state.angular.vel += impulse * invMoiA * rAproj;
-
-                } else {
-
-                    // apply frictional impulse
-                    bodyB.state.vel.vsub( perp.mult( impulse * invMassB ) );
-                    bodyB.state.angular.vel -= impulse * invMoiB * rBproj;
-                    bodyA.state.vel.vadd( perp.mult( invMassA * bodyB.mass ) );
-                    bodyA.state.angular.vel += impulse * invMoiA * rAproj;
-                }
-            }
-
-            // wake up bodies if necessary
-            if ( bodyA.sleep() ){
-                bodyA.sleepCheck();
-            }
-            if ( bodyB.sleep() ){
-                bodyB.sleepCheck();
-            }
-
-            scratch.done();
-        },
-
-        // internal
-        _pushUniq: function( body ){
-            var idx = Physics.util.sortedIndex( this._bodyList, body, getUid );
-            if ( this._bodyList[ idx ] !== body ){
-                this._bodyList.splice( idx, 0, body );
-            }
-        },
-
-        /** internal
-         * BodyImpulseResponseBehavior#respond( data )
-         * - data (Object): event data
-         *
-         * Event callback to respond to collision data.
-         **/
-        respond: function( data ){
-
-            var self = this
-                ,col
-                ,collisions = data.collisions// Physics.util.shuffle(data.collisions)
-                ,i,l,b
-                ;
-
-            for ( i = 0, l = collisions.length; i < l; ++i ){
-
-                col = collisions[ i ];
-                // add bodies to list for later
-                this._pushUniq( col.bodyA );
-                this._pushUniq( col.bodyB );
-                // ensure they have mtv stat vectors
-                col.bodyA._mtvTotal = col.bodyA._mtvTotal || new Physics.vector();
-                col.bodyB._mtvTotal = col.bodyB._mtvTotal || new Physics.vector();
-                col.bodyA._oldmtvTotal = col.bodyA._oldmtvTotal || new Physics.vector();
-                col.bodyB._oldmtvTotal = col.bodyB._oldmtvTotal || new Physics.vector();
-
-                self.collideBodies(
-                    col.bodyA,
-                    col.bodyB,
-                    col.norm,
-                    col.pos,
-                    col.mtv,
-                    col.collidedPreviously
-                );
-            }
-
-            // apply mtv vectors from the average mtv vector
-            for ( i = 0, l = this._bodyList.length; i < l; ++i ){
-                b = this._bodyList.pop();
-                // clampMTV( b._oldmtvTotal, b._mtvTotal, b._mtvTotal );
-
-                if ( b._mtvTotal.normSq() < this.options.mtvThreshold ){
-                    b._mtvTotal.mult( this.options.bodyExtractDropoff );
-                } else if ( this.options.forceWakeupAboveOverlapThreshold ) {
-                    // wake up bodies if necessary
-                    b.sleep( false );
-                }
-
-                b.state.pos.vadd( b._mtvTotal );
-                b.state.old.pos.vadd( b._mtvTotal );
-                b._oldmtvTotal.swap( b._mtvTotal );
-                b._mtvTotal.zero();
-            }
-        }
-    };
-});
-
-
-// ---
-// inside: src/behaviors/constant-acceleration.js
-
-/** 
- * class ConstantAccelerationBehavior < Behavior
- *
- * `Physics.behavior('constant-acceleration')`.
- *
- * Constant acceleration behavior.
- *
- * Basically the "gravity" behavior. Used to give "earth-like gravity" to the world.
- *
- * Additional options include:
- * - acc: The acceleration vector (Vectorish). (default: `{ x: 0, y: 0.0004 }`)
- **/
-Physics.behavior('constant-acceleration', function( parent ){
-
-    var defaults = {
-
-        acc: { x : 0, y: 0.0004 }
-    };
-
-    return {
-
-        // extended
-        init: function( options ){
-
-            parent.init.call( this );
-            this.options.defaults( defaults );
-            this.options( options );
-
-            // extend options
-            this._acc = new Physics.vector();
-            this.setAcceleration( this.options.acc );
-            delete this.options.acc;
-        },
-
-        /**
-         * ConstantAccelerationBehavior#setAcceleration( acc ) -> this
-         * - acc (Vectorish): The acceleration vector
-         * 
-         * Set the acceleration of the behavior.
-         **/
-        setAcceleration: function( acc ){
-
-            this._acc.clone( acc );
-            return this;
-        },
-
-        // extended
-        behave: function( data ){
-
-            var bodies = this.getTargets();
-
-            for ( var i = 0, l = bodies.length; i < l; ++i ){
-                
-                bodies[ i ].accelerate( this._acc );
-            }
-        }
-    };
-});
-
-// ---
-// inside: src/behaviors/edge-collision-detection.js
-
-/**
- * class EdgeCollisionDetectionBehavior < Behavior
- *
- * `Physics.behavior('edge-collision-detection')`.
- *
- * Used to detect collisions with the boundaries of an AABB.
- *
- * Additional options include:
- * - aabb: The [[Physics.aabb]] bounds to use as the constraining boundary
- * - restitution: The restitution of the boundary walls (default: `0.99`)
- * - cof: The coefficient of friction of the boundary walls (default: `1`)
- * - channel: The channel to publish collisions to. (default: 'collisions:detected')
- **/
-Physics.behavior('edge-collision-detection', function( parent ){
-
-    /*
-     * checkGeneral( body, bounds, dummy ) -> Array
-     * - body (Body): The body to check
-     * - bounds (Physics.aabb): The boundary
-     * - dummy: (Body): The dummy body to publish as the static other body it collides with
-     * + (Array): The collision data
-     *
-     * Check if a body collides with the boundary
-     */
-    var checkGeneral = function checkGeneral( body, bounds, dummy ){
-
-        var overlap
-            ,aabb = body.aabb()
-            ,scratch = Physics.scratchpad()
-            ,offset = body.getGlobalOffset( scratch.vector() )
-            ,trans = scratch.transform()
-            ,dir = scratch.vector()
-            ,result = scratch.vector()
-            ,collision = false
-            ,collisions = []
-            ;
-
-        // right
-        overlap = (aabb.x + aabb.hw) - bounds.max.x;
-
-        if ( overlap >= 0 ){
-
-            dir.set( 1, 0 ).rotateInv( trans.setRotation( body.state.angular.pos ) );
-
-            collision = {
-                bodyA: body,
-                bodyB: dummy,
-                overlap: overlap,
-                norm: {
-                    x: 1,
-                    y: 0
-                },
-                mtv: {
-                    x: overlap,
-                    y: 0
-                },
-                pos: body.geometry.getFarthestHullPoint( dir, result ).rotate( trans ).vadd( offset ).values()
-            };
-
-            collisions.push(collision);
-        }
-
-        // bottom
-        overlap = (aabb.y + aabb.hh) - bounds.max.y;
-
-        if ( overlap >= 0 ){
-
-            dir.set( 0, 1 ).rotateInv( trans.setRotation( body.state.angular.pos ) );
-
-            collision = {
-                bodyA: body,
-                bodyB: dummy,
-                overlap: overlap,
-                norm: {
-                    x: 0,
-                    y: 1
-                },
-                mtv: {
-                    x: 0,
-                    y: overlap
-                },
-                pos: body.geometry.getFarthestHullPoint( dir, result ).rotate( trans ).vadd( offset ).values()
-            };
-
-            collisions.push(collision);
-        }
-
-        // left
-        overlap = bounds.min.x - (aabb.x - aabb.hw);
-
-        if ( overlap >= 0 ){
-
-            dir.set( -1, 0 ).rotateInv( trans.setRotation( body.state.angular.pos ) );
-
-            collision = {
-                bodyA: body,
-                bodyB: dummy,
-                overlap: overlap,
-                norm: {
-                    x: -1,
-                    y: 0
-                },
-                mtv: {
-                    x: -overlap,
-                    y: 0
-                },
-                pos: body.geometry.getFarthestHullPoint( dir, result ).rotate( trans ).vadd( offset ).values()
-            };
-
-            collisions.push(collision);
-        }
-
-        // top
-        overlap = bounds.min.y - (aabb.y - aabb.hh);
-
-        if ( overlap >= 0 ){
-
-            dir.set( 0, -1 ).rotateInv( trans.setRotation( body.state.angular.pos ) );
-
-            collision = {
-                bodyA: body,
-                bodyB: dummy,
-                overlap: overlap,
-                norm: {
-                    x: 0,
-                    y: -1
-                },
-                mtv: {
-                    x: 0,
-                    y: -overlap
-                },
-                pos: body.geometry.getFarthestHullPoint( dir, result ).rotate( trans ).vadd( offset ).values()
-            };
-
-            collisions.push(collision);
-        }
-
-        scratch.done();
-        return collisions;
-    };
-
-    /*
-     * checkEdgeCollide( body, bounds, dummy ) -> Array
-     * - body (Body): The body to check
-     * - bounds (Physics.aabb): The boundary
-     * - dummy: (Body): The dummy body to publish as the static other body it collides with
-     * + (Array): The collision data
-     *
-     * Check if a body collides with the boundary
-     */
-    var checkEdgeCollide = function checkEdgeCollide( body, bounds, dummy ){
-
-        return checkGeneral( body, bounds, dummy );
-    };
-
-    var defaults = {
-
-        aabb: null,
-        restitution: 0.99,
-        cof: 1.0,
-        channel: 'collisions:detected'
-    };
-
-    return {
-
-        // extended
-        init: function( options ){
-
-            parent.init.call( this );
-            this.options.defaults( defaults );
-            this.options( options );
-
-            this.setAABB( this.options.aabb );
-            this.restitution = this.options.restitution;
-
-            this.body = Physics.body('point', {
-                treatment: 'static',
-                restitution: this.options.restitution,
-                cof: this.options.cof
-            });
-        },
-
-        /**
-         * EdgeCollisionDetectionBehavior#setAABB( aabb ) -> this
-         * - aabb (Physics.aabb): The aabb to use as the boundary
-         *
-         * Set the boundaries of the edge.
-         **/
-        setAABB: function( aabb ){
-
-            if (!aabb) {
-                throw 'Error: aabb not set';
-            }
-
-            this._edges = {
-                min: {
-                    x: (aabb.x - aabb.hw),
-                    y: (aabb.y - aabb.hh)
-                },
-                max: {
-                    x: (aabb.x + aabb.hw),
-                    y: (aabb.y + aabb.hh)
-                }
-            };
-
-            return this;
-        },
-
-        // extended
-        connect: function( world ){
-
-            world.on( 'integrate:positions', this.checkAll, this, 2 );
-        },
-
-        // extended
-        disconnect: function( world ){
-
-            world.off( 'integrate:positions', this.checkAll, this, 2 );
-        },
-
-        /** internal
-         * EdgeCollisionDetectionBehavior#checkAll( data )
-         * - data (Object): Event data
-         *
-         * Event callback to check all bodies for collisions with the edge
-         **/
-        checkAll: function( data ){
-
-            var bodies = this.getTargets()
-                ,dt = data.dt
-                ,body
-                ,collisions = []
-                ,ret
-                ,bounds = this._edges
-                ,dummy = this.body
-                ,prevContacts = this.prevContacts || {}
-                ,contactList = {}
-                ,pairHash = Physics.util.pairHash
-                ,hash
-                ;
-
-            for ( var i = 0, l = bodies.length; i < l; i++ ){
-
-                body = bodies[ i ];
-
-                // only detect dynamic bodies
-                if ( body.treatment === 'dynamic' ){
-
-                    ret = checkEdgeCollide( body, bounds, dummy );
-
-                    if ( ret ){
-                        hash = pairHash( body.uid, dummy.uid );
-
-                        for ( var j = 0, ll = ret.length; j < ll; j++ ){
-                            contactList[ hash ] = true;
-                            ret[ j ].collidedPreviously = prevContacts[ hash ];
-                        }
-
-                        collisions.push.apply( collisions, ret );
-                    }
-                }
-            }
-
-            this.prevContacts = contactList;
-
-            if ( collisions.length ){
-
-                this._world.emit( this.options.channel, {
-                    collisions: collisions
-                });
-            }
-        }
-    };
-
-});
-
-
-// ---
-// inside: src/behaviors/interactive.js
-
-/**
- * class InteractiveBehavior < Behavior
- *
- * `Physics.behavior('interactive')`.
- *
- * User interaction helper.
- *
- * Used to get mouse/touch events and add grab interactions.
- *
- * Additional options include:
- * - el: The element of the renderer. What you input as the `el` for the renderer.
- * - moveThrottle: The min time between move events (default: `10`).
- * - minVel: The minimum velocity clamp [[Vectorish]] (default: { x: -5, y: -5 }) to restrict velocity a user can give to a body
- * - maxVel: The maximum velocity clamp [[Vectorish]] (default: { x: 5, y: 5 }) to restrict velocity a user can give to a body
- *
- * The behavior also triggers the following events on the world:
- * ```javascript
- * // a body has been grabbed
- * world.on('interact:grab', function( data ){
- *     data.x; // the x coord
- *     data.y; // the y coord
- *     data.body; // the body that was grabbed
- * });
- * // no body was grabbed, but the renderer area was clicked, or touched
- * world.on('interact:poke', function( data ){
- *     data.x; // the x coord
- *     data.y; // the y coord
- * });
- * // when a mouse or pointer moves
- * world.on('interact:move', function( data ){
- *     data.x; // the x coord
- *     data.y; // the y coord
- *     data.body; // the grabbed body that was moved (if applicable)
- * });
- * // when the viewport is released (mouseup, touchend)
- * world.on('interact:release', function( data ){
- *     data.x; // the x coord
- *     data.y; // the y coord
- *     data.body; // the body that was grabbed (if applicable)
- * });
- * ```
- *
- * The behavior also sets body.isGrabbed = true for any grabbed bodies while they are grabbed.
- **/
-Physics.behavior('interactive', function( parent ){
-
-    if ( !document ){
-        // must be in node environment
-        return {};
-    }
-
-    var defaults = {
-            // the element to monitor
-            el: null,
-            // time between move events
-            moveThrottle: 1000 / 100 | 0,
-            // minimum velocity clamp
-            minVel: { x: -5, y: -5 },
-            // maximum velocity clamp
-            maxVel: { x: 5, y: 5 }
-        }
-        ,getElementOffset = function( el ){
-            var curleft = 0
-                ,curtop = 0
-                ;
-
-            if (el.offsetParent) {
-                do {
-                    curleft += el.offsetLeft;
-                    curtop += el.offsetTop;
-                } while (el = el.offsetParent);
-            }
-
-            return { left: curleft, top: curtop };
-        }
-        ;
-
-    return {
-        // extended
-        init: function( options ){
-
-            var self = this;
-
-            // call parent init method
-            parent.init.call( this );
-            this.options.defaults( defaults );
-            this.options( options );
-
-            // vars
-            this.bodyData = {};
-            this.bodyDataByUID = {};
-
-            this.el = typeof this.options.el === 'string' ? document.getElementById(this.options.el) : this.options.el;
-
-            if ( !this.el ){
-                throw "No DOM element specified";
-            }
-
-            // init events
-            // when there are multiple touchdowns, grab is usually called separately for each,
-            // but we loop through e.changedTouches just in case
-            self.grab = function grab( e ){
-                var pos
-                    ,body
-                    ,touchId
-                    ,touch
-                    ,offset
-                    ,data
-                    ,touchIndex
-                    ,l
-                    ;
-
-                if ( self._world ){
-
-                    // Adjust for PointerEvent and older browsers
-                    if ( !e.changedTouches ) {
-                        e.changedTouches = [ e ];
-                    }
-
-                    offset = getElementOffset( e.target );
-
-                    for ( touchIndex = 0, l = e.changedTouches.length; touchIndex < l; touchIndex++) {
-                        touch = e.changedTouches[touchIndex];
-                        touchId = touch.identifier || touch.pointerId || "mouse";
-                        pos = { idx: touchId, x: touch.pageX - offset.left, y: touch.pageY - offset.top };
-                        body = self._world.findOne({ $at: new Physics.vector( pos ), $in: self.getTargets() });
-
-                        if ( body ){
-                            // we're trying to grab a body
-
-                            // fix the body in place
-                            body.state.vel.zero();
-                            body.state.angular.vel = 0;
-                            body.isGrabbed = true;
-                            // remember the currently grabbed bodies
-                            data = self.bodyData[touchId] || {};
-                            data.body = body;
-                            // wake the body up
-                            body.sleep( false );
-                            data.time = Physics.util.ticker.now();
-
-                            // if we're grabbing the same body twice we don't want to remember the wrong treatment.
-                            data.treatment = self.bodyDataByUID[ body.uid ] ? self.bodyDataByUID[ body.uid ].treatment : body.treatment;
-                            // change its treatment but remember its old treatment
-                            body.treatment = 'kinematic';
-                            // remember the click/touch offset
-                            data.pos = data.pos || new Physics.vector();
-                            data.pos.clone( pos );
-
-                            data.offset = data.offset || new Physics.vector();
-                            data.offset.clone( pos ).vsub( body.state.pos );
-                            // init touchPointsOld here, too, so we don't have to do it in "move"
-                            data.oldPos = data.oldPos || new Physics.vector();
-                            data.oldPos.clone( pos );
-
-                            pos.body = body;
-                            self.bodyData[touchId] = data;
-                            self.bodyDataByUID[ body.uid ] = data;
-                            self._world.emit('interact:grab', pos);
-
-                        } else {
-
-                            self._world.emit('interact:poke', pos);
-                        }
-                    }
-                }
-            };
-
-            // when there are multiple touchdowns, move is called once
-            // and e.changedTouches will have one or more touches in it
-            self.move = Physics.util.throttle(function move( e ){
-                var pos
-                    ,state
-                    ,body
-                    ,touchId
-                    ,touch
-                    ,offset
-                    ,data
-                    ,touchIndex
-                    ,l
-                    ;
-
-                if ( self._world ){
-
-                    // Adjust for PointerEvent and older browsers
-                    if ( !e.changedTouches ) {
-                        e.changedTouches = [ e ];
-                    }
-
-                    offset = getElementOffset( self.el );
-
-                    for ( touchIndex = 0, l = e.changedTouches.length; touchIndex < l; touchIndex++) {
-                        touch = e.changedTouches[touchIndex];
-                        touchId = touch.identifier || touch.pointerId || "mouse";
-                        pos = { idx: touchId, x: touch.pageX - offset.left, y: touch.pageY - offset.top };
-                        data = self.bodyData[touchId];
-
-                        if ( data ){
-                            body = data.body;
-
-                            // wake the body up
-                            body.sleep( false );
-                            data.time = Physics.util.ticker.now();
-
-                            // set old mouse position
-                            data.oldPos.clone( data.pos );
-                            // get new mouse position
-                            data.pos.clone( pos );
-
-                            pos.body = body;
-                        }
-
-                        self._world.emit('interact:move', pos);
-                    }
-                }
-
-            }, self.options.moveThrottle);
-
-            // when there are multiple touchups, release is called once
-            // and e.changedTouches will have one or more touches in it
-            self.release = function release( e ){
-                var pos
-                    ,body
-                    ,touchId
-                    ,touch
-                    ,offset
-                    ,data
-                    ,dt
-                    ,touchIndex
-                    ,l
-                    ;
-
-                if ( self._world ){
-
-                    // Adjust for PointerEvent and older browsers
-                    if ( !e.changedTouches ) {
-                        e.changedTouches = [ e ];
-                    }
-
-                    for ( touchIndex = 0, l = e.changedTouches.length; touchIndex < l; touchIndex++) {
-                        offset = getElementOffset( self.el );
-                        touch = e.changedTouches[touchIndex];
-                        touchId = touch.identifier || touch.pointerId || "mouse";
-                        pos = { idx: touchId, x: touch.pageX - offset.left, y: touch.pageY - offset.top };
-                        data = self.bodyData[touchId];
-
-                        // release the body
-                        if ( data ){
-                            body = data.body;
-                            // wake the body up
-                            body.sleep( false );
-                            // get new mouse position
-                            data.pos.clone( pos );
-
-                            dt = Math.max(Physics.util.ticker.now() - data.time, self.options.moveThrottle);
-                            body.treatment = data.treatment;
-                            // calculate the release velocity
-                            body.state.vel.clone( data.pos ).vsub( data.oldPos ).mult( 1 / dt );
-                            // make sure it's not too big
-                            body.state.vel.clamp( self.options.minVel, self.options.maxVel );
-
-                            body.isGrabbed = false;
-                            pos.body = body;
-
-                            delete body.isGrabbed;
-                        }
-
-                        // emit before we delete the vars in case
-                        // the listeners need the body
-                        self._world.emit('interact:release', pos);
-
-                        // remove vars
-                        delete self.bodyData[touchId];
-                    }
-                }
-            };
-        },
-
-        // extended
-        connect: function( world ){
-
-            // subscribe the .behave() method to the position integration step
-            world.on('integrate:positions', this.behave, this);
-
-            if ( window.PointerEvent ) {
-
-                this.el.addEventListener('pointerdown', this.grab);
-                window.addEventListener('pointermove', this.move);
-                window.addEventListener('pointerup', this.release);
-
-            } else {
-
-                this.el.addEventListener('mousedown', this.grab);
-                this.el.addEventListener('touchstart', this.grab);
-
-                window.addEventListener('mousemove', this.move);
-                window.addEventListener('touchmove', this.move);
-
-                window.addEventListener('mouseup', this.release);
-                window.addEventListener('touchend', this.release);
-
-            }
-        },
-
-        // extended
-        disconnect: function( world ){
-
-            // unsubscribe when disconnected
-            world.off('integrate:positions', this.behave, this);
-
-            if ( window.PointerEvent ) {
-
-                this.el.removeEventListener('pointerdown', this.grab);
-                window.removeEventListener('pointermove', this.move);
-                window.removeEventListener('pointerup', this.release);
-
-            } else {
-
-                this.el.removeEventListener('mousedown', this.grab);
-                this.el.removeEventListener('touchstart', this.grab);
-
-                window.removeEventListener('mousemove', this.move);
-                window.removeEventListener('touchmove', this.move);
-
-                window.removeEventListener('mouseup', this.release);
-                window.removeEventListener('touchend', this.release);
-
-            }
-        },
-
-        // extended
-        behave: function( data ){
-
-            var self = this
-                ,state
-                ,dt = Math.max(data.dt, self.options.moveThrottle)
-                ,body
-                ,d
-                ;
-
-            // if we have one or more bodies grabbed, we need to move them to the new mouse/finger positions.
-            // we'll do this by adjusting the velocity so they get there at the next step
-            for ( var touchId in self.bodyData ) {
-                d = self.bodyData[touchId];
-                body = d.body;
-                state = body.state;
-                state.vel.clone( d.pos ).vsub( d.offset ).vsub( state.pos ).mult( 1 / dt );
-            }
-        }
-    };
-});
-
-
-// ---
-// inside: src/behaviors/newtonian.js
-
-/**
- * class NewtonianBehavior < Behavior
- *
- * `Physics.behavior('newtonian')`.
- *
- * Newtonian attraction between bodies (inverse square law).
- *
- * Additional options include:
- * - strength: The strength of the interaction between bodies. (default: `1`)
- * - max: The maximum distance between bodies at which to apply the behavior. (default: `false`... infinite)
- * - min: The minimum distance between bodies at which to apply the behavior. (default: `false`... autocalculate)
- **/
-Physics.behavior('newtonian', function( parent ){
-
-    var defaults = {
-
-        strength: 1,
-        // max distance to apply it to
-        max: false, // infinite
-        // min distance to apply it to
-        min: false // auto calc
-    };
-
-    return {
-
-        // extended
-        init: function( options ){
-
-            var self = this;
-            // call parent init method
-            parent.init.call( this );
-            this.options.defaults( defaults );
-            this.options.onChange(function( opts ){
-                self._maxDistSq = opts.max === false ? Infinity : opts.max * opts.max;
-                self._minDistSq = opts.min ? opts.min * opts.min : 100 * opts.strength;
-            });
-            this.options( options );
-        },
-
-        calcPotential: function( posA, posB, out ){
-
-            var strength = this.options.strength
-                ,minDistSq = this._minDistSq
-                ,maxDistSq = this._maxDistSq
-                ,normsq
-                ,g
-                ,pos
-                ;
-
-            pos = out || new Physics.vector();
-
-            // clone the position
-            pos.clone( posB ).vsub( posA );
-            // get the square distance
-            normsq = pos.normSq();
-
-            if (normsq > minDistSq && normsq < maxDistSq){
-
-                g = strength / normsq;
-                return pos.normalize().mult( g );
-            }
-
-            return pos.zero();
-        },
-
-        // extended
-        behave: function( data ){
-
-            var bodies = this.getTargets()
-                ,body
-                ,other
-                ,scratch = Physics.scratchpad()
-                ,potential = scratch.vector()
-                ,comp
-                ,bodyA
-                ,bodyB
-                ,posA = scratch.vector()
-                ,posB = scratch.vector()
-                ,i, j, k, m, l, ll, lll
-                ;
-
-            for ( j = 0, l = bodies.length; j < l; j++ ){
-
-                body = bodies[ j ];
-
-                for ( i = j + 1; i < l; i++ ){
-
-                    other = bodies[ i ];
-
-                    if ( body.name === 'compound' ){
-                        comp = body;
-                    } else if ( other.name === 'compound' ){
-                        comp = other;
-                        other = body;
-                    }
-
-                    if ( comp ){
-                        if ( other.name === 'compound' ){
-                            for ( k = 0, ll = comp.children.length; k < ll; k++ ){
-                                bodyA = comp.children[ k ];
-                                comp.toWorldCoords( posA.clone( bodyA.state.pos ).vadd( comp.offset ) );
-                                for ( m = 0, lll = other.children.length; m < lll; m++ ){
-                                    bodyB = other.children[ m ];
-                                    other.toWorldCoords( posB.clone( bodyB.state.pos ).vadd( other.offset ) );
-                                    this.calcPotential( posA, posB, potential );
-                                    comp.accelerate( potential.mult( bodyB.mass ) );
-                                    other.accelerate( potential.mult( bodyA.mass/bodyB.mass ).negate() );
-                                }
-                            }
-                        } else {
-                            for ( k = 0, ll = comp.children.length; k < ll; k++ ){
-                                bodyA = comp.children[ k ];
-                                comp.toWorldCoords( posA.clone( bodyA.state.pos ).vadd( comp.offset ) );
-                                this.calcPotential( posA, other.state.pos, potential );
-                                comp.accelerate( potential.mult( other.mass ) );
-                                other.accelerate( potential.mult( bodyA.mass/other.mass ).negate() );
-                            }
-                        }
-
-                    } else {
-
-                        this.calcPotential( body.state.pos, other.state.pos, potential );
-                        body.accelerate( potential.mult( other.mass ) );
-                        other.accelerate( potential.mult( body.mass/other.mass ).negate() );
-                    }
-
-                    comp = null;
-                }
-            }
-
-            scratch.done();
-        }
-    };
-});
-
-
-// ---
-// inside: src/behaviors/sweep-prune.js
-
-/**
- * class SweepPruneBehavior < Behavior
- *
- * `Physics.behavior('sweep-prune')`.
- *
- * Sweep and Prune implementation for broad phase collision detection.
- *
- * This massively improves the speed of collision detection. It's set up to always be used with [[BodyCollisionDetection]], and [[BodyImpulseResponse]].
- *
- * Additional options include:
- * - channel: The channel to publish collision candidates to. (default: `collisions:candidates`)
- **/
-Physics.behavior('sweep-prune', function( parent ){
-
-    var uid = 1;
-
-    // Get a unique numeric id for internal use
-    var getUniqueId = function getUniqueId(){
-
-        return uid++;
-    };
-
-    // add z: 2 to get this to work in 3D
-    var dof = { x: 0, y: 1 }; // degrees of freedom
-    // change to "3" to get it to work in 3D
-    var maxDof = 2;
-
-    var pairHash = Physics.util.pairHash;
-
-    return {
-
-        // extended
-        init: function( options ){
-
-            parent.init.call( this );
-            this.options.defaults({
-                channel: 'collisions:candidates' //default channel
-            });
-            this.options( options );
-
-            this.encounters = [];
-            this.candidates = [];
-
-            this.clear();
-        },
-
-        /**
-         * SweepPruneBehavior#clear()
-         *
-         * Refresh tracking data
-         **/
-        clear: function(){
-
-            this.tracked = [];
-            this.pairs = []; // pairs selected as candidate collisions by broad phase
-            this.intervalLists = []; // stores lists of aabb projection intervals to be sorted
-
-            // init intervalLists
-            for ( var xyz = 0; xyz < maxDof; ++xyz ){
-
-                this.intervalLists[ xyz ] = [];
-            }
-        },
-
-        // extended
-        connect: function( world ){
-
-            world.on( 'add:body', this.trackBody, this );
-            world.on( 'remove:body', this.untrackBody, this );
-            world.on( 'integrate:positions', this.sweep, this, 1 );
-
-            // add current bodies
-            var bodies = world.getBodies();
-            for ( var i = 0, l = bodies.length; i < l; ++i ){
-
-                this.trackBody({ body: bodies[ i ] });
-            }
-        },
-
-        // extended
-        disconnect: function( world ){
-
-            world.off( 'add:body', this.trackBody, this );
-            world.off( 'remove:body', this.untrackBody, this );
-            world.off( 'integrate:positions', this.sweep, this, 1 );
-            this.clear();
-        },
-
-        /** internal
-         * SweepPruneBehavior#broadPhase() -> Array
-         * + (Array): The candidate data of overlapping aabbs
-         *
-         * Execute the broad phase and get candidate collisions
-         **/
-        broadPhase: function(){
-
-            this.updateIntervals();
-            this.sortIntervalLists();
-
-            if ( this._world ){
-                this._world.emit('sweep-prune:intervals', this.intervalLists);
-            }
-
-            return this.checkOverlaps();
-        },
-
-        /** internal
-         * SweepPruneBehavior#sortIntervalLists()
-         *
-         * Simple insertion sort for each axis
-         **/
-        sortIntervalLists: function(){
-
-            var list
-                ,len
-                ,i
-                ,hole
-                ,bound
-                ,boundVal
-                ,left
-                ,leftVal
-                ,axis
-                ;
-
-            // for each axis...
-            for ( var xyz = 0; xyz < maxDof; ++xyz ){
-
-                // get the intervals for that axis
-                list = this.intervalLists[ xyz ];
-                i = 0;
-                len = list.length;
-                axis = xyz;
-
-                // for each interval bound...
-                while ( (++i) < len ){
-
-                    // store bound
-                    bound = list[ i ];
-                    boundVal = bound.val.get( axis );
-                    hole = i;
-
-                    left = list[ hole - 1 ];
-                    leftVal = left && left.val.get( axis );
-
-                    // while others are greater than bound...
-                    while (
-                        hole > 0 &&
-                        (
-                            leftVal > boundVal ||
-                            // if it's an equality, only move it over if
-                            // the hole was created by a minimum
-                            // and the previous is a maximum
-                            // so that we detect contacts also
-                            leftVal === boundVal &&
-                            ( left.type && !bound.type )
-                        )
-                    ) {
-
-                        // move others greater than bound to the right
-                        list[ hole ] = left;
-                        hole--;
-                        left = list[ hole - 1 ];
-                        leftVal = left && left.val.get( axis );
-                    }
-
-                    // insert bound in the hole
-                    list[ hole ] = bound;
-                }
-            }
-        },
-
-        /** internal
-         * SweepPruneBehavior#getPair( tr1, tr2, doCreate ) -> Object
-         * - tr1 (Object): First tracker
-         * - tr2 (Object): Second tracker
-         * - doCreate (Boolean): Create if not found
-         * + (Object): Pair object or null if not found
-         *
-         * Get a pair object for the tracker objects
-         **/
-        getPair: function(tr1, tr2, doCreate){
-
-            var hash = pairHash( tr1.id, tr2.id );
-
-            if ( hash === false ){
-                return null;
-            }
-
-            var c = this.pairs[ hash ];
-
-            if ( !c ){
-
-                if ( !doCreate ){
-                    return null;
-                }
-
-                c = this.pairs[ hash ] = {
-                    bodyA: tr1.body,
-                    bodyB: tr2.body,
-                    flag: 1
-                };
-            }
-
-            if ( doCreate){
-                c.flag = 1;
-            }
-
-            return c;
-        },
-
-        // getPair: function(tr1, tr2, doCreate){
-
-        //     var hash = Math.min(tr1.id, tr2.id) // = pairHash( tr1.id, tr2.id )
-        //         ,other = Math.max(tr1.id, tr2.id)
-        //         ,first
-        //         ,c
-        //         ;
-
-        //     if ( hash === false ){
-        //         return null;
-        //     }
-
-        //     first = this.pairs[ hash ];
-
-        //     if ( !first ){
-        //         if ( !doCreate ){
-        //             return null;
-        //         }
-
-        //         first = this.pairs[ hash ] = [];
-        //     }
-
-        //     c = first[ other ];
-
-        //     if ( !c ){
-
-        //         if ( !doCreate ){
-        //             return null;
-        //         }
-
-        //         c = first[ other ] = {
-        //             bodyA: tr1.body,
-        //             bodyB: tr2.body,
-        //             flag: 1
-        //         };
-        //     }
-
-        //     return c;
-        // },
-
-        /** internal
-         * SweepPruneBehavior#checkOverlaps() -> Array
-         * + (Array): List of candidate collisions
-         *
-         * Check each axis for overlaps of bodies AABBs
-         **/
-        checkOverlaps: function(){
-
-            var isX
-                ,hash
-                ,tr1
-                ,tr2
-                ,bound
-                ,list
-                ,len
-                ,i
-                ,j
-                ,c
-                // determine which axis is the last we need to check
-                ,collisionFlag = 1 << (dof.z + 1) << (dof.y + 1) << (dof.x + 1)
-                ,encounters = this.encounters
-                ,enclen = 0
-                ,candidates = this.candidates
-                ;
-
-            Physics.util.clearArray( encounters );
-            Physics.util.clearArray( candidates );
-
-            for ( var xyz = 0; xyz < maxDof; ++xyz ){
-
-                // is the x coord
-                isX = (xyz === 0);
-                // get the interval list for this axis
-                list = this.intervalLists[ xyz ];
-
-                // for each interval bound
-                for ( i = 0, len = list.length; i < len; i++ ){
-
-                    bound = list[ i ];
-                    tr1 = bound.tracker;
-
-                    if ( bound.type ){
-
-                        // is a max
-
-                        j = enclen;
-
-                        for ( j = enclen - 1; j >= 0; j-- ){
-
-                            tr2 = encounters[ j ];
-
-                            // if they are the same tracked interval
-                            if ( tr2 === tr1 ){
-
-                                // remove the interval from the encounters list
-                                // faster than .splice()
-                                if ( j < enclen - 1 ) {
-
-                                    encounters[ j ] = encounters.pop();
-
-                                } else {
-
-                                    // encountered a max right after a min... no overlap
-                                    encounters.pop();
-                                }
-
-                                enclen--;
-
-                            } else {
-
-                                // check if we have flagged this pair before
-                                // if it's the x axis, create a pair
-                                c = this.getPair( tr1, tr2, isX );
-
-                                if ( c && c.flag < collisionFlag ){
-
-                                    // if it's greater than the axis index, set the flag
-                                    // to = 0.
-                                    // if not, increment the flag by one.
-                                    c.flag = c.flag << (xyz + 1);
-
-                                    // c.flag will equal collisionFlag
-                                    // if we've incremented the flag
-                                    // enough that all axes are overlapping
-                                    if ( c.flag === collisionFlag ){
-
-                                        // overlaps on all axes.
-                                        // add it to possible collision
-                                        // candidates list for narrow phase
-
-                                        candidates.push( c );
-                                    }
-                                }
-                            }
-                        }
-
-                    } else {
-
-                        // is a min
-                        // just add this minimum to the encounters list
-                        enclen = encounters.push( tr1 );
-                    }
-                }
-            }
-
-            return candidates;
-        },
-
-        /** internal
-         * SweepPruneBehavior#updateIntervals()
-         *
-         * Update position intervals on each axis
-         **/
-        updateIntervals: function(){
-
-            var tr
-                ,intr
-                ,aabb
-                ,list = this.tracked
-                ,i = list.length
-                ;
-
-            // for all tracked bodies
-            while ( (--i) >= 0 ){
-
-                tr = list[ i ];
-                intr = tr.interval;
-                aabb = tr.body.aabb();
-
-                // copy the position (plus or minus) the aabb half-dimensions
-                // into the min/max intervals
-                intr.min.val.clone( aabb ).sub( aabb.hw, aabb.hh );
-                intr.max.val.clone( aabb ).add( aabb.hw, aabb.hh );
-            }
-        },
-
-        /** internal
-         * SweepPruneBehavior#trackBody( data )
-         * - data (Object): Event data
-         *
-         * Event callback to add body to list of those tracked by sweep and prune
-         **/
-        trackBody: function( data ){
-
-            var body = data.body
-                ,tracker = {
-
-                    id: getUniqueId(),
-                    body: body
-                }
-                ,intr = {
-
-                    min: {
-                        type: false, //min
-                        val: new Physics.vector(),
-                        tracker: tracker
-                    },
-
-                    max: {
-                        type: true, //max
-                        val: new Physics.vector(),
-                        tracker: tracker
-                    }
-                }
-                ;
-
-            tracker.interval = intr;
-            this.tracked.push( tracker );
-
-            for ( var xyz = 0; xyz < maxDof; ++xyz ){
-
-                this.intervalLists[ xyz ].push( intr.min, intr.max );
-            }
-        },
-
-        /** internal
-         * SweepPruneBehavior#untrackBody( data )
-         * - data (Object): Event data
-         *
-         * Event callback to remove body from list of those tracked
-         **/
-        untrackBody: function( data ){
-
-            var body = data.body
-                ,list
-                ,minmax
-                ,trackedList = this.tracked
-                ,tracker
-                ,count
-                ;
-
-            for ( var i = 0, l = trackedList.length; i < l; ++i ){
-
-                tracker = trackedList[ i ];
-
-                if ( tracker.body === body ){
-
-                    // remove the tracker at this index
-                    trackedList.splice(i, 1);
-
-                    for ( var xyz = 0; xyz < maxDof; ++xyz ){
-
-                        count = 0;
-                        list = this.intervalLists[ xyz ];
-
-                        for ( var j = 0, m = list.length; j < m; ++j ){
-
-                            minmax = list[ j ];
-
-                            if ( minmax === tracker.interval.min || minmax === tracker.interval.max ){
-
-                                // remove interval from list
-                                list.splice(j, 1);
-                                j--;
-                                l--;
-
-                                if (count > 0){
-                                    break;
-                                }
-
-                                count++;
-                            }
-                        }
-                    }
-
-                    break;
-                }
-            }
-        },
-
-        /** internal
-         * SweepPruneBehavior#sweep( data )
-         * - data (Object): Event data
-         *
-         * Event callback to sweep and publish event if any candidate collisions are found
-         **/
-        sweep: function( data ){
-
-            var self = this
-                ,candidates
-                ;
-
-            candidates = self.broadPhase();
-
-            if ( candidates.length ){
-
-                this._world.emit( this.options.channel, {
-                    candidates: candidates
-                });
-            }
-        }
-    };
-});
-
-
-// ---
-// inside: src/behaviors/verlet-constraints.js
-
-/**
- * class VerletConstraintsBehavior < Behavior
- *
- * `Physics.behavior('verlet-constraints')`.
- *
- * Verlet constraints manager.
- *
- * Handles distance constraints, and angle constraints
- *
- * Additional options include:
- * - iterations: The number of iterations to take to relax the constraints. (default: `2`)
- **/
-Physics.behavior('verlet-constraints', function( parent ){
-
-    var TWOPI = 2 * Math.PI;
-
-    var defaults = {
-
-        // number of iterations to resolve constraints
-        iterations: 2
-    };
-
-    return {
-
-        // extended
-        init: function( options ){
-
-            parent.init.call( this );
-            this.options.defaults( defaults );
-            this.options( options );
-
-            this._distanceConstraints = [];
-            this._angleConstraints = [];
-        },
-
-        // extended
-        connect: function( world ){
-
-            var intg = world.integrator();
-
-            if ( intg && intg.name.indexOf('verlet') < 0 ){
-
-                throw 'The rigid constraint manager needs a world with a "verlet" compatible integrator.';
-            }
-
-            world.on('integrate:positions', this.resolve, this);
-        },
-
-        // extended
-        disconnect: function( world ){
-
-            world.off('integrate:positions', this.resolve, this);
-        },
-
-        /**
-         * VerletConstraintsBehavior#drop() -> this
-         *
-         * Remove all constraints
-         **/
-        drop: function(){
-
-            // drop the current constraints
-            this._distanceConstraints = [];
-            this._angleConstraints = [];
-            return this;
-        },
-
-        /**
-         * VerletConstraintsBehavior#distanceConstraint( bodyA, bodyB[, stiffness, targetLength] ) -> Object
-         * - bodyA (Body): First body
-         * - bodyB (Body): Second body
-         * - stiffness (Number): A number between 0 and 1 that represents the stiffness of the constraint. Defaults to: `0.5`
-         * - targetLength (Number): Target length. defaults to current distance between the bodies
-         * + (Object): The constraint data object
-         *
-         * Constrain two bodies to a target relative distance.
-         *
-         * Returns constraint data that can be used to remove the constraint later.
-         *
-         * - `.bodyA` and `.bodyB` are references to the bodies
-         * - `.type` is the type of constraint
-         * - `.id` is the string ID of the constraint
-         * - `.stiffness` is the stiffness
-         * - `.targetLength` is the target length
-         **/
-        distanceConstraint: function( bodyA, bodyB, stiffness, targetLength ){
-
-            var cst;
-
-            if (!bodyA || !bodyB){
-
-                return false;
-            }
-
-            cst = {
-                id: Physics.util.uniqueId('dis-constraint'),
-                type: 'dis',
-                bodyA: bodyA,
-                bodyB: bodyB,
-                stiffness: stiffness || 0.5,
-                targetLength: targetLength || bodyB.state.pos.dist( bodyA.state.pos )
-            };
-
-            cst.targetLengthSq = cst.targetLength * cst.targetLength;
-
-            this._distanceConstraints.push( cst );
-            return cst;
-        },
-
-        /**
-         * VerletConstraintsBehavior#angleConstraint( bodyA, bodyB, bodyC[, stiffness, targetAngle] ) -> Object
-         * - bodyA (Body): First body
-         * - bodyB (Body): Second body
-         * - bodyC (Body): Third body
-         * - stiffness (Number): A number between 0 and 1 that represents the stiffness of the constraint. Defaults to: `0.5`
-         * - targetAngle (Number): Target angle. Defaults to the current angle between bodies
-         * + (Object): The constraint data object
-         *
-         * Constrain three bodies to a target relative angle
-         *
-         * Returns constraint data that can be used to remove the constraint later.
-         *
-         * - `.bodyA`, `.bodyB`, and `.bodyC` are references to the bodies
-         * - `.type` is the type of constraint
-         * - `.id` is the string ID of the constraint
-         * - `.stiffness` is the stiffness
-         * - `.targetAngle` is the target angle
-         **/
-        angleConstraint: function( bodyA, bodyB, bodyC, stiffness, targetAngle ){
-
-            var cst;
-
-            if (!bodyA || !bodyB){
-
-                return false;
-            }
-
-            cst = {
-                id: Physics.util.uniqueId('ang-constraint'),
-                type: 'ang',
-                bodyA: bodyA,
-                bodyB: bodyB,
-                bodyC: bodyC,
-                stiffness: stiffness || 0.5,
-                targetAngle: targetAngle || bodyB.state.pos.angle2( bodyA.state.pos, bodyC.state.pos )
-            };
-
-            this._angleConstraints.push( cst );
-            return cst;
-        },
-
-        /**
-         * VerletConstraintsBehavior#remove( constraintData ) -> this
-         * VerletConstraintsBehavior#remove( constraintId ) -> this
-         * - constraintData (Object): The constraint data returned when creating a constraint
-         * - constraintId (String): The constraint id
-         *
-         * Remove a constraint
-         **/
-        remove: function( cstrOrId ){
-
-            var constraints
-                ,type
-                ,isObj
-                ,i
-                ,l
-                ;
-
-            isObj = Physics.util.isObject( cstrOrId );
-
-            type = (isObj) ? cstrOrId.type : cstrOrId.substr(0, 3);
-            constraints = ( type === 'ang' ) ? this._angleConstraints : this._distanceConstraints;
-
-            if ( isObj ){
-
-                for ( i = 0, l = constraints.length; i < l; ++i ){
-
-                    if ( constraints[ i ] === cstrOrId ){
-
-                        constraints.splice( i, 1 );
-                        return this;
-                    }
-                }
-            } else {
-
-                for ( i = 0, l = constraints.length; i < l; ++i ){
-
-                    if ( constraints[ i ].id === cstrOrId ){
-
-                        constraints.splice( i, 1 );
-                        return this;
-                    }
-                }
-            }
-
-            return this;
-        },
-
-        /** internal
-         * VerletConstraintsBehavior#resolveAngleConstraints( coef )
-         * - coef (Number): Coefficient for this resolution phase
-         *
-         * Resolve angle constraints.
-         **/
-        resolveAngleConstraints: function( coef ){
-
-            var constraints = this._angleConstraints
-                ,scratch = Physics.scratchpad()
-                ,trans = scratch.transform()
-                ,con
-                ,ang
-                ,corr
-                ,proportion
-                ,invMassSum
-                ;
-
-            for ( var i = 0, l = constraints.length; i < l; ++i ){
-
-                con = constraints[ i ];
-
-                ang = con.bodyB.state.pos.angle2( con.bodyA.state.pos, con.bodyC.state.pos );
-                corr = ang - con.targetAngle;
-
-                if (!corr){
-
-                    continue;
-
-                } else if (corr <= -Math.PI){
-
-                    corr += TWOPI;
-
-                } else if (corr >= Math.PI){
-
-                    corr -= TWOPI;
-                }
-
-                trans.setTranslation( con.bodyB.state.pos );
-
-                corr *= -coef * con.stiffness;
-
-                if ( con.bodyA.treatment === 'dynamic' && con.bodyB.treatment === 'dynamic' && con.bodyC.treatment === 'dynamic' ){
-                    invMassSum = 1 / (con.bodyA.mass + con.bodyB.mass + con.bodyC.mass);
-                }
-
-                if ( con.bodyA.treatment === 'dynamic' ){
-
-                    if ( con.bodyB.treatment === 'dynamic' && con.bodyC.treatment === 'dynamic' ){
-
-                        ang = corr * (con.bodyB.mass + con.bodyC.mass) * invMassSum;
-
-                    } else if ( con.bodyB.treatment !== 'dynamic' ){
-
-                        ang = corr * con.bodyC.mass / ( con.bodyC.mass + con.bodyA.mass );
-
-                    } else {
-
-                        ang = corr * con.bodyB.mass / ( con.bodyB.mass + con.bodyA.mass );
-                    }
-
-
-                    trans.setRotation( ang );
-                    con.bodyA.state.pos.translateInv( trans );
-                    con.bodyA.state.pos.rotate( trans );
-                    con.bodyA.state.pos.translate( trans );
-                }
-
-                if ( con.bodyC.treatment === 'dynamic' ){
-
-                    if ( con.bodyA.treatment === 'dynamic' && con.bodyB.treatment === 'dynamic' ){
-
-                        ang = -corr * (con.bodyB.mass + con.bodyA.mass) * invMassSum;
-
-                    } else if ( con.bodyB.treatment !== 'dynamic' ){
-
-                        ang = -corr * con.bodyA.mass / ( con.bodyC.mass + con.bodyA.mass );
-
-                    } else {
-
-                        ang = -corr * con.bodyB.mass / ( con.bodyB.mass + con.bodyC.mass );
-                    }
-
-                    trans.setRotation( ang );
-                    con.bodyC.state.pos.translateInv( trans );
-                    con.bodyC.state.pos.rotate( trans );
-                    con.bodyC.state.pos.translate( trans );
-                }
-
-                if ( con.bodyB.treatment === 'dynamic' ){
-
-                    if ( con.bodyA.treatment === 'dynamic' && con.bodyC.treatment === 'dynamic' ){
-
-                        ang = corr * (con.bodyA.mass + con.bodyC.mass) * invMassSum;
-
-                    } else if ( con.bodyA.treatment !== 'dynamic' ){
-
-                        ang = corr * con.bodyC.mass / ( con.bodyC.mass + con.bodyB.mass );
-
-                    } else {
-
-                        ang = corr * con.bodyA.mass / ( con.bodyA.mass + con.bodyC.mass );
-                    }
-
-                    // ang = corr;
-
-                    trans.setRotation( ang ).setTranslation( con.bodyA.state.pos );
-                    con.bodyB.state.pos.translateInv( trans );
-                    con.bodyB.state.pos.rotate( trans );
-                    con.bodyB.state.pos.translate( trans );
-
-                    trans.setTranslation( con.bodyC.state.pos );
-                    con.bodyB.state.pos.translateInv( trans );
-                    con.bodyB.state.pos.rotateInv( trans );
-                    con.bodyB.state.pos.translate( trans );
-                }
-
-                con.bodyA.sleepCheck();
-                con.bodyB.sleepCheck();
-                con.bodyC.sleepCheck();
-            }
-
-            scratch.done();
-        },
-
-        /** internal
-         * VerletConstraintsBehavior#resolveDistanceConstraints( coef )
-         * - coef (Number): Coefficient for this resolution phase
-         *
-         * Resolve distance constraints.
-         **/
-        resolveDistanceConstraints: function( coef ){
-
-            var constraints = this._distanceConstraints
-                ,scratch = Physics.scratchpad()
-                ,BA = scratch.vector()
-                ,con
-                ,len
-                ,corr
-                ,proportion
-                ;
-
-            for ( var i = 0, l = constraints.length; i < l; ++i ){
-
-                con = constraints[ i ];
-
-                // move constrained bodies to target length based on their
-                // mass proportions
-                BA.clone( con.bodyB.state.pos ).vsub( con.bodyA.state.pos );
-                len = BA.normSq() || Math.random() * 0.0001;
-                corr = coef * con.stiffness * ( len - con.targetLengthSq ) / len;
-
-                BA.mult( corr );
-                proportion = (con.bodyA.treatment !== 'dynamic' || con.bodyB.treatment !== 'dynamic') ? 1 : con.bodyB.mass / (con.bodyA.mass + con.bodyB.mass);
-
-                if ( con.bodyA.treatment === 'dynamic' ){
-
-                    if ( con.bodyB.treatment === 'dynamic' ){
-                        BA.mult( proportion );
-                    }
-
-                    con.bodyA.state.pos.vadd( BA );
-
-                    if ( con.bodyB.treatment === 'dynamic' ){
-                        BA.mult( 1 / proportion );
-                    }
-                }
-
-                if ( con.bodyB.treatment === 'dynamic' ){
-
-                    if ( con.bodyA.treatment === 'dynamic' ){
-                        BA.mult( 1 - proportion );
-                    }
-
-                    con.bodyB.state.pos.vsub( BA );
-                }
-
-                con.bodyA.sleepCheck();
-                con.bodyB.sleepCheck();
-            }
-
-            scratch.done();
-        },
-
-        /** internal
-         * VerletConstraintsBehavior#shuffleConstraints()
-         *
-         * Mix up the constraints.
-         **/
-        shuffleConstraints: function(){
-
-            this._distanceConstraints = Physics.util.shuffle( this._distanceConstraints );
-            this._angleConstraints = Physics.util.shuffle( this._angleConstraints );
-        },
-
-        /** internal
-         * VerletConstraintsBehavior#resolve()
-         *
-         * Resolve all constraints.
-         **/
-        resolve: function(){
-
-            var its = this.options.iterations
-                ,coef = 1 / its
-                ;
-
-            for (var i = 0; i < its; i++){
-
-                // this.shuffleConstraints();
-                this.resolveDistanceConstraints( coef );
-                this.resolveAngleConstraints( coef );
-            }
-        },
-
-        /**
-         * VerletConstraintsBehavior#getConstraints() -> Object
-         * + (Object): The object containing copied arrays of the constraints
-         *
-         * Get all constraints.
-         **/
-        getConstraints: function(){
-
-            return {
-                distanceConstraints: [].concat(this._distanceConstraints),
-                angleConstraints: [].concat(this._angleConstraints)
-            };
-        }
-    };
-});
-
-
-// ---
-// inside: src/integrators/improved-euler.js
-
-Physics.integrator('improved-euler', function( parent ){
-
-    return {
-        /**
-         * class ImprovedEuler < Integrator
-         *
-         * `Physics.integrator('improved-euler')`.
-         *
-         * The improved euler integrator.
-         **/
-
-        // extended
-        init: function( options ){
-
-            // call parent init
-            parent.init.call(this, options);
-        },
-
-        // extended
-        integrateVelocities: function( bodies, dt ){
-
-            // half the timestep squared
-            var drag = 1 - this.options.drag
-                ,body = null
-                ,state
-                ;
-
-            for ( var i = 0, l = bodies.length; i < l; ++i ){
-
-                body = bodies[ i ];
-                state = body.state;
-
-                // only integrate if the body isn't fixed
-                if ( body.treatment !== 'static' && !body.sleep( dt ) ){
-
-                    // Inspired from https://github.com/soulwire/Coffee-Physics
-                    // @licence MIT
-                    //
-                    // x += (v * dt) + (a * 0.5 * dt * dt)
-                    // v += a * dt
-
-
-                    // Scale force to mass.
-                    // state.acc.mult( body.massInv );
-
-                    // Remember velocity for future use.
-                    state.old.vel.clone( state.vel );
-
-                    // remember original acc
-                    state.old.acc.clone( state.acc );
-
-                    // Update velocity first so we can reuse the acc vector.
-                    // a *= dt
-                    // v += a ...
-                    state.vel.vadd( state.acc.mult( dt ) );
-
-                    // Apply "air resistance".
-                    if ( drag ){
-
-                        state.vel.mult( drag );
-                    }
-
-                    // Reset accel
-                    state.acc.zero();
-
-                    //
-                    // Angular components
-                    //
-
-                    state.old.angular.vel = state.angular.vel;
-                    state.angular.vel += state.angular.acc * dt;
-                    state.angular.acc = 0;
-
-                } else {
-                    // set the velocity and acceleration to zero!
-                    state.vel.zero();
-                    state.acc.zero();
-                    state.angular.vel = 0;
-                    state.angular.acc = 0;
-                }
-            }
-        },
-
-        // extended
-        integratePositions: function( bodies, dt ){
-
-            // half the timestep squared
-            var halfdtdt = 0.5 * dt * dt
-                ,body = null
-                ,state
-                // use cached vector instances
-                // so we don't need to recreate them in a loop
-                ,scratch = Physics.scratchpad()
-                ,vel = scratch.vector()
-                ,angVel
-                ;
-
-            for ( var i = 0, l = bodies.length; i < l; ++i ){
-
-                body = bodies[ i ];
-                state = body.state;
-
-                // only integrate if the body isn't fixed
-                if ( body.treatment !== 'static' && !body.sleep() ){
-
-
-                    // Store previous location.
-                    state.old.pos.clone( state.pos );
-
-                    // Update position.
-                    // ...
-                    // oldV *= dt
-                    // a *= 0.5 * dt
-                    // x += oldV + a
-                    vel.clone( state.old.vel );
-                    state.pos.vadd( vel.mult( dt ) ).vadd( state.old.acc.mult( halfdtdt ) );
-
-                    state.old.acc.zero();
-
-                    //
-                    // Angular components
-                    //
-
-                    state.old.angular.pos = state.angular.pos;
-                    state.angular.pos += state.old.angular.vel * dt + state.old.angular.acc * halfdtdt;
-                    state.old.angular.acc = 0;
-
-                }
-            }
-
-            scratch.done();
-        }
-    };
-});
-
-
-// ---
-// inside: src/integrators/velocity-verlet-alt.js
-
-Physics.integrator('velocity-verlet-alt', function( parent ){
-
-    // for this integrator we need to know if the object has been integrated before
-    // so let's add a mixin to bodies
-
-    Physics.body.mixin({
-
-        started: function( val ){
-            if ( val !== undefined ){
-                this._started = true;
-            }
-
-            return !!this._started;
-        }
-    });
-
-
-    return {
-        /**
-         * class VelocityVerlet < Integrator
-         *
-         * `Physics.integrator('velocity-verlet')`.
-         *
-         * The velocity-verlet integrator.
-         **/
-
-        // extended
-        init: function( options ){
-
-            // call parent init
-            parent.init.call(this, options);
-        },
-
-        // extended
-        integrateVelocities: function( bodies, dt ){
-
-            // half the timestep
-            var dtdt = dt * dt
-                ,drag = 1 - this.options.drag
-                ,body = null
-                ,state
-                ;
-
-            for ( var i = 0, l = bodies.length; i < l; ++i ){
-
-                body = bodies[ i ];
-                state = body.state;
-
-                // only integrate if the body isn't static
-                if ( body.treatment !== 'static' ){
-
-                    // v = v_prev + 0.5 * (a_prev + a) * dt
-                    // x = x_prev + v_prev * dt + 0.5 * a_prev * dt * dt
-
-                    // use the velocity in vel if the velocity has been changed manually
-                    if ( !body.started() ){
-
-                        // Set old vals on first integration
-                        state.old.acc.clone( state.acc );
-                        state.old.acc.mult( dt );
-                        state.old.vel.clone( state.vel ).vsub( state.old.acc );
-                        state.old.acc.mult( 1/dt );
-                    }
-
-                    // Apply "air resistance".
-                    if ( drag ){
-
-                        state.vel.mult( drag );
-                    }
-
-                    // Apply acceleration
-                    // v += 0.5 * (a_prev + a) * dt
-                    state.vel.vadd( state.old.acc.vadd( state.acc ).mult( 0.5 * dt ) );
-
-                    // Reset accel
-                    // state.acc.zero();
-
-                    //
-                    // Angular components
-                    //
-
-                    if ( !body.started() ){
-
-                        // Set old vals on first integration
-                        state.old.angular.acc = state.angular.acc;
-                        state.old.angular.vel = state.angular.vel - state.old.angular.acc * dt;
-                    }
-
-                    state.angular.vel += 0.5 * (state.angular.acc + state.old.angular.acc) * dt;
-                    state.angular.acc = 0;
-
-                    body.started( true );
-
-                } else {
-                    // set the velocity and acceleration to zero!
-                    state.vel.zero();
-                    state.acc.zero();
-                    state.angular.vel = 0;
-                    state.angular.acc = 0;
-                }
-            }
-        },
-
-        // extended
-        integratePositions: function( bodies, dt ){
-
-            // half the timestep
-            var dtdt = dt * dt
-                ,body = null
-                ,state
-                ;
-
-            for ( var i = 0, l = bodies.length; i < l; ++i ){
-
-                body = bodies[ i ];
-                state = body.state;
-
-                // only integrate if the body isn't static
-                if ( body.treatment !== 'static' ){
-
-                    // x = x_prev + v_prev * dt + 0.5 * a_prev * dt * dt
-
-                    // Store old position.
-                    // xold = x
-                    state.old.pos.clone( state.pos );
-
-                    state.old.vel.mult( dt );
-                    state.old.acc.mult( 0.5 * dtdt );
-                    state.pos.vadd( state.old.vel ).vadd( state.old.acc );
-
-                    // store calculated velocity
-                    state.old.vel.clone( state.vel );
-
-                    // store old acc
-                    state.old.acc.clone( state.acc );
-
-                    // Reset accel
-                    state.acc.zero();
-
-                    //
-                    // Angular components
-                    //
-                    state.old.angular.pos = state.angular.pos;
-
-                    state.angular.pos += state.angular.vel * dt + 0.5 * state.old.angular.acc * dtdt;
-                    state.old.angular.vel = state.angular.vel;
-                    state.old.angular.acc = state.angular.acc;
-                    state.angular.acc = 0;
-                }
-            }
-        }
-    };
-});
-
-
-// ---
-// inside: src/integrators/velocity-verlet.js
-
-Physics.integrator('velocity-verlet', function( parent ){
-
-    // for this integrator we need to know if the object has been integrated before
-    // so let's add a mixin to bodies
-
-    Physics.body.mixin({
-
-        started: function( val ){
-            if ( val !== undefined ){
-                this._started = true;
-            }
-
-            return !!this._started;
-        }
-    });
-
-
-    return {
-        /**
-         * class VelocityVerlet < Integrator
-         *
-         * `Physics.integrator('velocity-verlet')`.
-         *
-         * The velocity-verlet integrator.
-         **/
-
-        // extended
-        init: function( options ){
-
-            // call parent init
-            parent.init.call(this, options);
-        },
-
-        /**
-         * Integrator#integrate( bodies, dt ) -> this
-         * - bodies (Array): List of bodies to integrate
-         * - dt (Number): Timestep size
-         *
-         * Integrate bodies by timestep.
-         *
-         * Will emit `integrate:velocities` and `integrate:positions`
-         * events on the world.
-         **/
-        integrate: function( bodies, dt ){
-
-            var world = this._world;
-
-            this.integratePositions( bodies, dt );
-
-            if ( world ){
-                world.emit('integrate:positions', {
-                    bodies: bodies,
-                    dt: dt
-                });
-            }
-
-            this.integrateVelocities( bodies, dt );
-
-            if ( world ){
-                world.emit('integrate:velocities', {
-                    bodies: bodies,
-                    dt: dt
-                });
-            }
-
-            return this;
-        },
-
-        // extended
-        integrateVelocities: function( bodies, dt ){
-
-            // half the timestep
-            var dtdt = dt * dt
-                ,drag = 1 - this.options.drag
-                ,body = null
-                ,state
-                ;
-
-            for ( var i = 0, l = bodies.length; i < l; ++i ){
-
-                body = bodies[ i ];
-                state = body.state;
-
-                // only integrate if the body isn't static
-                if ( body.treatment !== 'static' && !body.sleep() ){
-
-                    // v = v_prev + 0.5 * (a_prev + a) * dt
-                    // x = x_prev + v_prev * dt + 0.5 * a_prev * dt * dt
-
-                    // Apply "air resistance".
-                    if ( drag ){
-
-                        state.vel.mult( drag );
-                    }
-
-                    // Apply acceleration
-                    // v += 0.5 * (a_prev + a) * dt
-                    state.old.vel.clone( state.vel );
-                    state.vel.vadd( state.old.acc.vadd( state.acc ).mult( 0.5 * dt ) );
-
-                    // Reset accel
-                    state.old.acc.clone( state.acc );
-                    state.acc.zero();
-
-                    //
-                    // Angular components
-                    //
-
-                    state.old.angular.vel = state.angular.vel;
-                    state.old.angular.acc = state.angular.acc;
-
-                    state.angular.vel += 0.5 * (state.angular.acc + state.old.angular.acc) * dt;
-
-                    state.angular.acc = 0;
-
-                    body.started( true );
-
-                } else {
-                    // set the velocity and acceleration to zero!
-                    state.vel.zero();
-                    state.acc.zero();
-                    state.angular.vel = 0;
-                    state.angular.acc = 0;
-                }
-            }
-        },
-
-        // extended
-        integratePositions: function( bodies, dt ){
-
-            // half the timestep
-            var dtdt = dt * dt
-                ,body = null
-                ,state
-                ;
-
-            for ( var i = 0, l = bodies.length; i < l; ++i ){
-
-                body = bodies[ i ];
-                state = body.state;
-
-                // only integrate if the body isn't static
-                if ( body.treatment !== 'static' && !body.sleep( dt ) ){
-
-                    // x = x_prev + v_prev * dt + 0.5 * a_prev * dt * dt
-
-                    // use the velocity in vel if the velocity has been changed manually
-                    if ( !body.started() ){
-
-                        // Set old vals on first integration
-                        state.old.acc.clone( state.acc );
-                        state.old.acc.mult( dt );
-                        state.old.vel.clone( state.vel ).vsub( state.old.acc );
-                        state.old.acc.mult( 1/dt );
-                    }
-
-                    // Store old position.
-                    // xold = x
-                    state.old.pos.clone( state.pos );
-
-                    state.old.vel.mult( dt );
-                    state.old.acc.mult( 0.5 * dtdt );
-                    state.pos.vadd( state.old.vel ).vadd( state.old.acc );
-
-                    // revert
-                    state.old.vel.mult( 1/dt );
-                    state.old.acc.mult( 2 / dtdt );
-
-                    //
-                    // Angular components
-                    //
-
-                    if ( !body.started() ){
-
-                        // Set old vals on first integration
-                        state.old.angular.acc = state.angular.acc;
-                        state.old.angular.vel = state.angular.vel - state.old.angular.acc * dt;
-                    }
-
-                    state.old.angular.pos = state.angular.pos;
-
-                    state.angular.pos += state.angular.vel * dt + 0.5 * state.old.angular.acc * dtdt;
-                }
-            }
-        }
-    };
-});
-
-
-// ---
-// inside: src/renderers/canvas.js
-
-/**
- * class CanvasRenderer < Renderer
- *
- * Physics.renderer('canvas')
- *
- * Renderer that uses HTMLCanvas to render the world bodies.
- *
- * Additional config options:
- *
- * - metaEl: HTMLElement to write meta information like FPS and IPF into. (default: autogenerated)
- * - offset: Offset the shapes by this amount. (default: `{ x: 0, y: 0 }`)
- * - styles: Styles to use to draw the shapes. (see below)
- *
- * The styles property should contain _default_ styles for each shape you want to draw.
- *
- * Example:
- *
- * ```javascript
- * styles: {
- *
- *    'circle' : {
- *        strokeStyle: '#542437',
- *        lineWidth: 1,
- *        fillStyle: '#542437',
- *        angleIndicator: 'white'
- *    },
- *
- *    'convex-polygon' : {
- *        strokeStyle: '#542437',
- *        lineWidth: 1,
- *        fillStyle: '#542437',
- *        angleIndicator: 'white'
- *    }
- * }
- * ```
- *
- * Styles can also be defined on a per-body basis. Use the "styles" property for a body:
- *
- * Example:
- *
- * ```javascript
- * Physics.body('circle', {
- *     // ...
- *     styles: {
- *        strokeStyle: '#542437',
- *        lineWidth: 1,
- *        fillStyle: '#542437',
- *        angleIndicator: 'white'
- *    }
- * });
- * ```
- *
- * You can also define an image to use for a body:
- *
- * Example:
- *
- * ```javascript
- * Physics.body('circle', {
- *     // ...
- *     styles: {
- *        src: 'path/to/image.jpg',
- *        width: 40,
- *        height: 50
- *    }
- * });
- * ```
- **/
-Physics.renderer('canvas', function( proto ){
-
-    if ( !document ){
-        // must be in node environment
-        return {};
-    }
-
-    var Pi2 = Math.PI * 2
-        // helper to create new dom elements
-        ,newEl = function( node, content ){
-            var el = document.createElement(node || 'div');
-            if (content){
-                el.innerHTML = content;
-            }
-            return el;
-        }
-        ,colors = {
-            white: '#fff'
-            ,violet: '#542437'
-            ,blue: '#53777A'
-        }
-        ;
-
-    var defaults = {
-
-        // the element to place meta data into
-        metaEl: null,
-        // default styles of drawn objects
-        styles: {
-
-            'point': colors.blue,
-
-            'circle' : {
-                strokeStyle: colors.blue,
-                lineWidth: 1,
-                fillStyle: colors.blue,
-                angleIndicator: colors.white
-            },
-
-            'rectangle' : {
-                strokeStyle: colors.violet,
-                lineWidth: 1,
-                fillStyle: colors.violet,
-                angleIndicator: colors.white
-            },
-
-            'convex-polygon' : {
-                strokeStyle: colors.violet,
-                lineWidth: 1,
-                fillStyle: colors.violet,
-                angleIndicator: colors.white
-            }
-        },
-        offset: { x: 0, y: 0 }
-    };
-
-    return {
-
-        // extended
-        init: function( options ){
-
-            var self = this;
-
-            // call proto init
-            proto.init.call(this, options);
-
-            // further options
-            this.options.defaults( defaults, true );
-            this.options.onChange(function(){
-                self.options.offset = new Physics.vector( self.options.offset );
-            });
-            this.options( options, true );
-
-            // hidden canvas
-            this.hiddenCanvas = document.createElement('canvas');
-            this.hiddenCanvas.width = this.hiddenCanvas.height = 100;
-
-            if (!this.hiddenCanvas.getContext){
-                throw "Canvas not supported";
-            }
-
-            this.hiddenCtx = this.hiddenCanvas.getContext('2d');
-
-            // actual viewport
-            var viewport = this.el;
-            if (viewport.nodeName.toUpperCase() !== 'CANVAS'){
-
-                viewport = document.createElement('canvas');
-                this.el.appendChild( viewport );
-                if (typeof this.options.el === 'string' && this.el === document.body){
-                    viewport.id = this.options.el;
-                }
-                this.el = viewport;
-            }
-
-            this.container = this.el.parentNode;
-            this.ctx = viewport.getContext('2d');
-
-            this.els = {};
-
-            if (this.options.meta){
-                var stats = this.options.metaEl || newEl();
-                stats.className = 'pjs-meta';
-                this.els.fps = newEl('span');
-                this.els.ipf = newEl('span');
-                stats.appendChild(newEl('span', 'fps: '));
-                stats.appendChild(this.els.fps);
-                stats.appendChild(newEl('br'));
-                stats.appendChild(newEl('span', 'ipf: '));
-                stats.appendChild(this.els.ipf);
-
-                viewport.parentNode.insertBefore(stats, viewport);
-            }
-
-            this._layers = {};
-            this.addLayer( 'main', this.el );
-
-            if ( this.options.autoResize ){
-                this.resize();
-            } else {
-                this.resize( this.options.width, this.options.height );
-            }
-        },
-
-        /**
-         * CanvasRenderer#layer( id ) -> Layer
-         * - id (String): The id for the layer
-         *
-         * Get the layer by id.
-         **/
-        layer: function( id ){
-
-            if ( id in this._layers ){
-                return this._layers[ id ];
-            }
-
-            return null;
-        },
-
-        /**
-         * CanvasRenderer#addLayer( id[, el, opts ] ) -> Layer
-         * - id (String): The id for the layer
-         * - el (HTMLElement): The canvas element to use for this layer
-         * - opts (Object): The options for this layer (see below)
-         *
-         * Create a new layer.
-         *
-         * Layers can have the following options:
-         *
-         * - width: The width
-         * - height: The height
-         * - manual: Draw manually (default: `false`)
-         * - autoResize: Automatically resize the layer when the renderer's [[CanvasRenderer#resize]] method is called. (default: `true`)
-         * - follow: A [[Body]]. Offset this layer's rendering to follow a body's position. (default: `null`)
-         * - offset: The offset [[Vectorish]] for this layer. (default: `null`)
-         * - scale: Scale the layer by this amount. (default: `1`)
-         * - zIndex: The zIndex for the layer's HTMLElement. (default: `1`)
-         **/
-        addLayer: function( id, el, opts ){
-
-            /** belongs to: CanvasRenderer
-             * class Layer
-             *
-             * A rendering layer for the canvas renderer.
-             *
-             * Create by calling [[CanvasRenderer#addLayer]].
-             **/
-
-            var self = this
-                ,bodies = []
-                ,styles = Physics.util.extend({}, this.options.styles)
-                ,layer = {
-                    /**
-                     * Layer#id = String
-                     *
-                     * The layer's ID
-                     **/
-                    id: id
-                    /**
-                     * Layer#el = HTMLElement
-                     *
-                     * The layer's Canvas
-                     **/
-                    ,el: el || document.createElement('canvas')
-                    /** related to: Physics.util.options
-                      * Layer#options( options ) -> Object
-                      * - options (Object): The options to set as an object
-                      * + (Object): The options
-                      *
-                      * Set options on this layer.
-                      *
-                      * Access options directly from the options object.
-                      *
-                      * Example:
-                      *
-                      * ```javascript
-                      * this.options.someOption;
-                      * ```
-                      **/
-                    ,options: Physics.util.options({
-                        width: this.el.width
-                        ,height: this.el.height
-                        ,manual: false
-                        ,autoResize: true
-                        ,follow: null
-                        ,offset: null
-                        ,scale: 1
-                        ,zIndex: 1
-                    })( opts )
-                }
-                ;
-
-            if ( id in this._layers ){
-                throw 'Layer "' + id + '" already added.';
-            }
-
-            this.el.parentNode.insertBefore( layer.el, this.el );
-            layer.el.style.position = 'absolute';
-            layer.el.style.zIndex = layer.options.zIndex;
-            layer.el.className += ' pjs-layer-' + layer.id;
-            layer.ctx = layer.el.getContext('2d');
-            layer.ctx.scale( 1, 1 );
-            layer.el.width = layer.options.width;
-            layer.el.height = layer.options.height;
-
-            /**
-             * Layer#bodies = Array
-             *
-             * The Bodies this layer is rendering.
-             *
-             * The "main" layer will render all world bodies if it's empty.
-             **/
-            layer.bodies = bodies;
-
-            /**
-             * Layer#reset( [arr] ) -> this
-             * - arr (Array): Array to replace the current stack of Bodies.
-             *
-             * Reset the stack.
-             **/
-            layer.reset = function( arr ){
-
-                bodies = arr || [];
-                return layer;
-            };
-
-            /**
-             * Layer#addToStack( arr ) -> this
-             * Layer#addToStack( body ) -> this
-             * - body (Body): Body to add
-             * - arr (Array): Array of bodies to add
-             *
-             * Add body (bodies) to the rendering stack for this layer.
-             *
-             * Bodies must be added to the stack in order to be rendered by this layer UNLESS it is the "main" layer.
-             **/
-            layer.addToStack = function( thing ){
-
-                if ( Physics.util.isArray( thing ) ){
-                    bodies.push.apply( bodies, thing );
-                } else {
-                    bodies.push( thing );
-                }
-                return layer;
-            };
-
-            /**
-             * Layer#removeFromStack( arr ) -> this
-             * Layer#removeFromStack( body ) -> this
-             * - body (Body): Body to remove
-             * - arr (Array): Array of bodies to remove
-             *
-             * Remove body (bodies) from the rendering stack for this layer.
-             **/
-            layer.removeFromStack = function( thing ){
-
-                var i, l;
-
-                if ( Physics.util.isArray( thing ) ){
-                    for ( i = 0, l = thing.length; i < l; ++i ){
-                        layer.removeFromStack(thing[ i ]);
-                    }
-                } else {
-                    i = Physics.util.indexOf( bodies, thing );
-                    if ( i > -1 ){
-                        bodies.splice( i, 1 );
-                    }
-                }
-                return layer;
-            };
-
-            /**
-             * Layer#render( [clear] ) -> this
-             * - clear (Boolean): Clear the canvas (default: `true`)
-             *
-             * Render the bodies in this layer's stack.
-             *
-             * If you want you can replace this function with your own to do custom rendering.
-             *
-             * Example:
-             *
-             * ```javascript
-             * layer.render = myCustomRenderFn;
-             * ```
-             **/
-            layer.render = function( clear ){
-
-                var body
-                    ,scratch = Physics.scratchpad()
-                    ,offset = scratch.vector().set(0, 0)
-                    ,scale = layer.options.scale
-                    ,view
-                    ,i
-                    ,l = bodies.length
-                    ,t = self._interpolateTime
-                    ,stack = (l || layer.id !== 'main') ? bodies : self._world._bodies
-                    ;
-
-                if ( layer.options.manual ){
-                    scratch.done();
-                    return layer;
-                }
-
-                if ( layer.options.offset ){
-                    if ( layer.options.offset === 'center' ){
-                        offset.add( layer.el.width * 0.5, layer.el.height * 0.5 ).mult( 1/scale );
-                    } else {
-                        offset.vadd( layer.options.offset ).mult( 1/scale );
-                    }
-                }
-
-                if ( layer.options.follow ){
-                    offset.vsub( layer.options.follow.state.pos );
-                    offset.sub( layer.options.follow.state.vel.get(0)*t, layer.options.follow.state.vel.get(1)*t );
-                }
-
-                if ( clear !== false ){
-                    layer.ctx.clearRect(0, 0, layer.el.width, layer.el.height);
-                }
-
-                if ( scale !== 1 ){
-                    layer.ctx.save();
-                    layer.ctx.scale( scale, scale );
-                }
-
-                for ( i = 0, l = stack.length; i < l; ++i ){
-
-                    body = stack[ i ];
-                    if ( !body.hidden ){
-                        view = body.view || ( body.view = self.createView(body.geometry, body.styles || styles[ body.geometry.name ]) );
-                        self.drawBody( body, body.view, layer.ctx, offset );
-                    }
-                }
-
-                if ( scale !== 1 ){
-                    layer.ctx.restore();
-                }
-
-                scratch.done();
-                return layer;
-            };
-
-            // remember layer
-            this._layers[ id ] = layer;
-
-            return layer;
-        },
-
-        /**
-         * CanvasRenderer#removeLayer( id ) -> this
-         * CanvasRenderer#removeLayer( layer ) -> this
-         * - id (String): The id for the layer
-         * - layer (Layer): The layer
-         *
-         * Remove a layer.
-         **/
-        removeLayer: function( idOrLayer ){
-
-            var id = idOrLayer.id ? idOrLayer.id : idOrLayer
-                ,el = this._layers[ id ].el
-                ;
-
-            if ( el !== this.el ){
-                el.parentNode.removeChild( el );
-            }
-            delete this._layers[ id ];
-            return this;
-        },
-
-        /**
-         * CanvasRenderer#resize( width, height ) -> this
-         * - width (Number): The width
-         * - height (Number): The height
-         *
-         * Resize all layer canvases that have the `autoResize` option set to `true`.
-         **/
-        resize: function( width, height ){
-
-            var layer;
-            proto.resize.call( this, width, height );
-
-            for ( var id in this._layers ){
-
-                layer = this._layers[ id ];
-                if ( layer.options.autoResize ){
-                    layer.el.width = this.width;
-                    layer.el.height = this.height;
-                }
-            }
-
-            return this;
-        },
-
-        /**
-         * CanvasRenderer#setStyle( styles[, ctx] )
-         * - styles (Object|String): Styles to set on the canvas context
-         * - ctx (Canvas2DContext): The canvas context
-         *
-         * Set styles on the specified canvas context (or main context).
-         **/
-        setStyle: function( styles, ctx ){
-
-            ctx = ctx || this.ctx;
-
-            if ( Physics.util.isObject(styles) ){
-
-                styles.strokeStyle = styles.lineWidth ? styles.strokeStyle : 'rgba(0,0,0,0)';
-                Physics.util.extend(ctx, styles);
-
-            } else {
-
-                ctx.fillStyle = ctx.strokeStyle = styles;
-                ctx.lineWidth = 1;
-            }
-        },
-
-        /**
-         * CanvasRenderer#drawCircle( x, y, r, styles[, ctx] )
-         * - x (Number): The x coord
-         * - y (Number): The y coord
-         * - r (Number): The circle radius
-         * - styles (Object): The styles configuration
-         * - ctx (Canvas2DContext): The canvas context
-         *
-         * Draw a circle to specified canvas context.
-         **/
-        drawCircle: function(x, y, r, styles, ctx){
-
-            ctx = ctx || this.ctx;
-
-            ctx.beginPath();
-            this.setStyle( styles, ctx );
-            ctx.arc(x, y, r, 0, Pi2, false);
-            ctx.closePath();
-            ctx.stroke();
-            ctx.fill();
-        },
-
-        /**
-         * CanvasRenderer#drawPolygon( verts, styles[, ctx] )
-         * - verts (Array): Array of [[Vectorish]] vertices
-         * - styles (Object): The styles configuration
-         * - ctx (Canvas2DContext): The canvas context
-         *
-         * Draw a polygon to specified canvas context.
-         **/
-        drawPolygon: function(verts, styles, ctx){
-
-            var vert = verts[0]
-                ,x = vert.x
-                ,y = vert.y
-                ,l = verts.length
-                ;
-
-            ctx = ctx || this.ctx;
-            ctx.beginPath();
-            this.setStyle( styles, ctx );
-
-            ctx.moveTo(x, y);
-
-            for ( var i = 1; i < l; ++i ){
-
-                vert = verts[ i ];
-                x = vert.x;
-                y = vert.y;
-                ctx.lineTo(x, y);
-            }
-
-            if ( l > 2 ){
-                ctx.closePath();
-            }
-
-            ctx.stroke();
-            ctx.fill();
-        },
-
-        /**
-         * CanvasRenderer#drawRect( x, y, width, height, styles[, ctx] )
-         * - x (Number): The x coord
-         * - y (Number): The y coord
-         * - width (Number): The width
-         * - height (Number): The height
-         * - styles (Object): The styles configuration
-         * - ctx (Canvas2DContext): The canvas context
-         *
-         * Draw a rectangle to specified canvas context.
-         **/
-        drawRect: function(x, y, width, height, styles, ctx){
-
-            var hw = width * 0.5
-                ,hh = height * 0.5
-                ;
-
-            ctx = ctx || this.ctx;
-            this.setStyle( styles, ctx );
-            ctx.beginPath();
-            ctx.rect(x - hw, y - hh, width, height);
-            ctx.closePath();
-            ctx.stroke();
-            ctx.fill();
-        },
-
-        /**
-         * CanvasRenderer#drawLine( from, to, styles[, ctx] )
-         * - from (Vectorish): The starting pt
-         * - to (Vectorish): The ending pt
-         * - styles (Object): The styles configuration
-         * - ctx (Canvas2DContext): The canvas context
-         *
-         * Draw a line onto specified canvas context.
-         **/
-        drawLine: function(from, to, styles, ctx){
-
-            var x = from.x
-                ,y = from.y
-                ;
-
-            ctx = ctx || this.ctx;
-
-            ctx.beginPath();
-            this.setStyle( styles, ctx );
-
-            ctx.moveTo(x, y);
-
-            x = to.x;
-            y = to.y;
-
-            ctx.lineTo(x, y);
-
-            ctx.stroke();
-            ctx.fill();
-        },
-
-        /**
-         * CanvasRenderer#draw( geometry[, styles, ctx, offset] ) -> this
-         * - geometry (Geometry): The shape to draw
-         * - styles (Object): The styles configuration
-         * - ctx (Canvas2DContext): The canvas context
-         * - offset (Vectorish): The offset from center
-         *
-         * Draw a geometry to a context.
-         **/
-        draw: function( geometry, styles, ctx, offset ){
-
-            var name = geometry.name
-                ,x = +(offset && offset.x)
-                ,y = +(offset && offset.y)
-                ,w = geometry.aabb().hw
-                ;
-
-            ctx = ctx || this.ctx;
-            styles = styles || this.options.styles[ name ] || this.options.styles.circle || {};
-
-            ctx.save();
-            ctx.translate(x, y);
-
-            if (name === 'circle'){
-
-                this.drawCircle(0, 0, geometry.radius, styles, ctx);
-
-            } else if (name === 'convex-polygon'){
-
-                this.drawPolygon(geometry.vertices, styles, ctx);
-
-            } else if (name === 'rectangle'){
-
-                this.drawRect(0, 0, geometry.width, geometry.height, styles, ctx);
-
-            } else if (name === 'compound'){
-
-                for ( var i = 0, l = geometry.children.length, ch; i < l; i++ ){
-                    ch = geometry.children[ i ];
-
-                    // translate
-                    ctx.translate(ch.pos.x, ch.pos.y);
-                    // rotate
-                    ctx.rotate(ch.angle);
-
-                    this.draw( ch.g, styles, ctx );
-
-                    // unrotate
-                    ctx.rotate(-ch.angle);
-                    // untranslate
-                    ctx.translate(-ch.pos.x, -ch.pos.y);
-                }
-
-            } else {
-
-                // assume it's a point
-                this.drawCircle(0, 0, 1, styles, ctx);
-            }
-
-            if (name !== 'compound' && styles.angleIndicator){
-
-                ctx.beginPath();
-                this.setStyle( styles.angleIndicator, ctx );
-                ctx.moveTo(0, 0);
-                ctx.lineTo(w, 0);
-                ctx.closePath();
-                ctx.stroke();
-            }
-
-            ctx.restore();
-
-            return this;
-        },
-
-        // extended
-        createView: function( geometry, styles ){
-
-            var view
-                ,aabb = geometry.aabb()
-                ,hw = aabb.hw + Math.abs(aabb.x)
-                ,hh = aabb.hh + Math.abs(aabb.y)
-                ,offset = { x: hw + 1, y: hh + 1 }
-                ,hiddenCtx = this.hiddenCtx
-                ,hiddenCanvas = this.hiddenCanvas
-                ;
-
-            styles = styles || this.options.styles[ name ] || this.options.styles.circle || {};
-
-            // must want an image
-            if ( styles.src ){
-                view = new Image();
-                view.src = styles.src;
-                if ( styles.width ){
-                    view.width = styles.width;
-                }
-                if ( styles.height ){
-                    view.height = styles.height;
-                }
-                return view;
-            }
-
-            offset.x += styles.lineWidth | 0;
-            offset.y += styles.lineWidth | 0;
-
-            // clear and resize
-            hiddenCanvas.width = 2 * hw + 2 + (2 * styles.lineWidth|0);
-            hiddenCanvas.height = 2 * hh + 2 + (2 * styles.lineWidth|0);
-
-            this.draw( geometry, styles, hiddenCtx, offset );
-
-            view = new Image( hiddenCanvas.width, hiddenCanvas.height );
-            view.src = hiddenCanvas.toDataURL('image/png');
-            return view;
-        },
-
-        // extended
-        drawMeta: function( meta ){
-
-            this.els.fps.innerHTML = meta.fps.toFixed(2);
-            this.els.ipf.innerHTML = meta.ipf;
-        },
-
-        // extended
-        drawBody: function( body, view, ctx, offset ){
-
-            var pos = body.state.pos
-                ,os = body.offset
-                ,v = body.state.vel
-                ,t = this._interpolateTime || 0
-                ,x
-                ,y
-                ,ang
-                ,aabb
-                ;
-
-            offset = offset || this.options.offset;
-            ctx = ctx || this.ctx;
-
-            // interpolate positions
-            x = pos._[0] + offset.x + v._[0] * t;
-            y = pos._[1] + offset.y + v._[1] * t;
-            ang = body.state.angular.pos + body.state.angular.vel * t;
-
-            ctx.save();
-            ctx.translate( x, y );
-            ctx.rotate( ang );
-            ctx.translate( os._[0], os._[1] );
-            ctx.drawImage(view, -view.width/2, -view.height/2, view.width, view.height);
-            ctx.restore();
-        },
-
-        // extended
-        render: function( bodies, meta ){
-
-            var body
-                ,view
-                ,pos
-                ;
-
-            this._world.emit('beforeRender', {
-                renderer: this,
-                meta: meta
-            });
-
-            if ( this.options.meta ) {
-                this.drawMeta( meta );
-            }
-
-            this._interpolateTime = meta.interpolateTime;
-
-            for ( var id in this._layers ){
-
-                this._layers[ id ].render();
-            }
-
-            return this;
-        }
-    };
-});
-
-
-// ---
-// inside: src/renderers/dom.js
-
-/**
- * class DomRenderer < Renderer
- *
- * Physics.renderer('dom')
- *
- * Renderer that manipulates DOM elements according to the physics simulation. Very primative...
- **/
-Physics.renderer('dom', function( proto ){
-
-    if ( !document ){
-        // must be in node environment
-        return {};
-    }
-
-    // utility methods
-    var thePrefix = {}
-        ,tmpdiv = document.createElement("div")
-        ,toTitleCase = function toTitleCase(str) {
-            return str.replace(/(?:^|\s)\w/g, function(match) {
-                return match.toUpperCase();
-            });
-        }
-        // return the prefixed name for the specified css property
-        ,pfx = function pfx(prop) {
-
-            if (thePrefix[prop]){
-                return thePrefix[prop];
-            }
-
-            var arrayOfPrefixes = ['Webkit', 'Moz', 'Ms', 'O']
-                ,name
-                ;
-
-            for (var i = 0, l = arrayOfPrefixes.length; i < l; ++i) {
-
-                name = arrayOfPrefixes[i] + toTitleCase(prop);
-
-                if (name in tmpdiv.style){
-                    return thePrefix[prop] = name;
-                }
-            }
-
-            if (name in tmpdiv.style){
-                return thePrefix[prop] = prop;
-            }
-
-            return false;
-        }
-        ;
-
-    var classpfx = 'pjs-'
-        ,px = 'px'
-        ,cssTransform = pfx('transform')
-        ,borderRadius = pfx('borderRadius')
-        ;
-
-    var newEl = function( node, content ){
-            var el = document.createElement(node || 'div');
-            if (content){
-                el.innerHTML = content;
-            }
-            return el;
-        }
-        ,drawBody
-        ;
-
-    return {
-
-        // extended
-        init: function( options ){
-
-            // call proto init
-            proto.init.call(this, options);
-
-            var viewport = this.el;
-            viewport.style.position = 'relative';
-            viewport.style.overflow = 'hidden';
-            viewport.style[cssTransform] = 'translateZ(0)'; // force GPU accel
-            viewport.style.width = this.options.width + px;
-            viewport.style.height = this.options.height + px;
-
-            this.els = {};
-
-            if (options.meta){
-                var stats = newEl();
-                stats.className = 'pjs-meta';
-                this.els.fps = newEl('span');
-                this.els.ipf = newEl('span');
-                stats.appendChild(newEl('span', 'fps: '));
-                stats.appendChild(this.els.fps);
-                stats.appendChild(newEl('br'));
-                stats.appendChild(newEl('span', 'ipf: '));
-                stats.appendChild(this.els.ipf);
-
-                viewport.appendChild(stats);
-            }
-
-            if ( this.options.autoResize ){
-                this.resize();
-            } else {
-                this.resize( this.options.width, this.options.height );
-            }
-        },
-
-        // extended
-        resize: function( width, height ){
-
-            proto.resize.call( this, width, height );
-            this.el.style.width = this.width + px;
-            this.el.style.height = this.height + px;
-        },
-
-        /** internal
-         * DomRenderer#pointProperties( el, geometry )
-         * - el (HTMLElement): The element
-         * - geometry (Geometry): The body's geometry
-         *
-         * Set dom element style properties for a point.
-         **/
-        pointProperties: function( el, geometry ){
-
-            el.style.width = '2px';
-            el.style.height = '2px';
-            el.style.marginLeft = '-1px';
-            el.style.marginTop = '-1px';
-            el.style[ borderRadius ] = '50%';
-        },
-
-        /** internal
-         * DomRenderer#circleProperties( el, geometry )
-         * - el (HTMLElement): The element
-         * - geometry (Geometry): The body's geometry
-         *
-         * Set dom element style properties for a circle.
-         **/
-        circleProperties: function( el, geometry ){
-
-            var aabb = geometry.aabb();
-
-            el.style.width = (aabb.hw * 2) + px;
-            el.style.height = (aabb.hh * 2) + px;
-            el.style.marginLeft = (-aabb.hw) + px;
-            el.style.marginTop = (-aabb.hh) + px;
-            el.style[ borderRadius ] = '50%';
-        },
-
-        /** internal
-         * DomRenderer#rectangleProperties( el, geometry )
-         * - el (HTMLElement): The element
-         * - geometry (Geometry): The body's geometry
-         *
-         * Set dom element style properties for a rectangle.
-         **/
-        rectangleProperties: function( el, geometry ){
-
-            var aabb = geometry.aabb();
-
-            el.style.width = (aabb.hw * 2) + px;
-            el.style.height = (aabb.hh * 2) + px;
-            el.style.marginLeft = (-aabb.hw) + px;
-            el.style.marginTop = (-aabb.hh) + px;
-        },
-
-        // extended
-        createView: function( geometry ){
-
-            var el = newEl()
-                ,chel
-                ,fn = geometry.name + 'Properties'
-                ;
-
-            el.className = classpfx + geometry.name;
-            el.style.position = 'absolute';
-            el.style.top = '0px';
-            el.style.left = '0px';
-
-            if ( geometry.name === 'compound' ){
-
-                for ( var i = 0, l = geometry.children.length, ch; i < l; i++ ){
-                    ch = geometry.children[ i ];
-                    chel = newEl();
-                    chel.className = classpfx + geometry.name + ' ' + classpfx + 'child';
-                    chel.style.position = 'absolute';
-                    chel.style.top = '0px';
-                    chel.style.left = '0px';
-                    if ( this[ ch.g.name + 'Properties' ] ){
-                        this[ ch.g.name + 'Properties' ](chel, ch.g);
-                    }
-                    chel.style[cssTransform] = 'translate('+ch.pos._[0]+'px,'+ch.pos._[1]+'px) rotate('+ ch.angle +'rad)';
-                    el.appendChild( chel );
-                }
-
-            } else if ( this[ fn ] ){
-                this[ fn ](el, geometry);
-            }
-
-            this.el.appendChild( el );
-            return el;
-        },
-
-        // extended
-        connect: function( world ){
-
-            world.on( 'add:body', this.attach, this );
-            world.on( 'remove:body', this.detach, this );
-        },
-
-        // extended
-        disconnect: function( world ){
-
-            world.off( 'add:body', this.attach, this );
-            world.off( 'remove:body', this.detach, this );
-        },
-
-        /**
-         * DomRenderer#detach( data ) -> this
-         * - data (HTMLElement|Object): DOM node or event data (`data.body`)
-         *
-         * Event callback to detach a node from the DOM
-         **/
-        detach: function( data ){
-
-            // interpred data as either dom node or event data
-            var el = (data.nodeType && data) || (data.body && data.body.view)
-                ,par = el && el.parentNode
-                ;
-
-            if ( el && par ){
-                // remove view from dom
-                par.removeChild( el );
-            }
-
-            return this;
-        },
-
-        /**
-         * DomRenderer#attach( data ) -> this
-         * - data (HTMLElement|Object): DOM node or event data (`data.body`)
-         *
-         * Event callback to attach a node to the viewport
-         **/
-        attach: function( data ){
-
-            // interpred data as either dom node or event data
-            var el = (data.nodeType && data) || (data.body && data.body.view)
-                ;
-
-            if ( el ){
-                // attach to viewport
-                this.el.appendChild( el );
-            }
-
-            return this;
-        },
-
-        // extended
-        drawMeta: function( meta ){
-
-            this.els.fps.innerHTML = meta.fps.toFixed(2);
-            this.els.ipf.innerHTML = meta.ipf;
-        },
-
-        // extended
-        drawBody: function( body, view ){
-
-            var pos = body.state.pos
-                ,v = body.state.vel
-                ,os = body.offset
-                ,x
-                ,y
-                ,ang
-                ,t = this._interpolateTime
-                ;
-
-            // interpolate positions
-            x = pos._[0] + v._[0] * t;
-            y = pos._[1] + v._[1] * t;
-            ang = body.state.angular.pos + body.state.angular.vel * t;
-            view.style[cssTransform] = 'translate('+x+'px,'+y+'px) rotate('+ ang +'rad) translate('+os._[0]+'px,'+os._[1]+'px)';
-        }
-    };
-});
-
-
-// ---
-// inside: src/renderers/pixi-renderer.js
-
-/*
- * @requires pixi.js
- */
-/**
- * class PixiRenderer < Renderer
- *
- * Physics.renderer('pixi')
- *
- * Renderer that uses the PIXI.js library. [Documentation can be found here](https://github.com/wellcaffeinated/PhysicsJS/wiki/PIXI-Renderer).
- *
- * Additional config options:
- *
- * - metaEl: HTMLElement to write meta information like FPS and IPF into. (default: autogenerated)
- * - offset: Offset the shapes by this amount. (default: `{ x: 0, y: 0 }`)
- * - styles: Styles to use to draw the shapes. (see below)
- *
- * The styles property should contain _default_ styles for each shape you want to draw.
- *
- * Example:
- *
- * ```javascript
- * styles: {
- *    // Defines the default canvas colour
- *    'color': '0x66FF99',
- *
- *    'circle' : {
- *        strokeStyle: '0xE8900C',
- *        lineWidth: 3,
- *        fillStyle: '0xD5DE4C',
- *        angleIndicator: '0xE8900C',
- *        strokeAlpha: 1,
- *        fillAlpha: 1
- *    },
- *
- *    'convex-polygon' : {
- *        strokeStyle: '0xE8900C',
- *        lineWidth: 3,
- *        fillStyle: '0xD5DE4C',
- *        angleIndicator: '0xE8900C'
- *    }
- * }
- * ```
- *
- * Styles can also be defined on a per-body basis. Use the "styles" property for a body:
- *
- * Example:
- *
- * ```javascript
- * Physics.body('circle', {
- *     // ...
- *     styles: {
- *        strokeStyle: '0x542437',
- *        lineWidth: 1,
- *        fillStyle: '0x542437',
- *        angleIndicator: '0xFFFFFF'
- *    }
- * });
- * ```
- *
- * You can also define an image to use for a body:
- *
- * Example:
- *
- * ```javascript
- * Physics.body('circle', {
- *     // ...
- *     styles: {
- *        src: 'path/to/image.jpg',
- *        width: 40,
- *        height: 50,
- *        anchor: { x: 0.5, y: 0.5 }
- *    }
- * });
- * ```
- **/
-/* global PIXI */
-Physics.renderer('pixi', function( parent ){
-
-    if ( !document ){
-        // must be in node environment
-        return {};
-    }
-
-    var Pi2 = Math.PI * 2
-        ,colors = {
-            white: '0xFFFFFF'
-            ,violet: '0x542437'
-            ,blue: '0x53777A'
-        }
-        ,fontStyles = {
-            font: "18px monospace",
-            fill: "black",
-            align: "left"
-        }
-
-        ,defaults = {
-
-            // the element to place meta data into
-            metaEl: null,
-            offset: { x: 0, y: 0 },
-            // Provide some default colours
-            styles: {
-                // Defines the default canvas colour
-                'color': false,
-
-                'point': colors.blue,
-
-                'circle' : {
-                    strokeStyle: colors.blue,
-                    lineWidth: 1,
-                    fillStyle: colors.blue,
-                    angleIndicator: colors.white,
-                    fillAlpha: 1,
-                    strokeAlpha: 1,
-                    alpha: 1
-                },
-
-                'rectangle' : {
-                    strokeStyle: colors.violet,
-                    lineWidth: 1,
-                    fillStyle: colors.violet,
-                    angleIndicator: colors.white,
-                    fillAlpha: 1,
-                    strokeAlpha: 1,
-                    alpha: 1
-                },
-
-                'convex-polygon' : {
-                    strokeStyle: colors.violet,
-                    lineWidth: 1,
-                    fillStyle: colors.violet,
-                    angleIndicator: colors.white,
-                    fillAlpha: 1,
-                    strokeAlpha: 1,
-                    alpha: 1
-                }
-            }
-        }
-        ;
-
-    return {
-
-        // extended
-        init: function( options ){
-
-            var self = this
-                ,el
-                ,isTransparent
-                ;
-
-            if (typeof PIXI === 'undefined') {
-                throw "PIXI not present - cannot continue";
-            }
-
-            // call parent init
-            parent.init.call(this, options);
-
-            // further options
-            this.options.defaults( defaults, true );
-            this.options.onChange(function(){
-                self.options.offset = new Physics.vector( self.options.offset );
-            });
-            this.options( options, true );
-
-            isTransparent = (!this.options.styles.color || this.options.styles.color === 'transparent');
-            // Hook in PIXI stage here
-            this.stage = new PIXI.Stage(this.options.styles.color);
-
-            // Create empty meta object for use later
-            this.meta = {};
-
-            el = (this.el && this.el.nodeName === 'CANVAS') ? el : null;
-            // add the renderer view element to the DOM according to its type
-            this.renderer = new PIXI.autoDetectRenderer(this.options.width, this.options.height, {
-                view: el,
-                transparent: isTransparent,
-                resolution: window.devicePixelRatio || 1
-            });
-
-            if ( !el ){
-                this.el = this.el || document.body;
-                // add to passed in element
-                this.el.appendChild( this.renderer.view );
-            }
-
-            if ( this.options.autoResize ){
-                this.resize();
-            } else {
-                this.resize( this.options.width, this.options.height );
-            }
-        },
-
-        // extended
-        resize: function( width, height ){
-
-            parent.resize.call( this, width, height );
-            this.renderer.resize( this.width, this.height );
-        },
-
-        // extended
-        connect: function( world ){
-
-            world.on( 'add:body', this.attach, this );
-            world.on( 'remove:body', this.detach, this );
-        },
-
-        // extended
-        disconnect: function( world ){
-
-            world.off( 'add:body', this.attach, this );
-            world.off( 'remove:body', this.detach, this );
-        },
-
-        /**
-         * PixiRenderer#detach( data ) -> this
-         * - data (PIXI.Graphics|Object): Graphics object or event data (`data.body`)
-         *
-         * Event callback to detach a child from the stage
-         **/
-        detach: function( data ){
-
-            // interpred data as either dom node or event data
-            var el = (data instanceof PIXI.Graphics && data) || (data.body && data.body.view);
-
-            if ( el ){
-                // remove view from dom
-                this.stage.removeChild( el );
-            }
-
-            return this;
-        },
-
-        /**
-         * PixiRenderer#attach( data ) -> this
-         * - data (PIXI.Graphics|Object): Graphics object or event data (`data.body`)
-         *
-         * Event callback to attach a child to the stage
-         **/
-        attach: function( data ){
-
-            // interpred data as either dom node or event data
-            var el = (data instanceof PIXI.Graphics && data) || (data.body && data.body.view);
-
-            if ( el ){
-                // attach to viewport
-                this.stage.addChild( el );
-            }
-
-            return this;
-        },
-
-        /**
-         * PixiRenderer#loadSpriteSheets( assetsToLoad, callback ) -> this
-         * - assetsToLoad (Array): Array of spritesheets to load
-         * - callback (Function): Function to call when loading is complete
-         *
-         * Loads textures defined in a spritesheet
-         **/
-        loadSpriteSheets: function( assetsToLoad, callback ){
-
-            if ( !Physics.util.isArray( assetsToLoad ) ) {
-                throw 'Spritesheets must be defined in arrays';
-            }
-
-            var self = this
-                ,loader = new PIXI.AssetLoader(assetsToLoad)
-                ;
-
-            // Start loading resources!
-            loader.load();
-
-            loader.on('onComplete', function(evt){
-                self.assetsLoaded = true;
-                callback();
-            });
-
-            return self;
-        },
-
-        /**
-         * PixiRenderer#drawBody( body, view )
-         * - body (Body): The body to draw
-         * - view (DisplayObject): The pixi display object
-         *
-         * Draw a PIXI.DisplayObject to the stage.
-         **/
-        drawBody: function( body, view ){
-            var pos = body.state.pos
-                ,v = body.state.vel
-                ,os = body.offset
-                ,t = this._interpolateTime || 0
-                ,x
-                ,y
-                ,ang
-                ;
-
-            // interpolate positions
-            x = pos._[0] + v._[0] * t;
-            y = pos._[1] + v._[1] * t;
-            ang = body.state.angular.pos + body.state.angular.vel * t;
-
-            view.position.set( x, y );
-            view.pivot.set( -os._[0], -os._[1] );
-            view.rotation = ang;
-        },
-
-        // extended
-        render: function( bodies, meta ){
-
-            parent.render.call(this, bodies, meta);
-            this.renderer.render(this.stage);
-        },
-
-        /**
-         * PixiRenderer#setStyles( graphics, styles ) -> PIXI.Graphics
-         * - graphics (PIXI.Graphics): The graphics object to set styles on
-         * - styles (Object): The styles configuration
-         * + (PIXI.Graphics): A graphic object
-         *
-         * Set styles on pixi graphics object
-         **/
-        setStyles: function( graphics, styles ){
-
-            if ( Physics.util.isObject(styles) ){
-
-                if ( styles.fillStyle && styles.fillStyle !== 'transparent' ){
-                    graphics.beginFill( styles.fillStyle );
-                    graphics.fillAlpha = styles.fillAlpha !== undefined ? styles.fillAlpha : 1;
-                } else {
-                    graphics.beginFill();
-                    graphics.fillAlpha = 0;
-                }
-
-                graphics.lineStyle( styles.lineWidth || 0, styles.strokeStyle, styles.strokeAlpha !== undefined ? styles.strokeAlpha : 1 );
-                graphics.alpha = styles.alpha !== undefined ? styles.alpha : 1;
-
-            } else {
-
-                if ( styles && styles !== 'transparent' ){
-                    graphics.beginFill( styles );
-                } else {
-                    graphics.beginFill();
-                    graphics.fillAlpha = 0;
-                }
-
-                graphics.lineStyle( 0 );
-            }
-
-            return graphics;
-        },
-
-        /**
-         * PixiRenderer#createCircle( x, y, r, styles ) -> PIXI.Graphics
-         * - x (Number): The x coord
-         * - y (Number): The y coord
-         * - r (Number): The circle radius
-         * - styles (Object): The styles configuration
-         * + (PIXI.Graphics): A graphic object representing a circle.
-         *
-         * Create a circle for use in PIXI stage
-         **/
-        createCircle: function( x, y, r, styles ){
-
-            var graphics = new PIXI.Graphics();
-            this.setStyles( graphics, styles );
-            graphics.drawCircle( x, y, r );
-            graphics.endFill();
-            return graphics;
-        },
-
-        /**
-         * PixiRenderer#createRect( x, y, r, styles ) -> PIXI.Graphics
-         * - x (Number): The x coord
-         * - y (Number): The y coord
-         * - width (Number): The rectangle width
-         * - height (Number): The rectangle height
-         * - styles (Object): The styles configuration
-         * + (PIXI.Graphics): A graphic object representing a circle.
-         *
-         * Create a rectangle for use in PIXI stage
-         **/
-        createRect: function( x, y, width, height, styles ){
-
-            var graphics = new PIXI.Graphics();
-            this.setStyles( graphics, styles );
-            graphics.drawRect( x, y, width, height );
-            graphics.endFill();
-            return graphics;
-        },
-
-        /**
-         * PixiRenderer#createPolygon( verts, styles ) -> PIXI.Graphics
-         * - verts (Array): Array of [[Vectorish]] vertices
-         * - styles (Object): The styles configuration
-         * + (PIXI.Graphics): A graphic object representing a polygon.
-         *
-         * Create a polygon for use in PIXI stage
-         **/
-        createPolygon: function( verts, styles ){
-
-            var vert = verts[0]
-                ,x = vert.x
-                ,y = vert.y
-                ,l = verts.length
-                ,start = {
-                    x: x
-                    ,y: y
-                }
-                ,graphics = new PIXI.Graphics()
-                ;
-
-            this.setStyles( graphics, styles );
-
-            graphics.moveTo(x, y);
-
-            for ( var i = 1; i < l; ++i ){
-
-                vert = verts[ i ];
-                x = vert.x;
-                y = vert.y;
-                graphics.lineTo(x, y);
-            }
-
-            if (l > 2){
-                graphics.lineTo(start.x, start.y);
-            }
-
-            graphics.endFill();
-            return graphics;
-        },
-
-        /**
-         * PixiRenderer#createLine( from, to, styles ) -> PIXI.Graphics
-         * - from (Vectorish): Starting point
-         * - to (Vectorish): Ending point
-         * - styles (Object): The styles configuration
-         * + (PIXI.Graphics): A graphic object representing a polygon.
-         *
-         * Create a line for use in PIXI stage
-         **/
-        createLine: function( from, to, styles ){
-
-            var x = from.x
-                ,y = from.y
-                ;
-
-            var graphics = new PIXI.Graphics();
-            this.setStyles( graphics, styles );
-
-            graphics.moveTo(x, y);
-
-            x = to.x;
-            y = to.y;
-
-            graphics.lineTo(x, y);
-
-            graphics.endFill();
-            return graphics;
-        },
-
-        // extended
-        createView: function( geometry, styles, parent ){
-
-            var view = null
-                ,aabb = geometry.aabb()
-                ,hw = aabb.hw + Math.abs(aabb.x)
-                ,hh = aabb.hh + Math.abs(aabb.y)
-                ,name = geometry.name
-                ;
-
-            parent = parent || this.stage;
-            styles = styles || this.options.styles[ name ] || this.options.styles.circle || {};
-
-            // must want an image
-            if ( styles.src ){
-                view = PIXI.Sprite.fromImage( styles.src );
-                view.anchor.set( 0.5, 0.5 );
-                if ( styles.anchor ) {
-                    view.anchor.x = styles.anchor.x;
-                    view.anchor.y = styles.anchor.y;
-                }
-                if ( styles.width ){
-                    view.width = styles.width;
-                }
-                if ( styles.height ){
-                    view.height = styles.height;
-                }
-                parent.addChild(view);
-                return view;
-            }
-
-            if (name === 'circle'){
-
-                view = this.createCircle(0, 0, geometry.radius, styles);
-
-            } else if (name === 'convex-polygon'){
-
-                view = this.createPolygon(geometry.vertices, styles);
-
-            } else if (name === 'rectangle'){
-
-                view = this.createRect(-geometry.width/2, -geometry.height/2, geometry.width, geometry.height, styles);
-            } else if (name === 'compound'){
-
-                view = new PIXI.Graphics();
-
-                for ( var i = 0, l = geometry.children.length, ch, chview; i < l; i++ ){
-                    ch = geometry.children[ i ];
-                    chview = this.createView( ch.g, styles, view );
-                    chview.position.set( ch.pos.x, ch.pos.y );
-                    chview.rotation = ch.angle;
-                }
-            } else {
-
-                // assume it's a point
-                view = this.createCircle(0, 0, 1, styles);
-            }
-
-            if ( name !== 'compound' && styles.angleIndicator && styles.angleIndicator !== 'transparent' ){
-
-                view.lineStyle( styles.lineWidth, styles.angleIndicator );
-                view.moveTo( 0, 0 );
-                view.lineTo( hw, 0 );
-            }
-
-            if ( name !== 'compound' ){
-                view.cacheAsBitmap = true;
-            }
-
-            parent.addChild(view);
-            return view;
-        },
-
-        // extended
-        drawMeta: function( meta ){
-            if (!this.meta.loaded){
-                // define the font styles here
-                this.meta.fps = new PIXI.Text('FPS: ' + meta.fps.toFixed(2), fontStyles);
-                this.meta.fps.position.x = 15;
-                this.meta.fps.position.y = 5;
-
-                this.meta.ipf = new PIXI.Text('IPF: ' + meta.ipf, fontStyles);
-                this.meta.ipf.position.x = 15;
-                this.meta.ipf.position.y = 30;
-
-                this.stage.addChild(this.meta.fps);
-                this.stage.addChild(this.meta.ipf);
-                this.meta.loaded = true;
-            } else {
-                this.meta.fps.setText('FPS: ' + meta.fps.toFixed(2));
-                this.meta.ipf.setText('IPF: ' + meta.ipf);
-            }
-        },
-
-        /**
-         * PixiRenderer#createDisplay( type, options ) -> PIXI.DisplayObject
-         * - type (String): The type of PIXI.DisplayObject to make
-         * - options (Object): Options to apply to the view.
-         * + (PIXI.DisplayObject): An object that is renderable.
-         *
-         * Create a PIXI sprite or movie clip.
-         **/
-        createDisplay: function( type, options ){
-            var view = null
-                ,texture = null
-                ;
-            switch (type){
-                // Create a sprite object
-                case 'sprite':
-                    texture = PIXI.Texture.fromImage(options.texture);
-                    view = new PIXI.Sprite(texture);
-                    if (options.anchor ) {
-                        view.anchor.x = options.anchor.x;
-                        view.anchor.y = options.anchor.y;
-                    }
-                    // If a container is specified, use add to that container
-                    if (options.container) {
-                        options.container.addChild(view);
-                    } else {
-                        // Otherwise just add the view to the stage
-                        this.stage.addChild(view);
-                    }
-                    return view;
-                // Create a movieclip object
-                case 'movieclip':
-                    if (!this.assetsLoaded) {
-                        throw "No assets have been loaded. Use loadSpritesheet() first";
-                    }
-                    var tex = []
-                        ,i = 0
-                        ;
-                    // Populate our movieclip
-                    for (i; i < options.frames.length; i++) {
-                        texture = PIXI.Texture.fromFrame(options.frames[i]);
-                        tex.push(texture);
-                    }
-                    view = new PIXI.MovieClip(tex);
-                    if (options.anchor ) {
-                        view.anchor.x = options.anchor.x;
-                        view.anchor.y = options.anchor.y;
-                    }
-                    // If a container is specified, use add to that container
-                    if (options.container) {
-                        options.container.addChild(view);
-                    } else {
-                        // Otherwise just add the view to the stage
-                        this.stage.addChild(view);
-                    }
-                    return view;
-                // Create a default case
-                default:
-                    throw 'Invalid PIXI.DisplayObject passed';
-            }
-        },
-
-        /**
-         * PixiRenderer#centerAnchor( view )
-         * - view (PIXI.DisplayObject): The view to center
-         *
-         * Centers the anchor to {x: 0.5, y: 0.5} of a view
-         **/
-        centerAnchor: function( view ) {
-            if (view !== null){
-                view.anchor.x = 0.5;
-                view.anchor.y = 0.5;
-            }
-        }
-    };
-});
-
-
-// ---
-// inside: src/outro.js
-
-return Physics;
-}));

+ 137 - 4
sites/all/modules/figli/edlp_corpus/assets/dist/scripts/corpus.min.js

@@ -1,12 +1,12 @@
 (function($) {
 
-
   EdlpCorpus = function(){
-    var $container = $('body>div.layout-container');
+    var $container = $('body');
     var $canvas = $('<canvas>').addClass('edlp-map').appendTo($container);
     var canvas = $canvas[0];
     var ctx = canvas.getContext('2d');
     var physics = new Physics();
+    var particules = [];
 
     function init(){
       console.log("EdlpCorpus init()");
@@ -15,8 +15,141 @@
 
     function initMap(){
       console.log("EdlpCorpus initMap()");
-      console.log('physics',physics);
-    }
+      // console.log('physics',physics);
+      initCanvas();
+      loadCorpus();
+    };
+
+    function initCanvas(){
+      // resize the canvas to fill browser window dynamically
+      window.addEventListener('resize', resizeCanvas, false);
+      resizeCanvas();
+    };
+
+    function resizeCanvas() {
+      canvas.width = window.innerWidth;
+      canvas.height = window.innerHeight;
+    };
+
+    function loadCorpus(){
+      // console.log('drupalSettings',drupalSettings);
+      console.log('window.location', window.location);
+      var path = window.location.origin + drupalSettings.basepath + "edlp/corpus";
+      $.getJSON(path, {}, function(data){
+        console.log('corpus loaded : data', data);
+        // console.log('first node', data.nodes[0]);
+        buildMap(data.nodes);
+        startAnime();
+      });
+    };
+
+    function buildMap(nodes){
+      var x,y,p;
+      var mass = 8;
+      console.log("physics", physics);
+      for (var i in nodes) {
+        // console.log(nodes[i]);
+        x = Math.random()*canvas.width;
+        y = Math.random()*canvas.height;
+        p = physics.makeParticle(mass, x, y);
+        p.velocity = new Physics.Vector((Math.random()-0.5)*0.10, (Math.random()-0.5)*0.10);
+        // if(particules.length){
+          // for (var i = 0; i < particules.length; i++) {
+          //   physics.makeAttraction(p, particules[i], strength, minDistance);
+          // }
+        // }
+        particules.push(p);
+      }
+    };
+
+    function render(){
+      ctx.clearRect(0, 0, canvas.width, canvas.height);
+      var radius = 5;
+
+      // colisions between particules
+      for (var p = 0, l = particules.length; p < l; p++) {
+        var particule = particules[p];
+        // var theta = 360 / (Math.PI * radius);
+        if(!particule.attracted) continue;
+        for (var q = 0; q < p; q++) {
+          if(q==p) continue;
+
+          var a = particule;
+          var b = particules[q];
+          if(!b.attracted) continue;
+          var d = a.distanceTo(b);
+
+          // apply new forces if colliding
+          if(d <= radius*2){
+
+            var newVelX1 = (a.velocity.x * (a.mass - b.mass) + (2 * b.mass * b.velocity.x)) / (a.mass + b.mass);
+            var newVelY1 = (a.velocity.y * (a.mass - b.mass) + (2 * b.mass * b.velocity.y)) / (a.mass + b.mass);
+            var newVelX2 = (b.velocity.x * (b.mass - a.mass) + (2 * a.mass * a.velocity.x)) / (a.mass + b.mass);
+            var newVelY2 = (b.velocity.y * (b.mass - a.mass) + (2 * a.mass * a.velocity.y)) / (a.mass + b.mass);
+
+            a.velocity.x = newVelX1;
+            a.velocity.y = newVelY1;
+            b.velocity.x = newVelX2;
+            b.velocity.y = newVelY2;
+
+            a.velocity.multiplyScalar(0.75);
+            b.velocity.multiplyScalar(0.75);
+
+
+            // move particles if they overlap
+            if (d < radius*2) {
+              var makeup = radius - d/2;
+              var angle = Math.atan2(b.position.y - a.position.y, b.position.x - a.position.x);
+
+              b.position.x += makeup * Math.cos(angle);
+              b.position.y += makeup * Math.sin(angle);
+
+              angle += Math.PI;
+
+              a.position.x += makeup * Math.cos(angle);
+              a.position.y += makeup * Math.sin(angle);
+
+            }
+          }
+        }
+      }
+
+      for (var i = 0; i < particules.length; i++) {
+        var p = particules[i];
+        // wall boucing
+        if(p.position.x < 0+radius || p.position.x > canvas.width-radius){
+          // console.log("bounce x");
+          p.velocity.multiplyScalarXY(-1, 1).multiplyScalar(0.75);
+        }
+        if(p.position.y < 0+radius || p.position.y > canvas.height-radius){
+          // console.log("bounce y");
+          p.velocity.multiplyScalarXY(1,-1).multiplyScalar(0.75);
+        }
+
+
+
+        // draw the ball
+        ctx.beginPath();
+        ctx.fillRect(p.position.x, p.position.y, 8, 8);
+        if(p.attracted){
+          ctx.fillStyle = "red";
+        }else{
+          ctx.fillStyle = "black";
+        }
+        ctx.fill();
+      }
+
+
+    };
+
+    function startAnime(){
+      physics.onUpdate(render);
+      // render();
+
+      physics.play()
+    };
+
+
 
     init();
   }

+ 7 - 0
sites/all/modules/figli/edlp_corpus/assets/dist/styles/corpus.min.css

@@ -0,0 +1,7 @@
+canvas.edlp-map {
+  position: absolute;
+  -webkit-box-sizing: border-box;
+  box-sizing: border-box;
+  top: 0;
+  left: 0;
+  z-index: 0; }

+ 137 - 4
sites/all/modules/figli/edlp_corpus/assets/scripts/corpus.js

@@ -1,12 +1,12 @@
 (function($) {
 
-
   EdlpCorpus = function(){
-    var $container = $('body>div.layout-container');
+    var $container = $('body');
     var $canvas = $('<canvas>').addClass('edlp-map').appendTo($container);
     var canvas = $canvas[0];
     var ctx = canvas.getContext('2d');
     var physics = new Physics();
+    var particules = [];
 
     function init(){
       console.log("EdlpCorpus init()");
@@ -15,8 +15,141 @@
 
     function initMap(){
       console.log("EdlpCorpus initMap()");
-      console.log('physics',physics);
-    }
+      // console.log('physics',physics);
+      initCanvas();
+      loadCorpus();
+    };
+
+    function initCanvas(){
+      // resize the canvas to fill browser window dynamically
+      window.addEventListener('resize', resizeCanvas, false);
+      resizeCanvas();
+    };
+
+    function resizeCanvas() {
+      canvas.width = window.innerWidth;
+      canvas.height = window.innerHeight;
+    };
+
+    function loadCorpus(){
+      // console.log('drupalSettings',drupalSettings);
+      console.log('window.location', window.location);
+      var path = window.location.origin + drupalSettings.basepath + "edlp/corpus";
+      $.getJSON(path, {}, function(data){
+        console.log('corpus loaded : data', data);
+        // console.log('first node', data.nodes[0]);
+        buildMap(data.nodes);
+        startAnime();
+      });
+    };
+
+    function buildMap(nodes){
+      var x,y,p;
+      var mass = 8;
+      console.log("physics", physics);
+      for (var i in nodes) {
+        // console.log(nodes[i]);
+        x = Math.random()*canvas.width;
+        y = Math.random()*canvas.height;
+        p = physics.makeParticle(mass, x, y);
+        p.velocity = new Physics.Vector((Math.random()-0.5)*0.10, (Math.random()-0.5)*0.10);
+        // if(particules.length){
+          // for (var i = 0; i < particules.length; i++) {
+          //   physics.makeAttraction(p, particules[i], strength, minDistance);
+          // }
+        // }
+        particules.push(p);
+      }
+    };
+
+    function render(){
+      ctx.clearRect(0, 0, canvas.width, canvas.height);
+      var radius = 5;
+
+      // colisions between particules
+      for (var p = 0, l = particules.length; p < l; p++) {
+        var particule = particules[p];
+        // var theta = 360 / (Math.PI * radius);
+        if(!particule.attracted) continue;
+        for (var q = 0; q < p; q++) {
+          if(q==p) continue;
+
+          var a = particule;
+          var b = particules[q];
+          if(!b.attracted) continue;
+          var d = a.distanceTo(b);
+
+          // apply new forces if colliding
+          if(d <= radius*2){
+
+            var newVelX1 = (a.velocity.x * (a.mass - b.mass) + (2 * b.mass * b.velocity.x)) / (a.mass + b.mass);
+            var newVelY1 = (a.velocity.y * (a.mass - b.mass) + (2 * b.mass * b.velocity.y)) / (a.mass + b.mass);
+            var newVelX2 = (b.velocity.x * (b.mass - a.mass) + (2 * a.mass * a.velocity.x)) / (a.mass + b.mass);
+            var newVelY2 = (b.velocity.y * (b.mass - a.mass) + (2 * a.mass * a.velocity.y)) / (a.mass + b.mass);
+
+            a.velocity.x = newVelX1;
+            a.velocity.y = newVelY1;
+            b.velocity.x = newVelX2;
+            b.velocity.y = newVelY2;
+
+            a.velocity.multiplyScalar(0.75);
+            b.velocity.multiplyScalar(0.75);
+
+
+            // move particles if they overlap
+            if (d < radius*2) {
+              var makeup = radius - d/2;
+              var angle = Math.atan2(b.position.y - a.position.y, b.position.x - a.position.x);
+
+              b.position.x += makeup * Math.cos(angle);
+              b.position.y += makeup * Math.sin(angle);
+
+              angle += Math.PI;
+
+              a.position.x += makeup * Math.cos(angle);
+              a.position.y += makeup * Math.sin(angle);
+
+            }
+          }
+        }
+      }
+
+      for (var i = 0; i < particules.length; i++) {
+        var p = particules[i];
+        // wall boucing
+        if(p.position.x < 0+radius || p.position.x > canvas.width-radius){
+          // console.log("bounce x");
+          p.velocity.multiplyScalarXY(-1, 1).multiplyScalar(0.75);
+        }
+        if(p.position.y < 0+radius || p.position.y > canvas.height-radius){
+          // console.log("bounce y");
+          p.velocity.multiplyScalarXY(1,-1).multiplyScalar(0.75);
+        }
+
+
+
+        // draw the ball
+        ctx.beginPath();
+        ctx.fillRect(p.position.x, p.position.y, 8, 8);
+        if(p.attracted){
+          ctx.fillStyle = "red";
+        }else{
+          ctx.fillStyle = "black";
+        }
+        ctx.fill();
+      }
+
+
+    };
+
+    function startAnime(){
+      physics.onUpdate(render);
+      // render();
+
+      physics.play()
+    };
+
+
 
     init();
   }

+ 7 - 0
sites/all/modules/figli/edlp_corpus/assets/styles/corpus.scss

@@ -0,0 +1,7 @@
+canvas.edlp-map{
+  position: absolute;
+  box-sizing: border-box;
+  top:0; left:0;
+  // width:100%; height:100%;
+  z-index:0;
+}

+ 1 - 1
sites/all/modules/figli/edlp_corpus/bower.json

@@ -14,6 +14,6 @@
     "tests"
   ],
   "dependencies": {
-    "PhysicsJS": "latest"
+    "physics": "latest"
   }
 }

+ 2 - 1
sites/all/modules/figli/edlp_corpus/edlp_corpus.libraries.yml

@@ -6,7 +6,8 @@ corpus:
 
   version: VERSION
   js:
-    assets/dist/bower/physicsjs-full.js: { scope: footer }
+    assets/dist/bower/physics.js: { scope: footer }
     assets/dist/scripts/corpus.min.js: { scope: footer }
   dependencies:
+    - core/drupalSettings
     - core/jquery

+ 6 - 2
sites/all/modules/figli/edlp_corpus/edlp_corpus.module

@@ -5,7 +5,11 @@
  * @param array $attachments
  */
 function edlp_corpus_page_attachments(array &$attachments) {
-    //add here any conditions if you need to limit the pages
-
+  //add here any conditions if you need to limit the pages
+  if (\Drupal::service('path.matcher')->isFrontPage()) {
     $attachments['#attached']['library'][] = 'edlp_corpus/corpus';
+    $attachments['#attached']['drupalSettings']['basepath'] = base_path();
+    // $attachments['#attached']['drupalSettings']['pathtoedlpcorpus'] = base_path() . drupal_get_path('module', 'edlp_corpus');
+    // $attachments['#attached']['drupalSettings']['pathtotfiles'] = PublicStream::basePath();
+  }
 }

+ 2 - 2
sites/all/modules/figli/edlp_corpus/edlp_corpus.routing.yml

@@ -1,7 +1,7 @@
-edlp_corpus.content:
+edlp_corpus.corpusjson:
   path: '/edlp/corpus'
   defaults:
-    _controller: '\Drupal\edlp_corpus\Controller\CorpusController::content'
+    _controller: '\Drupal\edlp_corpus\Controller\CorpusController::contentjson'
     _title: 'Corpus'
   requirements:
     _permission: 'access content'

+ 5 - 0
sites/all/modules/figli/edlp_corpus/gulpfile.js

@@ -42,6 +42,11 @@ gulp.task('bower', function() {
       "overrides":{
         "jquery":{
           "ignore":true
+        },
+        "physics": {
+          "main": [
+            './build/physics.js'
+          ]
         }
       }
     }))

+ 59 - 4
sites/all/modules/figli/edlp_corpus/src/Controller/CorpusController.php

@@ -3,19 +3,74 @@
 namespace Drupal\edlp_corpus\Controller;
 
 use Drupal\Core\Controller\ControllerBase;
+use Drupal\File\Entity\File;
+use Symfony\Component\HttpFoundation\JsonResponse;
+
 
 class CorpusController extends ControllerBase {
 
+
   /**
    * Display the markup.
    *
    * @return array
    */
-  public function content() {
-    return array(
-      '#type' => 'markup',
-      '#markup' => $this->t('Hello, Edlp Corpus!'),
+  public function contentjson() {
+
+    // @see https://www.droptica.com/blog/drupal-8-restjson-integration-simple-javascript-application/
+    // @see https://www.sitepoint.com/drupal-8-version-entityfieldquery/
+    // @see https://www.frobiovox.com/posts/2016/03/28/simplify-drupal-8-field-value-calls.html
+    // @see https://chromatichq.com/blog/dependency-injection-drupal-8-plugins
+
+    // Get a node storage object.
+    // $file_storage = \Drupal::entityManager()->getStorage('node')
+
+    $response = new JsonResponse();
+
+    $config = \Drupal::config('system.site');
+
+    $query = \Drupal::entityQuery('node')
+      ->condition('status', 1)
+      ->condition('type', 'enregistrement');
+
+    $nids = $query->execute();
+    $nodes = entity_load_multiple('node', $nids);
+
+    $nodes_data = [];
+    foreach ($nodes as $node) {
+
+      $entrees = [];
+      foreach ($node->get('field_entrees')->getValue() as $key => $term) {
+        $entrees[] = $term['target_id'];
+      }
+      $son_fid = $node->get('field_son')->getValue();
+      // TODO: how to get this fucking file uri, fuck !!
+      // $son_file = $file_storage->load($fid);
+      // $son_file = File::load($son_fid);
+      // $son_uri = $son_file->url();
+      // $son_uri = \Drupal\file\Entity\File::load($son_fid);//->getFileUri();
+      // $son_uri = file_create_url($node->get('field_son')->entity->getFileUri());
+
+      $nodes_data[] = array(
+        "nid" => $node->get('nid')->getString(),
+        "title" => $node->get('title')->getString(),
+        "description" => $node->get('field_description')->getString(),
+        "son_fid" => $son_fid,
+        // "son" => $son_file,
+        "entrees" => $entrees,
+      );
+    }
+
+    $data = array(
+      'date' => time(),
+      'site_name' => $config->get('name'),
+      'count' => count($nodes),
+      'nodes' => $nodes_data,
     );
+
+    $response->setData($data);
+
+    return $response;
   }
 
 }

+ 1 - 0
sites/all/themes/custom/edlptheme/.gitignore

@@ -1,3 +1,4 @@
 node_modules/
 .npm-debug-log
+package-lock.json
 bower_components/

+ 2 - 1
sites/all/themes/custom/edlptheme/assets/dist/styles/app.min.css

@@ -19,7 +19,8 @@ div.layout-container {
   height: 100%;
   padding: 1em;
   -webkit-box-sizing: border-box;
-  box-sizing: border-box; }
+  box-sizing: border-box;
+  z-index: 1; }
 
 header[role="banner"] {
   outline: 1px solid blue; }

+ 1 - 0
sites/all/themes/custom/edlptheme/assets/styles/app.scss

@@ -20,6 +20,7 @@ div.layout-container{
   width:100%; height:100%;
   padding:1em;
   box-sizing: border-box;
+  z-index: 1;
 }
 
 header[role="banner"]{