text: /**
   * Shifty Core
   * By Jeremy Kahn - jeremyckahn@gmail.com
   */
  
  var Tweenable = (function () {
  
    'use strict';
  
    // Aliases that get defined later in this function
    var formula;
  
    // CONSTANTS
    var DEFAULT_SCHEDULE_FUNCTION;
    var DEFAULT_EASING = 'linear';
    var DEFAULT_DURATION = 500;
    var UPDATE_TIME = 1000 / 60;
  
    var _now = Date.now
         ? Date.now
         : function () {return +new Date();};
  
    var now = typeof SHIFTY_DEBUG_NOW !== 'undefined' ? SHIFTY_DEBUG_NOW : _now;
  
    if (typeof window !== 'undefined') {
      // requestAnimationFrame() shim by Paul Irish (modified for Shifty)
      // http://paulirish.com/2011/requestanimationframe-for-smart-animating/
      DEFAULT_SCHEDULE_FUNCTION = window.requestAnimationFrame
         || window.webkitRequestAnimationFrame
         || window.oRequestAnimationFrame
         || window.msRequestAnimationFrame
         || (window.mozCancelRequestAnimationFrame
         && window.mozRequestAnimationFrame)
         || setTimeout;
    } else {
      DEFAULT_SCHEDULE_FUNCTION = setTimeout;
    }
  
    function noop () {
      // NOOP!
    }
  
    /**
     * Handy shortcut for doing a for-in loop. This is not a "normal" each
     * function, it is optimized for Shifty.  The iterator function only receives
     * the property name, not the value.
     * @param {Object} obj
     * @param {Function(string)} fn
     * @private
     */
    function each (obj, fn) {
      var key;
      for (key in obj) {
        if (Object.hasOwnProperty.call(obj, key)) {
          fn(key);
        }
      }
    }
  
    /**
     * Perform a shallow copy of Object properties.
     * @param {Object} targetObject The object to copy into
     * @param {Object} srcObject The object to copy from
     * @return {Object} A reference to the augmented `targetObj` Object
     * @private
     */
    function shallowCopy (targetObj, srcObj) {
      each(srcObj, function (prop) {
        targetObj[prop] = srcObj[prop];
      });
  
      return targetObj;
    }
  
    /**
     * Copies each property from src onto target, but only if the property to
     * copy to target is undefined.
     * @param {Object} target Missing properties in this Object are filled in
     * @param {Object} src
     * @private
     */
    function defaults (target, src) {
      each(src, function (prop) {
        if (typeof target[prop] === 'undefined') {
          target[prop] = src[prop];
        }
      });
    }
  
    /**
     * Calculates the interpolated tween values of an Object for a given
     * timestamp.
     * @param {Number} forPosition The position to compute the state for.
     * @param {Object} currentState Current state properties.
     * @param {Object} originalState: The original state properties the Object is
     * tweening from.
     * @param {Object} targetState: The destination state properties the Object
     * is tweening to.
     * @param {number} duration: The length of the tween in milliseconds.
     * @param {number} timestamp: The UNIX epoch time at which the tween began.
     * @param {Object} easing: This Object's keys must correspond to the keys in
     * targetState.
     * @private
     */
    function tweenProps (forPosition, currentState, originalState, targetState,
      duration, timestamp, easing) {
      var normalizedPosition =
          forPosition < timestamp ? 0 : (forPosition - timestamp) / duration;
  
  
      var prop;
      var easingObjectProp;
      var easingFn;
      for (prop in currentState) {
        if (currentState.hasOwnProperty(prop)) {
          easingObjectProp = easing[prop];
          easingFn = typeof easingObjectProp === 'function'
            ? easingObjectProp
            : formula[easingObjectProp];
  
          currentState[prop] = tweenProp(
            originalState[prop],
            targetState[prop],
            easingFn,
            normalizedPosition
          );
        }
      }
  
      return currentState;
    }
  
    /**
     * Tweens a single property.
     * @param {number} start The value that the tween started from.
     * @param {number} end The value that the tween should end at.
     * @param {Function} easingFunc The easing curve to apply to the tween.
     * @param {number} position The normalized position (between 0.0 and 1.0) to
     * calculate the midpoint of 'start' and 'end' against.
     * @return {number} The tweened value.
     * @private
     */
    function tweenProp (start, end, easingFunc, position) {
      return start + (end - start) * easingFunc(position);
    }
  
    /**
     * Applies a filter to Tweenable instance.
     * @param {Tweenable} tweenable The `Tweenable` instance to call the filter
     * upon.
     * @param {String} filterName The name of the filter to apply.
     * @private
     */
    function applyFilter (tweenable, filterName) {
      var filters = Tweenable.prototype.filter;
      var args = tweenable._filterArgs;
  
      each(filters, function (name) {
        if (typeof filters[name][filterName] !== 'undefined') {
          filters[name][filterName].apply(tweenable, args);
        }
      });
    }
  
    var timeoutHandler_endTime;
    var timeoutHandler_currentTime;
    var timeoutHandler_isEnded;
    var timeoutHandler_offset;
    /**
     * Handles the update logic for one step of a tween.
     * @param {Tweenable} tweenable
     * @param {number} timestamp
     * @param {number} delay
     * @param {number} duration
     * @param {Object} currentState
     * @param {Object} originalState
     * @param {Object} targetState
     * @param {Object} easing
     * @param {Function(Object, *, number)} step
     * @param {Function(Function,number)}} schedule
     * @param {number=} opt_currentTimeOverride Needed for accurate timestamp in
     * Tweenable#seek.
     * @private
     */
    function timeoutHandler (tweenable, timestamp, delay, duration, currentState,
      originalState, targetState, easing, step, schedule,
      opt_currentTimeOverride) {
  
      timeoutHandler_endTime = timestamp + delay + duration;
  
      timeoutHandler_currentTime =
      Math.min(opt_currentTimeOverride || now(), timeoutHandler_endTime);
  
      timeoutHandler_isEnded =
        timeoutHandler_currentTime >= timeoutHandler_endTime;
  
      timeoutHandler_offset = duration - (
        timeoutHandler_endTime - timeoutHandler_currentTime);
  
      if (tweenable.isPlaying()) {
        if (timeoutHandler_isEnded) {
          step(targetState, tweenable._attachment, timeoutHandler_offset);
          tweenable.stop(true);
        } else {
          tweenable._scheduleId =
            schedule(tweenable._timeoutHandler, UPDATE_TIME);
  
          applyFilter(tweenable, 'beforeTween');
  
          // If the animation has not yet reached the start point (e.g., there was
          // delay that has not yet completed), just interpolate the starting
          // position of the tween.
          if (timeoutHandler_currentTime < (timestamp + delay)) {
            tweenProps(1, currentState, originalState, targetState, 1, 1, easing);
          } else {
            tweenProps(timeoutHandler_currentTime, currentState, originalState,
              targetState, duration, timestamp + delay, easing);
          }
  
          applyFilter(tweenable, 'afterTween');
  
          step(currentState, tweenable._attachment, timeoutHandler_offset);
        }
      }
    }
  
  
    /**
     * Creates a usable easing Object from a string, a function or another easing
     * Object.  If `easing` is an Object, then this function clones it and fills
     * in the missing properties with `"linear"`.
     * @param {Object.<string|Function>} fromTweenParams
     * @param {Object|string|Function} easing
     * @return {Object.<string|Function>}
     * @private
     */
    function composeEasingObject (fromTweenParams, easing) {
      var composedEasing = {};
      var typeofEasing = typeof easing;
  
      if (typeofEasing === 'string' || typeofEasing === 'function') {
        each(fromTweenParams, function (prop) {
          composedEasing[prop] = easing;
        });
      } else {
        each(fromTweenParams, function (prop) {
          if (!composedEasing[prop]) {
            composedEasing[prop] = easing[prop] || DEFAULT_EASING;
          }
        });
      }
  
      return composedEasing;
    }
  
    /**
     * Tweenable constructor.
     * @class Tweenable
     * @param {Object=} opt_initialState The values that the initial tween should
     * start at if a `from` object is not provided to `{{#crossLink
     * "Tweenable/tween:method"}}{{/crossLink}}` or `{{#crossLink
     * "Tweenable/setConfig:method"}}{{/crossLink}}`.
     * @param {Object=} opt_config Configuration object to be passed to
     * `{{#crossLink "Tweenable/setConfig:method"}}{{/crossLink}}`.
     * @module Tweenable
     * @constructor
     */
    function Tweenable (opt_initialState, opt_config) {
      this._currentState = opt_initialState || {};
      this._configured = false;
      this._scheduleFunction = DEFAULT_SCHEDULE_FUNCTION;
  
      // To prevent unnecessary calls to setConfig do not set default
      // configuration here.  Only set default configuration immediately before
      // tweening if none has been set.
      if (typeof opt_config !== 'undefined') {
        this.setConfig(opt_config);
      }
    }
  
    /**
     * Configure and start a tween.
     * @method tween
     * @param {Object=} opt_config Configuration object to be passed to
     * `{{#crossLink "Tweenable/setConfig:method"}}{{/crossLink}}`.
     * @chainable
     */
    Tweenable.prototype.tween = function (opt_config) {
      if (this._isTweening) {
        return this;
      }
  
      // Only set default config if no configuration has been set previously and
      // none is provided now.
      if (opt_config !== undefined || !this._configured) {
        this.setConfig(opt_config);
      }
  
      this._timestamp = now();
      this._start(this.get(), this._attachment);
      return this.resume();
    };
  
    /**
     * Configure a tween that will start at some point in the future.
     *
     * @method setConfig
     * @param {Object} config The following values are valid:
     * - __from__ (_Object=_): Starting position.  If omitted, `{{#crossLink
     *   "Tweenable/get:method"}}get(){{/crossLink}}` is used.
     * - __to__ (_Object=_): Ending position.
     * - __duration__ (_number=_): How many milliseconds to animate for.
     * - __delay__ (_delay=_): How many milliseconds to wait before starting the
     *   tween.
     * - __start__ (_Function(Object, *)_): Function to execute when the tween
     *   begins.  Receives the state of the tween as the first parameter and
     *   `attachment` as the second parameter.
     * - __step__ (_Function(Object, *, number)_): Function to execute on every
     *   tick.  Receives `{{#crossLink
     *   "Tweenable/get:method"}}get(){{/crossLink}}` as the first parameter,
     *   `attachment` as the second parameter, and the time elapsed since the
     *   start of the tween as the third. This function is not called on the
     *   final step of the animation, but `finish` is.
     * - __finish__ (_Function(Object, *)_): Function to execute upon tween
     *   completion.  Receives the state of the tween as the first parameter and
     *   `attachment` as the second parameter.
     * - __easing__ (_Object.<string|Function>|string|Function=_): Easing curve
     *   name(s) or function(s) to use for the tween.
     * - __attachment__ (_*_): Cached value that is passed to the
     *   `step`/`start`/`finish` methods.
     * @chainable
     */
    Tweenable.prototype.setConfig = function (config) {
      config = config || {};
      this._configured = true;
  
      // Attach something to this Tweenable instance (e.g.: a DOM element, an
      // object, a string, etc.);
      this._attachment = config.attachment;
  
      // Init the internal state
      this._pausedAtTime = null;
      this._scheduleId = null;
      this._delay = config.delay || 0;
      this._start = config.start || noop;
      this._step = config.step || noop;
      this._finish = config.finish || noop;
      this._duration = config.duration || DEFAULT_DURATION;
      this._currentState = shallowCopy({}, config.from) || this.get();
      this._originalState = this.get();
      this._targetState = shallowCopy({}, config.to) || this.get();
  
      var self = this;
      this._timeoutHandler = function () {
        timeoutHandler(self,
          self._timestamp,
          self._delay,
          self._duration,
          self._currentState,
          self._originalState,
          self._targetState,
          self._easing,
          self._step,
          self._scheduleFunction
        );
      };
  
      // Aliases used below
      var currentState = this._currentState;
      var targetState = this._targetState;
  
      // Ensure that there is always something to tween to.
      defaults(targetState, currentState);
  
      this._easing = composeEasingObject(
        currentState, config.easing || DEFAULT_EASING);
  
      this._filterArgs =
        [currentState, this._originalState, targetState, this._easing];
  
      applyFilter(this, 'tweenCreated');
      return this;
    };
  
    /**
     * @method get
     * @return {Object} The current state.
     */
    Tweenable.prototype.get = function () {
      return shallowCopy({}, this._currentState);
    };
  
    /**
     * @method set
     * @param {Object} state The current state.
     */
    Tweenable.prototype.set = function (state) {
      this._currentState = state;
    };
  
    /**
     * Pause a tween.  Paused tweens can be resumed from the point at which they
     * were paused.  This is different from `{{#crossLink
     * "Tweenable/stop:method"}}{{/crossLink}}`, as that method
     * causes a tween to start over when it is resumed.
     * @method pause
     * @chainable
     */
    Tweenable.prototype.pause = function () {
      this._pausedAtTime = now();
      this._isPaused = true;
      return this;
    };
  
    /**
     * Resume a paused tween.
     * @method resume
     * @chainable
     */
    Tweenable.prototype.resume = function () {
      if (this._isPaused) {
        this._timestamp += now() - this._pausedAtTime;
      }
  
      this._isPaused = false;
      this._isTweening = true;
  
      this._timeoutHandler();
  
      return this;
    };
  
    /**
     * Move the state of the animation to a specific point in the tween's
     * timeline.  If the animation is not running, this will cause the `step`
     * handlers to be called.
     * @method seek
     * @param {millisecond} millisecond The millisecond of the animation to seek
     * to.  This must not be less than `0`.
     * @chainable
     */
    Tweenable.prototype.seek = function (millisecond) {
      millisecond = Math.max(millisecond, 0);
      var currentTime = now();
  
      if ((this._timestamp + millisecond) === 0) {
        return this;
      }
  
      this._timestamp = currentTime - millisecond;
  
      if (!this.isPlaying()) {
        this._isTweening = true;
        this._isPaused = false;
  
        // If the animation is not running, call timeoutHandler to make sure that
        // any step handlers are run.
        timeoutHandler(this,
          this._timestamp,
          this._delay,
          this._duration,
          this._currentState,
          this._originalState,
          this._targetState,
          this._easing,
          this._step,
          this._scheduleFunction,
          currentTime
        );
  
        this.pause();
      }
  
      return this;
    };
  
    /**
     * Stops and cancels a tween.
     * @param {boolean=} gotoEnd If `false` or omitted, the tween just stops at
     * its current state, and the `finish` handler is not invoked.  If `true`,
     * the tweened object's values are instantly set to the target values, and
     * `finish` is invoked.
     * @method stop
     * @chainable
     */
    Tweenable.prototype.stop = function (gotoEnd) {
      this._isTweening = false;
      this._isPaused = false;
      this._timeoutHandler = noop;
  
      (root.cancelAnimationFrame            ||
      root.webkitCancelAnimationFrame     ||
      root.oCancelAnimationFrame          ||
      root.msCancelAnimationFrame         ||
      root.mozCancelRequestAnimationFrame ||
      root.clearTimeout)(this._scheduleId);
  
      if (gotoEnd) {
        applyFilter(this, 'beforeTween');
        tweenProps(
          1,
          this._currentState,
          this._originalState,
          this._targetState,
          1,
          0,
          this._easing
        );
        applyFilter(this, 'afterTween');
        applyFilter(this, 'afterTweenEnd');
        this._finish.call(this, this._currentState, this._attachment);
      }
  
      return this;
    };
  
    /**
     * @method isPlaying
     * @return {boolean} Whether or not a tween is running.
     */
    Tweenable.prototype.isPlaying = function () {
      return this._isTweening && !this._isPaused;
    };
  
    /**
     * Set a custom schedule function.
     *
     * If a custom function is not set,
     * [`requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/window.requestAnimationFrame)
     * is used if available, otherwise
     * [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/Window.setTimeout)
     * is used.
     * @method setScheduleFunction
     * @param {Function(Function,number)} scheduleFunction The function to be
     * used to schedule the next frame to be rendered.
     */
    Tweenable.prototype.setScheduleFunction = function (scheduleFunction) {
      this._scheduleFunction = scheduleFunction;
    };
  
    /**
     * `delete` all "own" properties.  Call this when the `Tweenable` instance
     * is no longer needed to free memory.
     * @method dispose
     */
    Tweenable.prototype.dispose = function () {
      var prop;
      for (prop in this) {
        if (this.hasOwnProperty(prop)) {
          delete this[prop];
        }
      }
    };
  
    /**
     * Filters are used for transforming the properties of a tween at various
     * points in a Tweenable's life cycle.  See the README for more info on this.
     * @private
     */
    Tweenable.prototype.filter = {};
  
    /**
     * This object contains all of the tweens available to Shifty.  It is
     * extensible - simply attach properties to the `Tweenable.prototype.formula`
     * Object following the same format as `linear`.
     *
     * `pos` should be a normalized `number` (between 0 and 1).
     * @property formula
     * @type {Object(function)}
     */
    Tweenable.prototype.formula = {
      linear: function (pos) {
        return pos;
      }
    };
  
    formula = Tweenable.prototype.formula;
  
    shallowCopy(Tweenable, {
      'now': now
      ,'each': each
      ,'tweenProps': tweenProps
      ,'tweenProp': tweenProp
      ,'applyFilter': applyFilter
      ,'shallowCopy': shallowCopy
      ,'defaults': defaults
      ,'composeEasingObject': composeEasingObject
    });
  
    // `root` is provided in the intro/outro files.
  
    // A hook used for unit testing.
    if (typeof SHIFTY_DEBUG_NOW === 'function') {
      root.timeoutHandler = timeoutHandler;
    }
  
    // Bootstrap Tweenable appropriately for the environment.
    if (typeof exports === 'object') {
      // CommonJS
      module.exports = Tweenable;
    } else if (typeof define === 'function' && define.amd) {
      // AMD
      define(function () {return Tweenable;});
    } else if (typeof root.Tweenable === 'undefined') {
      // Browser: Make `Tweenable` globally accessible.
      root.Tweenable = Tweenable;
    }
  
    return Tweenable;
  
  } ());
  