'use strict';

(function () {

  var flo = function (position) {

    var floObject = {
      position: position,
      animations: {},
      requestAnimationFrame: function (func) {
        var requestAnimationFrame = window.requestAnimationFrame ||
        window.mozRequestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        window.msRequestAnimationFrame;
        requestAnimationFrame(func);
      },
      isFullscreen: function () {
        return document.fullscreenElement ||
          document.msFullscreenElement ||
          document.mozFullScreenElement ||
          document.webkitFullscreenElement;
      },
      enterFullscreen: function (element) {
        if (element.requestFullscreen) {
          element.requestFullscreen();
        } else if (element.msRequestFullscreen) {
          element.msRequestFullscreen();
        } else if (element.mozRequestFullScreen) {
          element.mozRequestFullScreen();
        } else if (element.webkitRequestFullscreen) {
          element.webkitRequestFullscreen();
        }
      },
      exitFullscreen: function () {
        if (document.exitFullscreen) {
          document.exitFullscreen();
        } else if (document.msExitFullscreen) {
          document.msExitFullscreen();
        } else if (document.mozCancelFullScreen) {
          document.mozCancelFullScreen();
        } else if (document.webkitExitFullscreen) {
          document.webkitExitFullscreen();
        }
      },
      onDocumentReady: function (func) {
        var domContentLoaded = false;
        var runFunction = function () {
          if (!domContentLoaded) {
            domContentLoaded = true;
            func();
          }
        };
        if (document.addEventListener) {
          document.addEventListener('DOMContentLoaded', runFunction, false);
        }
        if (document.attachEvent) {
          document.attachEvent('onreadystatechange', runFunction);
        }
        document.onload = runFunction;
      }
    };

    floObject.animation = function (name) {
      if (floObject.animations[name] === undefined) {
        floObject.animations[name] = {};
      }

      var animation = {
        duration: (function (name) {
          return function (time) {
            floObject.animations[name].duration = time;
            return animation;
          };
        })(name),
        nextPosition: (function (name) {
          return function (obj) {
            floObject.animations[name].nextPosition = {};
            for (var key in obj) {
              floObject.animations[name].nextPosition[key] = obj[key];
            }
            return animation;
          };
        })(name),
        previousPosition: (function (name) {
          return function (obj) {
            floObject.animations[name].previousPosition = obj;
            return animation;
          };
        })(name),
        onComplete: (function (name) {
          return function (func) {
            floObject.animations[name].onComplete = func;
            return animation;
          };
        })(name),
        invert: (function (name) {
          return function () {
            var currentAnimation = floObject.animations[name].nextPosition;
            for (var key in currentAnimation) {
              currentAnimation[key] *= -1;
            }
            return animation;
          };
        })(name),
        clear: (function (name) {
          return function (attr) {
            if (attr !== undefined) {
              floObject.animations[name][attr] = undefined;
            } else {
              floObject.animations[name] = undefined;
            }
            return animation;
          };
        })(name),
        do: (function (name) {
          return function (newName) {
            if (newName !== undefined) {
              floObject.do(newName);
            } else {
              floObject.do(name);
            }
            return animation;
          };
        })(name)
      };

      return animation;
    };

    floObject.do = function (name) {
      if (name === undefined) {
        floObject.currentAnimation = undefined;
      } else {
        floObject.startTime = new Date().getTime();
        floObject.currentAnimation = name;
        floObject.duration = floObject.animations[floObject.currentAnimation].duration;

        floObject.previousPosition = (function () {
          var key;
          var newPosition = {};
          var animation = floObject.animations[name];
          if (animation.previousPosition !== undefined) {
            for (key in floObject.position) {
              newPosition[key] = animation.previousPosition[key] !== undefined ? animation.previousPosition[key] : floObject.position[key];
            }
            return newPosition;
          }
          for (key in floObject.position) {
            newPosition[key] = floObject.position[key];
          }
          return newPosition;
        })();
      }
    };

    floObject.animate = function () {
      var multiplier = Math.min((new Date().getTime() - floObject.startTime) / floObject.duration, 1);

      if (floObject.currentAnimation) {
        var animation = floObject.animations[floObject.currentAnimation];

        for (var key in animation.nextPosition) {
          floObject.position[key] = animation.nextPosition[key] * multiplier + floObject.previousPosition[key] * (1 - multiplier);
        }

        if (multiplier === 1) {
          if (typeof animation.onComplete === 'function') {
            animation.onComplete();
          } else if (typeof animation.onComplete === 'string') {
            floObject.do(animation.onComplete);
          }
        }
      }
    };

    return floObject;
  };

  window.flo = flo;

})();

@@ -3061,32 +3061,217 @@
       %7D)(name),%0A
+        ease: (function (name) %7B%0A          return function (easing) %7B%0A            floObject.animations%5Bname%5D.ease = easing;%0A            return animation;%0A          %7D;%0A        %7D)(name),%0A
         invert: 
@@ -5192,22 +5192,86 @@
     
-var multiplier
+if (floObject.currentAnimation) %7B%0A        var multiplier;%0A        var progress
  = M
@@ -5353,174 +5353,690 @@
 1);%0A
-%0A
+  
       
-if (floObject.currentAnimation) %7B%0A        var animation = floObject.animations%5BfloObject.currentAnimation%5D;%0A%0A        for (var key in animation.nextPosition) %7B%0A
+var animation = floObject.animations%5BfloObject.currentAnimation%5D;%0A%0A        if (animation.ease === 'in') %7B%0A          multiplier = (1 - Math.cos(progress * Math.PI / 2));%0A        %7D else if (animation.ease === 'out') %7B%0A          multiplier = Math.cos((1 - progress) * Math.PI / 2);%0A        %7D else if (animation.ease === 'inout' %7C%7C animation.ease === 'both') %7B%0A          multiplier = (1 - Math.cos(progress * Math.PI)) / 2;%0A        %7D else %7B%0A          multiplier = progress;%0A        %7D%0A%0A        multiplier = Math.min(Math.max(multiplier, 0), 1);%0A%0A        for (var key in animation.nextPosition) %7B%0A          if (animation.nextPosition%5Bkey%5D !== floObject.previousPosition%5Bkey%5D) %7B%0A  
     
@@ -6162,16 +6162,28 @@
 plier);%0A
+          %7D%0A
         
@@ -6197,26 +6197,24 @@
     if (
-multiplier
+progress
  === 1) 

Implement ease method, easing & don't transform duplicate values