// Generated by CoffeeScript 1.4.0
(function() {
  var Animation, Animations, Bezier, Dynamic, DynamicElement, Dynamics, EaseInOut, Gravity, GravityWithForce, Linear, Loop, Matrix, SelfSpring, Spring, Vector, animationFrame, animationStart, browserSupportPrefixFor, browserSupportTransform, browserSupportWithPrefix, cacheFn, combineVector, convertToMatrix3d, css, decomposeMatrix, defaultForProperty, degProperties, getFirstFrame, hasCommonProperties, interpolateMatrix, keysForTransform, lengthVector, matrixToString, normalizeVector, parseFrames, propertiesAtFrame, pxProperties, recomposeMatrix, set, stopAnimationsForEl, transformProperties, transformStringToMatrixString, unitFor,
    __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
    __hasProp = {}.hasOwnProperty,
    __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };

  Vector = (function() {

    function Vector(els) {
      this.els = els;
      this.cross = __bind(this.cross, this);

      this.dot = __bind(this.dot, this);

      this.e = __bind(this.e, this);

    }

    Vector.prototype.e = function(i) {
      if (i < 1 || i > this.els.length) {
        return null;
      } else {
        return this.els[i - 1];
      }
    };

    Vector.prototype.dot = function(vector) {
      var V, n, product;
      V = vector.els || vector;
      product = 0;
      n = this.els.length;
      if (n !== V.length) {
        return null;
      }
      n += 1;
      while (--n) {
        product += this.els[n - 1] * V[n - 1];
      }
      return product;
    };

    Vector.prototype.cross = function(vector) {
      var A, B;
      B = vector.els || vector;
      if (this.els.length !== 3 || B.length !== 3) {
        return null;
      }
      A = this.els;
      return new Vector([(A[1] * B[2]) - (A[2] * B[1]), (A[2] * B[0]) - (A[0] * B[2]), (A[0] * B[1]) - (A[1] * B[0])]);
    };

    return Vector;

  })();

  Matrix = (function() {

    function Matrix(els) {
      this.els = els;
      this.inverse = __bind(this.inverse, this);

      this.augment = __bind(this.augment, this);

      this.toRightTriangular = __bind(this.toRightTriangular, this);

      this.transpose = __bind(this.transpose, this);

      this.multiply = __bind(this.multiply, this);

      this.dup = __bind(this.dup, this);

      this.e = __bind(this.e, this);

    }

    Matrix.prototype.e = function(i, j) {
      if (i < 1 || i > this.els.length || j < 1 || j > this.els[0].length) {
        return null;
      }
      return this.els[i - 1][j - 1];
    };

    Matrix.prototype.dup = function() {
      return new Matrix(this.els);
    };

    Matrix.prototype.multiply = function(matrix) {
      var M, c, cols, elements, i, j, ki, kj, nc, ni, nj, returnVector, sum;
      returnVector = matrix.modulus ? true : false;
      M = matrix.els || matrix;
      if (typeof M[0][0] === 'undefined') {
        M = new Matrix(M).els;
      }
      ni = this.els.length;
      ki = ni;
      kj = M[0].length;
      cols = this.els[0].length;
      elements = [];
      ni += 1;
      while (--ni) {
        i = ki - ni;
        elements[i] = [];
        nj = kj;
        nj += 1;
        while (--nj) {
          j = kj - nj;
          sum = 0;
          nc = cols;
          nc += 1;
          while (--nc) {
            c = cols - nc;
            sum += this.els[i][c] * M[c][j];
          }
          elements[i][j] = sum;
        }
      }
      M = new Matrix(elements);
      if (returnVector) {
        return M.col(1);
      } else {
        return M;
      }
    };

    Matrix.prototype.transpose = function() {
      var cols, elements, i, j, ni, nj, rows;
      rows = this.els.length;
      cols = this.els[0].length;
      elements = [];
      ni = cols;
      ni += 1;
      while (--ni) {
        i = cols - ni;
        elements[i] = [];
        nj = rows;
        nj += 1;
        while (--nj) {
          j = rows - nj;
          elements[i][j] = this.els[j][i];
        }
      }
      return new Matrix(elements);
    };

    Matrix.prototype.toRightTriangular = function() {
      var M, els, i, j, k, kp, multiplier, n, np, p, _i, _j, _ref, _ref1;
      M = this.dup();
      n = this.els.length;
      k = n;
      kp = this.els[0].length;
      while (--n) {
        i = k - n;
        if (M.els[i][i] === 0) {
          for (j = _i = _ref = i + 1; _ref <= k ? _i < k : _i > k; j = _ref <= k ? ++_i : --_i) {
            if (M.els[j][i] !== 0) {
              els = [];
              np = kp;
              np += 1;
              while (--np) {
                p = kp - np;
                els.push(M.els[i][p] + M.els[j][p]);
              }
              M.els[i] = els;
              break;
            }
          }
        }
        if (M.els[i][i] !== 0) {
          for (j = _j = _ref1 = i + 1; _ref1 <= k ? _j < k : _j > k; j = _ref1 <= k ? ++_j : --_j) {
            multiplier = M.els[j][i] / M.els[i][i];
            els = [];
            np = kp;
            np += 1;
            while (--np) {
              p = kp - np;
              els.push(p <= i ? 0 : M.els[j][p] - M.els[i][p] * multiplier);
            }
            M.els[j] = els;
          }
        }
      }
      return M;
    };

    Matrix.prototype.augment = function(matrix) {
      var M, T, cols, i, j, ki, kj, ni, nj;
      M = matrix.els || matrix;
      if (typeof M[0][0] === 'undefined') {
        M = new Matrix(M).els;
      }
      T = this.dup();
      cols = T.els[0].length;
      ni = T.els.length;
      ki = ni;
      kj = M[0].length;
      if (ni !== M.length) {
        return null;
      }
      ni += 1;
      while (--ni) {
        i = ki - ni;
        nj = kj;
        nj += 1;
        while (--nj) {
          j = kj - nj;
          T.els[i][cols + j] = M[i][j];
        }
      }
      return T;
    };

    Matrix.prototype.inverse = function() {
      var M, divisor, els, i, inverse_elements, j, ki, kp, new_element, np, p, vni, _i;
      vni = this.els.length;
      ki = ni;
      M = this.augment(Matrix.I(ni)).toRightTriangular();
      kp = M.els[0].length;
      inverse_elements = [];
      ni += 1;
      while (--ni) {
        i = ni - 1;
        els = [];
        np = kp;
        inverse_elements[i] = [];
        divisor = M.els[i][i];
        np += 1;
        while (--np) {
          p = kp - np;
          new_element = M.els[i][p] / divisor;
          els.push(new_element);
          if (p >= ki) {
            inverse_elements[i].push(new_element);
          }
        }
        M.els[i] = els;
        for (j = _i = 0; 0 <= i ? _i < i : _i > i; j = 0 <= i ? ++_i : --_i) {
          els = [];
          np = kp;
          np += 1;
          while (--np) {
            p = kp - np;
            els.push(M.els[j][p] - M.els[i][p] * M.els[j][i]);
          }
          M.els[j] = els;
        }
      }
      return new Matrix(inverse_elements);
    };

    Matrix.I = function(n) {
      var els, i, j, k, nj;
      els = [];
      k = n;
      n += 1;
      while (--n) {
        i = k - n;
        els[i] = [];
        nj = k;
        nj += 1;
        while (--nj) {
          j = k - nj;
          els[i][j] = i === j ? 1 : 0;
        }
      }
      return new Matrix(els);
    };

    return Matrix;

  })();

  Dynamic = (function() {

    Dynamic.properties = {};

    function Dynamic(options) {
      var k, v, _ref;
      this.options = options != null ? options : {};
      this.next = __bind(this.next, this);

      this.init = __bind(this.init, this);

      _ref = this.options.type.properties;
      for (k in _ref) {
        v = _ref[k];
        if (!(this.options[k] != null) && !v.editable) {
          this.options[k] = v["default"];
        }
      }
    }

    Dynamic.prototype.init = function() {
      return this.t = 0;
    };

    Dynamic.prototype.next = function(step) {
      var r;
      if (this.t > 1) {
        this.t = 1;
      }
      r = this.at(this.t);
      this.t += step;
      return r;
    };

    Dynamic.prototype.at = function(t) {
      return [t, t];
    };

    return Dynamic;

  })();

  Linear = (function(_super) {

    __extends(Linear, _super);

    function Linear() {
      return Linear.__super__.constructor.apply(this, arguments);
    }

    Linear.properties = {
      duration: {
        min: 100,
        max: 4000,
        "default": 1000
      }
    };

    Linear.prototype.at = function(t) {
      return [t, t];
    };

    return Linear;

  })(Dynamic);

  Gravity = (function(_super) {

    __extends(Gravity, _super);

    Gravity.properties = {
      bounce: {
        min: 0,
        max: 80,
        "default": 40
      },
      gravity: {
        min: 1,
        max: 4000,
        "default": 1000
      },
      expectedDuration: {
        editable: false
      }
    };

    function Gravity(options) {
      var _ref;
      this.options = options != null ? options : {};
      this.at = __bind(this.at, this);

      this.curve = __bind(this.curve, this);

      this.init = __bind(this.init, this);

      this.length = __bind(this.length, this);

      this.gravityValue = __bind(this.gravityValue, this);

      this.bounceValue = __bind(this.bounceValue, this);

      this.duration = __bind(this.duration, this);

      this.expectedDuration = __bind(this.expectedDuration, this);

      if ((_ref = this.initialForce) == null) {
        this.initialForce = false;
      }
      this.options.duration = this.duration();
      Gravity.__super__.constructor.call(this, this.options);
    }

    Gravity.prototype.expectedDuration = function() {
      return this.duration();
    };

    Gravity.prototype.duration = function() {
      return Math.round(1000 * 1000 / this.options.gravity * this.length());
    };

    Gravity.prototype.bounceValue = function() {
      return Math.min(this.options.bounce / 100, 80);
    };

    Gravity.prototype.gravityValue = function() {
      return this.options.gravity / 100;
    };

    Gravity.prototype.length = function() {
      var L, b, bounce, curve, gravity;
      bounce = this.bounceValue();
      gravity = this.gravityValue();
      b = Math.sqrt(2 / gravity);
      curve = {
        a: -b,
        b: b,
        H: 1
      };
      if (this.initialForce) {
        curve.a = 0;
        curve.b = curve.b * 2;
      }
      while (curve.H > 0.001) {
        L = curve.b - curve.a;
        curve = {
          a: curve.b,
          b: curve.b + L * bounce,
          H: curve.H * bounce * bounce
        };
      }
      return curve.b;
    };

    Gravity.prototype.init = function() {
      var L, b, bounce, curve, gravity, _results;
      Gravity.__super__.init.apply(this, arguments);
      L = this.length();
      gravity = this.gravityValue() * L * L;
      bounce = this.bounceValue();
      b = Math.sqrt(2 / gravity);
      this.curves = [];
      curve = {
        a: -b,
        b: b,
        H: 1
      };
      if (this.initialForce) {
        curve.a = 0;
        curve.b = curve.b * 2;
      }
      this.curves.push(curve);
      _results = [];
      while (curve.b < 1 && curve.H > 0.001) {
        L = curve.b - curve.a;
        curve = {
          a: curve.b,
          b: curve.b + L * bounce,
          H: curve.H * bounce * bounce
        };
        _results.push(this.curves.push(curve));
      }
      return _results;
    };

    Gravity.prototype.curve = function(a, b, H, t) {
      var L, c, t2;
      L = b - a;
      t2 = (2 / L) * t - 1 - (a * 2 / L);
      c = t2 * t2 * H - H + 1;
      if (this.initialForce) {
        c = 1 - c;
      }
      return c;
    };

    Gravity.prototype.at = function(t) {
      var bounce, curve, gravity, i, v;
      bounce = this.options.bounce / 100;
      gravity = this.options.gravity;
      i = 0;
      curve = this.curves[i];
      while (!(t >= curve.a && t <= curve.b)) {
        i += 1;
        curve = this.curves[i];
        if (!curve) {
          break;
        }
      }
      if (!curve) {
        v = this.initialForce ? 0 : 1;
      } else {
        v = this.curve(curve.a, curve.b, curve.H, t);
      }
      return [t, v];
    };

    return Gravity;

  })(Dynamic);

  GravityWithForce = (function(_super) {

    __extends(GravityWithForce, _super);

    GravityWithForce.prototype.returnsToSelf = true;

    function GravityWithForce(options) {
      this.options = options != null ? options : {};
      this.initialForce = true;
      GravityWithForce.__super__.constructor.call(this, this.options);
    }

    return GravityWithForce;

  })(Gravity);

  Spring = (function(_super) {

    __extends(Spring, _super);

    function Spring() {
      this.at = __bind(this.at, this);
      return Spring.__super__.constructor.apply(this, arguments);
    }

    Spring.properties = {
      frequency: {
        min: 0,
        max: 100,
        "default": 15
      },
      friction: {
        min: 1,
        max: 1000,
        "default": 200
      },
      anticipationStrength: {
        min: 0,
        max: 1000,
        "default": 0
      },
      anticipationSize: {
        min: 0,
        max: 99,
        "default": 0
      },
      duration: {
        min: 100,
        max: 4000,
        "default": 1000
      }
    };

    Spring.prototype.at = function(t) {
      var A, At, a, angle, b, decal, frequency, friction, frictionT, s, v, y0, yS,
        _this = this;
      frequency = Math.max(1, this.options.frequency);
      friction = Math.pow(20, this.options.friction / 100);
      s = this.options.anticipationSize / 100;
      decal = Math.max(0, s);
      frictionT = (t / (1 - s)) - (s / (1 - s));
      if (t < s) {
        A = function(t) {
          var M, a, b, x0, x1;
          M = 0.8;
          x0 = s / (1 - s);
          x1 = 0;
          b = (x0 - (M * x1)) / (x0 - x1);
          a = (M - b) / x0;
          return (a * t * _this.options.anticipationStrength / 100) + b;
        };
        yS = (s / (1 - s)) - (s / (1 - s));
        y0 = (0 / (1 - s)) - (s / (1 - s));
        b = Math.acos(1 / A(yS));
        a = (Math.acos(1 / A(y0)) - b) / (frequency * (-s));
      } else {
        A = function(t) {
          return Math.pow(friction / 10, -t) * (1 - t);
        };
        b = 0;
        a = 1;
      }
      At = A(frictionT);
      angle = frequency * (t - s) * a + b;
      v = 1 - (At * Math.cos(angle));
      return [t, v, At, frictionT, angle];
    };

    return Spring;

  })(Dynamic);

  SelfSpring = (function(_super) {

    __extends(SelfSpring, _super);

    function SelfSpring() {
      this.at = __bind(this.at, this);
      return SelfSpring.__super__.constructor.apply(this, arguments);
    }

    SelfSpring.properties = {
      frequency: {
        min: 0,
        max: 100,
        "default": 15
      },
      friction: {
        min: 1,
        max: 1000,
        "default": 200
      },
      duration: {
        min: 100,
        max: 4000,
        "default": 1000
      }
    };

    SelfSpring.prototype.returnsToSelf = true;

    SelfSpring.prototype.at = function(t) {
      var A, At, At2, Ax, angle, frequency, friction, v,
        _this = this;
      frequency = Math.max(1, this.options.frequency);
      friction = Math.pow(20, this.options.friction / 100);
      A = function(t) {
        return 1 - Math.pow(friction / 10, -t) * (1 - t);
      };
      At = A(t);
      At2 = A(1 - t);
      Ax = (Math.cos(t * 2 * 3.14 - 3.14) / 2) + 0.5;
      Ax = Math.pow(Ax, this.options.friction / 100);
      angle = frequency * t;
      v = Math.cos(angle) * Ax;
      return [t, v, Ax, -Ax];
    };

    return SelfSpring;

  })(Dynamic);

  Bezier = (function(_super) {

    __extends(Bezier, _super);

    Bezier.properties = {
      points: {
        type: 'points',
        "default": [
          {
            x: 0,
            y: 0,
            controlPoints: [
              {
                x: 0.2,
                y: 0
              }
            ]
          }, {
            x: 0.5,
            y: 1.2,
            controlPoints: [
              {
                x: 0.3,
                y: 1.2
              }, {
                x: 0.8,
                y: 1.2
              }
            ]
          }, {
            x: 1,
            y: 1,
            controlPoints: [
              {
                x: 0.8,
                y: 1
              }
            ]
          }
        ]
      },
      duration: {
        min: 100,
        max: 4000,
        "default": 1000
      }
    };

    function Bezier(options) {
      this.options = options != null ? options : {};
      this.at = __bind(this.at, this);

      this.yForX = __bind(this.yForX, this);

      this.B = __bind(this.B, this);

      this.returnsToSelf = this.options.points[this.options.points.length - 1].y === 0;
      Bezier.__super__.constructor.call(this, this.options);
    }

    Bezier.prototype.B_ = function(t, p0, p1, p2, p3) {
      return (Math.pow(1 - t, 3) * p0) + (3 * Math.pow(1 - t, 2) * t * p1) + (3 * (1 - t) * Math.pow(t, 2) * p2) + Math.pow(t, 3) * p3;
    };

    Bezier.prototype.B = function(t, p0, p1, p2, p3) {
      return {
        x: this.B_(t, p0.x, p1.x, p2.x, p3.x),
        y: this.B_(t, p0.y, p1.y, p2.y, p3.y)
      };
    };

    Bezier.prototype.yForX = function(xTarget, Bs) {
      var B, aB, i, lower, percent, upper, x, xTolerance, _i, _len;
      B = null;
      for (_i = 0, _len = Bs.length; _i < _len; _i++) {
        aB = Bs[_i];
        if (xTarget >= aB(0).x && xTarget <= aB(1).x) {
          B = aB;
        }
        if (B !== null) {
          break;
        }
      }
      if (!B) {
        if (this.returnsToSelf) {
          return 0;
        } else {
          return 1;
        }
      }
      xTolerance = 0.0001;
      lower = 0;
      upper = 1;
      percent = (upper + lower) / 2;
      x = B(percent).x;
      i = 0;
      while (Math.abs(xTarget - x) > xTolerance && i < 100) {
        if (xTarget > x) {
          lower = percent;
        } else {
          upper = percent;
        }
        percent = (upper + lower) / 2;
        x = B(percent).x;
        i += 1;
      }
      return B(percent).y;
    };

    Bezier.prototype.at = function(t) {
      var Bs, i, k, points, x, y, _fn,
        _this = this;
      x = t;
      points = this.options.points || Bezier.properties.points["default"];
      Bs = [];
      _fn = function(pointA, pointB) {
        var B;
        B = function(t) {
          return _this.B(t, pointA, pointA.controlPoints[pointA.controlPoints.length - 1], pointB.controlPoints[0], pointB);
        };
        return Bs.push(B);
      };
      for (i in points) {
        k = parseInt(i);
        if (k >= points.length - 1) {
          break;
        }
        _fn(points[k], points[k + 1]);
      }
      y = this.yForX(x, Bs);
      return [x, y];
    };

    return Bezier;

  })(Dynamic);

  EaseInOut = (function(_super) {

    __extends(EaseInOut, _super);

    EaseInOut.properties = {
      friction: {
        min: 1,
        max: 1000,
        "default": 500
      },
      duration: {
        min: 100,
        max: 4000,
        "default": 1000
      }
    };

    function EaseInOut(options) {
      var friction, points;
      this.options = options != null ? options : {};
      this.at = __bind(this.at, this);

      EaseInOut.__super__.constructor.apply(this, arguments);
      friction = this.options.friction || EaseInOut.properties.friction["default"];
      points = [
        {
          x: 0,
          y: 0,
          controlPoints: [
            {
              x: 1 - (friction / 1000),
              y: 0
            }
          ]
        }, {
          x: 1,
          y: 1,
          controlPoints: [
            {
              x: friction / 1000,
              y: 1
            }
          ]
        }
      ];
      this.bezier = new Bezier({
        type: Bezier,
        duration: this.options.duration,
        points: points
      });
    }

    EaseInOut.prototype.at = function(t) {
      return this.bezier.at(t);
    };

    return EaseInOut;

  })(Dynamic);

  cacheFn = function(func) {
    var cachedMethod, data;
    data = {};
    cachedMethod = function() {
      var k, key, result, _i, _len;
      key = "";
      for (_i = 0, _len = arguments.length; _i < _len; _i++) {
        k = arguments[_i];
        key += k.toString() + ",";
      }
      result = data[key];
      if (!result) {
        data[key] = result = func.apply(this, arguments);
      }
      return result;
    };
    return cachedMethod;
  };

  browserSupportTransform = function() {
    return browserSupportWithPrefix("transform");
  };

  browserSupportPrefixFor = cacheFn(function(property) {
    var k, prefix, prop, propArray, propertyName, _i, _j, _len, _len1, _ref;
    propArray = property.split('-');
    propertyName = "";
    for (_i = 0, _len = propArray.length; _i < _len; _i++) {
      prop = propArray[_i];
      propertyName += prop.substring(0, 1).toUpperCase() + prop.substring(1);
    }
    _ref = ["Webkit", "Moz"];
    for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
      prefix = _ref[_j];
      k = prefix + propertyName;
      if (document.body.style[k] !== void 0) {
        return prefix;
      }
    }
    return '';
  });

  browserSupportWithPrefix = cacheFn(function(property) {
    var prefix;
    prefix = browserSupportPrefixFor(property);
    if (prefix === 'Moz') {
      return "" + prefix + (property.substring(0, 1).toUpperCase() + property.substring(1));
    }
    if (prefix !== '') {
      return "-" + (prefix.toLowerCase()) + "-" + property;
    }
    return property;
  });

  lengthVector = function(vector) {
    var a, e, _i, _len, _ref;
    a = 0;
    _ref = vector.els;
    for (_i = 0, _len = _ref.length; _i < _len; _i++) {
      e = _ref[_i];
      a += Math.pow(e, 2);
    }
    return Math.sqrt(a);
  };

  normalizeVector = function(vector) {
    var e, i, length, newElements, _ref;
    length = lengthVector(vector);
    newElements = [];
    _ref = vector.els;
    for (i in _ref) {
      e = _ref[i];
      newElements[i] = e / length;
    }
    return new Vector(newElements);
  };

  combineVector = function(a, b, ascl, bscl) {
    var i, result, _i;
    result = [];
    for (i = _i = 0; _i <= 2; i = ++_i) {
      result[i] = (ascl * a.els[i]) + (bscl * b.els[i]);
    }
    return new Vector(result);
  };

  decomposeMatrix = function(matrix) {
    var els, i, inversePerspectiveMatrix, j, k, pdum3, perspective, perspectiveMatrix, quaternion, result, rightHandSide, rotate, row, rowElement, s, scale, skew, t, translate, transposedInversePerspectiveMatrix, type, typeKey, v, w, x, y, z, _i, _j, _k, _l, _m, _n, _o, _p;
    translate = [];
    scale = [];
    skew = [];
    quaternion = [];
    perspective = [];
    els = matrix.els;
    if (els[3][3] === 0) {
      return false;
    }
    for (i = _i = 0; _i <= 3; i = ++_i) {
      for (j = _j = 0; _j <= 3; j = ++_j) {
        els[i][j] /= els[3][3];
      }
    }
    perspectiveMatrix = matrix.dup();
    for (i = _k = 0; _k <= 2; i = ++_k) {
      perspectiveMatrix.els[i][3] = 0;
    }
    perspectiveMatrix.els[3][3] = 1;
    if (els[0][3] !== 0 || els[1][3] !== 0 || els[2][3] !== 0) {
      rightHandSide = new Vector(els.slice(0, 4)[3]);
      inversePerspectiveMatrix = perspectiveMatrix.inverse();
      transposedInversePerspectiveMatrix = inversePerspectiveMatrix.transpose();
      perspective = transposedInversePerspectiveMatrix.multiply(rightHandSide).els;
      for (i = _l = 0; _l <= 2; i = ++_l) {
        els[i][3] = 0;
      }
      els[3][3] = 1;
    } else {
      perspective = [0, 0, 0, 1];
    }
    for (i = _m = 0; _m <= 2; i = ++_m) {
      translate[i] = els[3][i];
      els[3][i] = 0;
    }
    row = [];
    for (i = _n = 0; _n <= 2; i = ++_n) {
      row[i] = new Vector(els[i].slice(0, 3));
    }
    scale[0] = lengthVector(row[0]);
    row[0] = normalizeVector(row[0]);
    skew[0] = row[0].dot(row[1]);
    row[1] = combineVector(row[1], row[0], 1.0, -skew[0]);
    scale[1] = lengthVector(row[1]);
    row[1] = normalizeVector(row[1]);
    skew[0] /= scale[1];
    skew[1] = row[0].dot(row[2]);
    row[2] = combineVector(row[2], row[0], 1.0, -skew[1]);
    skew[2] = row[1].dot(row[2]);
    row[2] = combineVector(row[2], row[1], 1.0, -skew[2]);
    scale[2] = lengthVector(row[2]);
    row[2] = normalizeVector(row[2]);
    skew[1] /= scale[2];
    skew[2] /= scale[2];
    pdum3 = row[1].cross(row[2]);
    if (row[0].dot(pdum3) < 0) {
      for (i = _o = 0; _o <= 2; i = ++_o) {
        scale[i] *= -1;
        for (j = _p = 0; _p <= 2; j = ++_p) {
          row[i].els[j] *= -1;
        }
      }
    }
    rowElement = function(index, elementIndex) {
      return row[index].els[elementIndex];
    };
    rotate = [];
    rotate[1] = Math.asin(-rowElement(0, 2));
    if (Math.cos(rotate[1]) !== 0) {
      rotate[0] = Math.atan2(rowElement(1, 2), rowElement(2, 2));
      rotate[2] = Math.atan2(rowElement(0, 1), rowElement(0, 0));
    } else {
      rotate[0] = Math.atan2(-rowElement(2, 0), rowElement(1, 1));
      rotate[1] = 0;
    }
    t = rowElement(0, 0) + rowElement(1, 1) + rowElement(2, 2) + 1.0;
    if (t > 1e-4) {
      s = 0.5 / Math.sqrt(t);
      w = 0.25 / s;
      x = (rowElement(2, 1) - rowElement(1, 2)) * s;
      y = (rowElement(0, 2) - rowElement(2, 0)) * s;
      z = (rowElement(1, 0) - rowElement(0, 1)) * s;
    } else if ((rowElement(0, 0) > rowElement(1, 1)) && (rowElement(0, 0) > rowElement(2, 2))) {
      s = Math.sqrt(1.0 + rowElement(0, 0) - rowElement(1, 1) - rowElement(2, 2)) * 2.0;
      x = 0.25 * s;
      y = (rowElement(0, 1) + rowElement(1, 0)) / s;
      z = (rowElement(0, 2) + rowElement(2, 0)) / s;
      w = (rowElement(2, 1) - rowElement(1, 2)) / s;
    } else if (rowElement(1, 1) > rowElement(2, 2)) {
      s = Math.sqrt(1.0 + rowElement(1, 1) - rowElement(0, 0) - rowElement(2, 2)) * 2.0;
      x = (rowElement(0, 1) + rowElement(1, 0)) / s;
      y = 0.25 * s;
      z = (rowElement(1, 2) + rowElement(2, 1)) / s;
      w = (rowElement(0, 2) - rowElement(2, 0)) / s;
    } else {
      s = Math.sqrt(1.0 + rowElement(2, 2) - rowElement(0, 0) - rowElement(1, 1)) * 2.0;
      x = (rowElement(0, 2) + rowElement(2, 0)) / s;
      y = (rowElement(1, 2) + rowElement(2, 1)) / s;
      z = 0.25 * s;
      w = (rowElement(1, 0) - rowElement(0, 1)) / s;
    }
    quaternion = [x, y, z, w];
    result = {
      translate: translate,
      scale: scale,
      skew: skew,
      quaternion: quaternion,
      perspective: perspective,
      rotate: rotate
    };
    for (typeKey in result) {
      type = result[typeKey];
      for (k in type) {
        v = type[k];
        if (isNaN(v)) {
          type[k] = 0;
        }
      }
    }
    return result;
  };

  interpolateMatrix = function(decomposedA, decomposedB, t, only) {
    var angle, decomposed, i, invscale, invth, k, qa, qb, scale, th, _i, _j, _k, _l, _len, _ref, _ref1;
    if (only == null) {
      only = [];
    }
    decomposed = {};
    _ref = ['translate', 'scale', 'skew', 'perspective'];
    for (_i = 0, _len = _ref.length; _i < _len; _i++) {
      k = _ref[_i];
      decomposed[k] = [];
      for (i = _j = 0, _ref1 = decomposedA[k].length - 1; 0 <= _ref1 ? _j <= _ref1 : _j >= _ref1; i = 0 <= _ref1 ? ++_j : --_j) {
        if (only.indexOf(k) > -1 || only.indexOf("" + k + ['x', 'y', 'z'][i]) > -1) {
          decomposed[k][i] = (decomposedB[k][i] - decomposedA[k][i]) * t + decomposedA[k][i];
        } else {
          decomposed[k][i] = decomposedA[k][i];
        }
      }
    }
    if (only.indexOf('rotate') !== -1) {
      qa = decomposedA.quaternion;
      qb = decomposedB.quaternion;
      angle = qa[0] * qb[0] + qa[1] * qb[1] + qa[2] * qb[2] + qa[3] * qb[3];
      if (angle < 0.0) {
        for (i = _k = 0; _k <= 3; i = ++_k) {
          qa[i] = -qa[i];
        }
        angle = -angle;
      }
      if (angle + 1.0 > .05) {
        if (1.0 - angle >= .05) {
          th = Math.acos(angle);
          invth = 1.0 / Math.sin(th);
          scale = Math.sin(th * (1.0 - t)) * invth;
          invscale = Math.sin(th * t) * invth;
        } else {
          scale = 1.0 - t;
          invscale = t;
        }
      } else {
        qb[0] = -qa[1];
        qb[1] = qa[0];
        qb[2] = -qa[3];
        qb[3] = qa[2];
        scale = Math.sin(piDouble * (.5 - t));
        invscale = Math.sin(piDouble * t);
      }
      decomposed.quaternion = [];
      for (i = _l = 0; _l <= 3; i = ++_l) {
        decomposed.quaternion[i] = qa[i] * scale + qb[i] * invscale;
      }
    } else {
      decomposed.quaternion = decomposedA.quaternion;
    }
    return decomposed;
  };

  recomposeMatrix = function(decomposedMatrix) {
    var i, j, match, matrix, quaternion, skew, temp, w, x, y, z, _i, _j, _k, _l;
    matrix = Matrix.I(4);
    for (i = _i = 0; _i <= 3; i = ++_i) {
      matrix.els[i][3] = decomposedMatrix.perspective[i];
    }
    quaternion = decomposedMatrix.quaternion;
    x = quaternion[0];
    y = quaternion[1];
    z = quaternion[2];
    w = quaternion[3];
    skew = decomposedMatrix.skew;
    match = [[1, 0], [2, 0], [2, 1]];
    for (i = _j = 2; _j >= 0; i = --_j) {
      if (skew[i]) {
        temp = Matrix.I(4);
        temp.els[match[i][0]][match[i][1]] = skew[i];
        matrix = matrix.multiply(temp);
      }
    }
    matrix = matrix.multiply(new Matrix([[1 - 2 * (y * y + z * z), 2 * (x * y - z * w), 2 * (x * z + y * w), 0], [2 * (x * y + z * w), 1 - 2 * (x * x + z * z), 2 * (y * z - x * w), 0], [2 * (x * z - y * w), 2 * (y * z + x * w), 1 - 2 * (x * x + y * y), 0], [0, 0, 0, 1]]));
    for (i = _k = 0; _k <= 2; i = ++_k) {
      for (j = _l = 0; _l <= 2; j = ++_l) {
        matrix.els[i][j] *= decomposedMatrix.scale[i];
      }
      matrix.els[3][i] = decomposedMatrix.translate[i];
    }
    return matrix;
  };

  matrixToString = function(matrix) {
    var i, j, str, _i, _j;
    str = 'matrix3d(';
    for (i = _i = 0; _i <= 3; i = ++_i) {
      for (j = _j = 0; _j <= 3; j = ++_j) {
        str += matrix.els[i][j];
        if (!(i === 3 && j === 3)) {
          str += ',';
        }
      }
    }
    str += ')';
    return str;
  };

  transformStringToMatrixString = cacheFn(function(transform) {
    var matrixEl, result, style;
    matrixEl = document.createElement('div');
    matrixEl.style[browserSupportTransform()] = transform;
    document.body.appendChild(matrixEl);
    style = window.getComputedStyle(matrixEl, null);
    result = style.transform || style[browserSupportTransform()];
    document.body.removeChild(matrixEl);
    return result;
  });

  convertToMatrix3d = function(transform) {
    var digits, elements, i, match, matrixElements, _i;
    match = transform.match(/matrix3?d?\(([-0-9, \.]*)\)/);
    if (match) {
      digits = match[1].split(',');
      digits = digits.map(parseFloat);
      if (digits.length === 6) {
        elements = [digits[0], digits[1], 0, 0, digits[2], digits[3], 0, 0, 0, 0, 1, 0, digits[4], digits[5], 0, 1];
      } else {
        elements = digits;
      }
    } else {
      elements = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
    }
    matrixElements = [];
    for (i = _i = 0; _i <= 3; i = ++_i) {
      matrixElements.push(elements.slice(i * 4, i * 4 + 4));
    }
    return new Matrix(matrixElements);
  };

  getFirstFrame = function(properties) {
    var frame, k, style, v;
    frame = {};
    style = window.getComputedStyle(this.el, null);
    for (k in properties) {
      if (transformProperties.contains(k)) {
        k = 'transform';
      }
      if (!frame[k]) {
        v = this.el.style[browserSupportWithPrefix(k)];
        if (v == null) {
          v = style[browserSupportWithPrefix(k)];
        }
        frame[k] = v;
      }
    }
    return frame;
  };

  parseFrames = function(frames) {
    var k, match, newFrames, newProperties, percent, properties, transform, transforms, unit, v, vString, value;
    newFrames = {};
    for (percent in frames) {
      properties = frames[percent];
      transforms = [];
      newProperties = {};
      for (k in properties) {
        v = properties[k];
        if (k === 'transform') {
          transforms.push(v);
        } else if (transformProperties.contains(k)) {
          v = "" + k + "(" + v + (unitFor(k, v)) + ")";
          transforms.push(v);
        } else {
          vString = v + "";
          match = vString.match(/([-0-9.]*)(.*)/);
          value = parseFloat(match[1]);
          unit = match[2];
          newProperties[k] = {
            value: value,
            originalValue: v,
            unit: unit
          };
        }
      }
      if (transforms.length > 0) {
        transform = transforms.join(' ');
        newProperties['transform'] = {
          value: decomposeMatrix(convertToMatrix3d(transformStringToMatrixString(transform))),
          originalValue: transform,
          unit: ''
        };
      }
      newFrames[percent] = newProperties;
    }
    return newFrames;
  };

  defaultForProperty = function(property) {
    if (property === 'opacity') {
      return 1;
    }
    return 0;
  };

  animationFrame = function(ts) {
    var at, dTs, properties, t, _base;
    if (this.stopped) {
      Loop.remove(this);
      return {};
    }
    t = 0;
    if (this.ts) {
      dTs = ts - this.ts;
      t = dTs / this.options.duration;
    } else {
      this.ts = ts;
    }
    at = this.dynamic().at(t);
    properties = propertiesAtFrame.call(this, at[1], {
      progress: t
    });
    if (t >= 1) {
      Loop.remove(this);
      this.animating = false;
      this.dynamic().init();
      if (typeof (_base = this.options).complete === "function") {
        _base.complete(this);
      }
    }
    return properties;
  };

  propertiesAtFrame = function(t, args) {
    var dValue, frame0, frame1, k, newValue, oldValue, progress, properties, transform, unit, v, value;
    if (args == null) {
      args = {};
    }
    frame0 = this.frames[0];
    frame1 = this.frames[100];
    progress = args.progress;
    if (progress == null) {
      progress = -1;
    }
    transform = '';
    properties = {};
    for (k in frame1) {
      v = frame1[k];
      value = v.value;
      unit = v.unit;
      newValue = null;
      if (progress >= 1) {
        if (this.returnsToSelf) {
          newValue = frame0[k].value;
        } else {
          newValue = frame1[k].value;
        }
      }
      if (k === 'transform') {
        if (newValue == null) {
          newValue = interpolateMatrix(frame0[k].value, frame1[k].value, t, this.keysToInterpolate);
        }
        properties['transform'] = recomposeMatrix(newValue);
      } else {
        if (!newValue) {
          oldValue = null;
          if (frame0[k]) {
            oldValue = frame0[k].value;
          }
          if (!(oldValue != null) || isNaN(oldValue)) {
            oldValue = defaultForProperty(k);
          }
          dValue = value - oldValue;
          newValue = oldValue + (dValue * t);
        }
        properties[k] = newValue;
      }
    }
    return properties;
  };

  animationStart = function() {
    if (!this.options.animated) {
      alert('!!! need to do something here');
      return;
    }
    this.animating = true;
    this.ts = null;
    if (this.stopped) {
      this.stopped = false;
    }
    return Loop.add(this);
  };

  keysForTransform = function(transform) {
    var keys, match, matches, _i, _len;
    matches = transform.match(/[a-zA-Z0-9]*\([^)]*\)/g);
    keys = [];
    if (matches != null) {
      for (_i = 0, _len = matches.length; _i < _len; _i++) {
        match = matches[_i];
        keys.push(match.substring(0, match.indexOf('(')));
      }
    }
    return keys;
  };

  Animations = [];

  hasCommonProperties = function(props1, props2) {
    var k, v;
    for (k in props1) {
      v = props1[k];
      if (props2[k] != null) {
        return true;
      }
    }
    return false;
  };

  stopAnimationsForEl = function(el, properties) {
    var animation, _i, _len, _results;
    _results = [];
    for (_i = 0, _len = Animations.length; _i < _len; _i++) {
      animation = Animations[_i];
      if (animation.el === el && hasCommonProperties(animation.to, properties)) {
        _results.push(animation.stop());
      } else {
        _results.push(void 0);
      }
    }
    return _results;
  };

  Loop = {
    animations: [],
    running: false,
    start: function() {
      this.running = true;
      return requestAnimationFrame(this.tick.bind(this));
    },
    stop: function() {
      return this.running = false;
    },
    tick: function(ts) {
      var animation, animations, el, elProperties, found, k, properties, propertiesByEls, v, _i, _j, _k, _len, _len1, _len2, _ref, _ref1;
      if (!this.running) {
        return;
      }
      animations = this.animations.slice();
      propertiesByEls = [];
      for (_i = 0, _len = animations.length; _i < _len; _i++) {
        animation = animations[_i];
        properties = animationFrame.call(animation, ts);
        found = false;
        for (_j = 0, _len1 = propertiesByEls.length; _j < _len1; _j++) {
          _ref = propertiesByEls[_j], el = _ref[0], elProperties = _ref[1];
          if (animation.el === el) {
            for (k in properties) {
              v = properties[k];
              if (k === 'transform' && elProperties[k]) {
                v = v.multiply(elProperties[k]);
              }
              elProperties[k] = v;
            }
            found = true;
            break;
          }
        }
        if (!found) {
          propertiesByEls.push([animation.el, properties]);
        }
      }
      for (_k = 0, _len2 = propertiesByEls.length; _k < _len2; _k++) {
        _ref1 = propertiesByEls[_k], el = _ref1[0], properties = _ref1[1];
        if (properties['transform'] != null) {
          properties['transform'] = matrixToString(properties['transform']);
        }
        css(el, properties);
      }
      return requestAnimationFrame(this.tick.bind(this));
    },
    add: function(animation) {
      if (this.animations.indexOf(animation) === -1) {
        this.animations.push(animation);
      }
      if (!this.running && this.animations.length > 0) {
        return this.start();
      }
    },
    remove: function(animation) {
      if (this.running && this.animations.length === 0) {
        return this.stop();
      }
    }
  };

  set = function(array) {
    var obj, v, _i, _len;
    obj = {};
    for (_i = 0, _len = array.length; _i < _len; _i++) {
      v = array[_i];
      obj[v] = 1;
    }
    return {
      obj: obj,
      contains: function(v) {
        return obj[v] != null;
      }
    };
  };

  pxProperties = set(['marginTop', 'marginLeft', 'marginBottom', 'marginRight', 'paddingTop', 'paddingLeft', 'paddingBottom', 'paddingRight', 'top', 'left', 'bottom', 'right', 'translateX', 'translateY', 'translateZ']);

  degProperties = set(['rotate', 'rotateX', 'rotateY', 'rotateZ', 'skew', 'skewX', 'skewY', 'skewZ']);

  transformProperties = set(['translateX', 'translateY', 'translateZ', 'scale', 'scaleX', 'scaleY', 'scaleZ', 'rotate', 'rotateX', 'rotateY', 'rotateZ', 'skew', 'skewX', 'skewY', 'skewZ', 'perspective', 'width', 'height', 'maxWidth', 'maxHeight', 'minWidth', 'minHeight']);

  unitFor = function(k, v) {
    if (typeof v !== 'number') {
      return '';
    }
    if (pxProperties.contains(k)) {
      return 'px';
    } else if (degProperties.contains(k)) {
      return 'deg';
    }
    return '';
  };

  css = function(el, properties) {
    var k, transforms, v;
    transforms = [];
    for (k in properties) {
      v = properties[k];
      if (k === 'transform') {
        transforms.push(v);
      }
      if (transformProperties.contains(k)) {
        transforms.push("" + k + "(" + v + (unitFor(k, v)) + ")");
      } else {
        el.style[browserSupportWithPrefix(k)] = "" + v + (unitFor(k, v));
      }
    }
    if (transforms.length > 0) {
      return el.style[browserSupportWithPrefix("transform")] = transforms.join(' ');
    }
  };

  Animation = (function() {

    function Animation(el, to, options) {
      var redraw;
      this.el = el;
      this.to = to;
      if (options == null) {
        options = {};
      }
      this.stop = __bind(this.stop, this);

      this.start = __bind(this.start, this);

      this.dynamic = __bind(this.dynamic, this);

      this.setOptions = __bind(this.setOptions, this);

      if (window['jQuery'] && this.el instanceof jQuery) {
        this.el = this.el[0];
      }
      this.animating = false;
      redraw = this.el.offsetHeight;
      this.frames = parseFrames({
        0: getFirstFrame.call(this, this.to),
        100: this.to
      });
      this.keysToInterpolate = [];
      if (this.frames[100]['transform'] != null) {
        this.keysToInterpolate = keysForTransform(this.frames[100]['transform'].originalValue);
        this.keysToInterpolate = this.keysToInterpolate.map(function(e) {
          return e.toLowerCase();
        });
      }
      this.setOptions(options);
      if (this.options.debugName && Dynamics.InteractivePanel) {
        Dynamics.InteractivePanel.addAnimation(this);
      }
      Animations.push(this);
    }

    Animation.prototype.setOptions = function(options) {
      var optionsChanged, _base, _base1, _base2, _base3, _ref, _ref1, _ref2, _ref3, _ref4;
      if (options == null) {
        options = {};
      }
      optionsChanged = (_ref = this.options) != null ? _ref.optionsChanged : void 0;
      this.options = options;
      if ((_ref1 = (_base = this.options).duration) == null) {
        _base.duration = 1000;
      }
      if ((_ref2 = (_base1 = this.options).complete) == null) {
        _base1.complete = null;
      }
      if ((_ref3 = (_base2 = this.options).type) == null) {
        _base2.type = Linear;
      }
      if ((_ref4 = (_base3 = this.options).animated) == null) {
        _base3.animated = true;
      }
      this.returnsToSelf = false || this.dynamic().returnsToSelf;
      this._dynamic = null;
      if ((this.options.debugName != null) && (Dynamics.Overrides != null) && Dynamics.Overrides["for"](this.options.debugName)) {
        this.options = Dynamics.Overrides.getOverride(this.options, this.options.debugName);
      }
      this.dynamic().init();
      return typeof optionsChanged === "function" ? optionsChanged() : void 0;
    };

    Animation.prototype.dynamic = function() {
      var _ref;
      if ((_ref = this._dynamic) == null) {
        this._dynamic = new this.options.type(this.options);
      }
      return this._dynamic;
    };

    Animation.prototype.start = function(options) {
      var _ref, _ref1;
      if (options == null) {
        options = {};
      }
      if ((_ref = options.delay) == null) {
        options.delay = this.options.delay;
      }
      if ((_ref1 = options.delay) == null) {
        options.delay = 0;
      }
      stopAnimationsForEl(this.el, this.to);
      if (options.delay <= 0) {
        return animationStart.call(this);
      } else {
        return setTimeout(animationStart.bind(this), options.delay);
      }
    };

    Animation.prototype.stop = function() {
      this.animating = false;
      return this.stopped = true;
    };

    return Animation;

  })();

  DynamicElement = (function() {

    function DynamicElement(el) {
      this.delay = __bind(this.delay, this);

      this.start = __bind(this.start, this);

      this.to = __bind(this.to, this);

      this.css = __bind(this.css, this);
      this._el = el;
      this._delay = 0;
      this._animations = [];
    }

    DynamicElement.prototype.css = function(to) {
      css(this._el, to);
      return this;
    };

    DynamicElement.prototype.to = function(to, options) {
      if (options == null) {
        options = {};
      }
      options.delay = this._delay;
      this._animations.push(new Dynamics.Animation(this._el, to, options));
      return this;
    };

    DynamicElement.prototype.start = function() {
      var animation, _i, _len, _ref;
      _ref = this._animations;
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        animation = _ref[_i];
        animation.start();
      }
      this._animations = [];
      this._delay = 0;
      return this;
    };

    DynamicElement.prototype.delay = function(delay) {
      this._delay += delay;
      return this;
    };

    return DynamicElement;

  })();

  this.dynamic = function(el) {
    return new DynamicElement(el);
  };

  Dynamics = {
    Animation: Animation,
    Types: {
      Spring: Spring,
      SelfSpring: SelfSpring,
      Gravity: Gravity,
      GravityWithForce: GravityWithForce,
      Linear: Linear,
      Bezier: Bezier,
      EaseInOut: EaseInOut
    },
    css: css
  };

  try {
    if (module) {
      module.exports = Dynamics;
    } else {
      this.Dynamics = Dynamics;
    }
  } catch (e) {
    this.Dynamics = Dynamics;
  }

}).call(this);

