/**
 * 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 = 30; // 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";
                        // patched by noiv, + button
                        pos = { idx: touchId, x: touch.pageX - offset.left, y: touch.pageY - offset.top, button: e.button };
                        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";
                        // patched by noiv, + button
                        pos = { idx: touchId, x: touch.pageX - offset.left, y: touch.pageY - offset.top, button: e.button };
                        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;
}));