// Ease and Wizz 2.5.0 : backOut then expoIn
// Ian Haigh (http://aescripts.com/ease-and-wizz/)
// Last built: 2016-11-16T17:06:15+11:00
 
function doIt() {
	var e = new EaseAndWizz();
 
	// you can manually edit the easing types here, e.g. "e.backIn", "e.expoOut" etc
 
	var ew_one = e.backOut;	// edit this one for first two keyframes
	var ew_two = e.expoIn;	// edit this one for last two
 
	// full list of easing types for reference:
 
	// backIn, backOut, backInOut
	// bounceOut, bounceIn, bounceInOut
	// circIn, circOut, circInOut
	// elasticIn, elasticOut, elasticInOut
	// expoIn, expoOut, expoInOut
	// quadIn, quadOut, quadInOut
	// quartIn, quartOut, quartInOut
	// quintIn, quintOut, quintInOut
	// sineIn, sineOut, sineInOut
  
	var n = 0;
	if (numKeys > 0) {
		n = nearestKey(time).index;

		if (key(n).time > time) { n-- }
		if (n < 2) { easingEquation = ew_one }					
			// it's the start of the animation (keys 1 & 2)
		else if (n >= (numKeys - 1)) { easingEquation = ew_two }
			// it's the end of the animation (keys n-1 and n)
		else {return null}
			 // otherwise, just use existing easing values on the keyframes
	}

	try {
		var key1 = key(n);
		var key2 = key(n+1);
	} catch(e) {
		return null;
	}
	
	// determine how many dimensions the keyframes need
	var dim = 1; // It's gotta have at least ONE dimension
	try {
		key(1)[1];
		dim = 2;
		key(1)[2];
		dim = 3;
	} catch(e) {}

	var t = time - key1.time;
	var d = key2.time - key1.time;

	var sX = key1[0];
	var eX = key2[0] - key1[0];

	if (dim >= 2) {
		var sY = key1[1];
		var eY = key2[1] - key1[1];

		if (dim >= 3) {
			var sZ = key1[2];
			var eZ = key2[2] - key1[2];
		}
	}

	if ((time < key1.time) || (time > key2.time)) {
		return value;
	} else {
		val1 =  easingEquation(t, sX, eX, d);
		switch (dim) {
			case 1:
				 return val1;
				 break;
			case 2:
				 val2 = easingEquation(t, sY, eY, d);
				 return [val1, val2];
				 break;
			case 3:
				 val2 = easingEquation(t, sY, eY, d);
				 val3 = easingEquation(t, sZ, eZ, d);
				 return [val1, val2, val3];
				 break;
			default:
				 return null;
		}
	}
}

function EaseAndWizz() {
	// object that has all the easing functions

	// fixes for the expo glitch
	var IN_EXPO_CORRECTION		= 0.000976563;
	var OUT_EXPO_CORRECTION	= 1.000976563;

	// "back" overshoot amount
	var s = 1.70158;

	function bounceOut(t,b,c,d) {
		if ((t/=d) < (1/2.75)) { return c*(7.5625*t*t) + b }
		else if (t < (2/2.75)) { return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b }
		else if (t < (2.5/2.75)) { return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b } 
		else { return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b }
	}
	function bounceIn(t, b, c, d) {
		return c - bounceOut (d-t, 0, c, d) + b;
	}
	function bounceInOut(t, b, c, d) {
		if (t < d/2) return bounceIn (t*2, 0, c, d) * .5 + b;
		else return bounceOut (t*2-d, 0, c, d) * .5 + c*.5 + b;
	}
	this.bounceOut = bounceOut;
	this.bounceIn = bounceIn;
	this.bounceInOut = bounceInOut;

	this.backIn = function (t, b, c, d) {
		return c*(t/=d)*t*((s+1)*t - s) + b;
	}
	this.backInOut = function (t, b, c, d) {
		if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
		return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
	}
	this.backOut = function (t, b, c, d) {
		return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
	}
	this.circIn = function (t, b, c, d) {
		return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
	}
	this.circInOut = function (t, b, c, d) {
		if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
		return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
	}
	this.circOut = function (t, b, c, d) {
		return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
	}
	this.elasticIn = function (t, b, c, d) {
		var p = 0.81;		// period
		var a = 50;		// amplitude

		if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
		if (!a || a < Math.abs(c)) { a=c;  s=p/4; }
		else  s = p/(2*Math.PI) * Math.asin (c/a);
		return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
	}
	this.elasticInOut = function (t, b, c, d) {
		var p = 0.81;		// period
		var a = 50;		// amplitude

		if (t==0) return b;  if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5);
		if (!a || a < Math.abs(c)) { a=c;  s=p/4; }
		else s = p/(2*Math.PI) * Math.asin (c/a);
		if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
		return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
	}
	this.elasticOut = function (t, b, c, d) {
		var p = 0.81;		// period
		var a = 50;		// amplitude

		if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
		if (!a || a < Math.abs(c)) { a=c; s=p/4; }
		else s = p/(2*Math.PI) * Math.asin (c/a);
		return (a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b);
	}
	this.expoIn = function (t, b, c, d) {
		return t==0 ? b : c * (Math.pow(2, 10 * (t/d - 1)) - IN_EXPO_CORRECTION) + b;
	}
	this.expoInOut = function (t, b, c, d) {
		var v;
		if ((t/=d/2) < 1) {
			v = Math.pow(2, 10 * (t - 1)) - IN_EXPO_CORRECTION;
		} else {
			v = (-Math.pow(2, -10 * (t - 1)) + 2) + IN_EXPO_CORRECTION;
		}
		return b + (v/2) * c;
	}
	this.expoOut = function (t, b, c, d) {
		return (t==d) ? b+c : c * OUT_EXPO_CORRECTION * (-Math.pow(2, -10 * t/(d)) + 1) + b;
	}
	this.quadIn = function (t, b, c, d) {
		return c*(t/=d)*t + b;
	}
	this.quadInOut = function (t, b, c, d) {
		if ((t/=d/2) < 1) return c/2*t*t + b;
		return -c/2 * ((--t)*(t-2) - 1) + b;
	}
	this.quadOut = function (t, b, c, d) {
		return -c *(t/=d)*(t-2) + b;
	}
	this.quartIn = function (t, b, c, d) {
		return c*(t/=d)*t*t*t + b;
	}
	this.quartInOut = function (t, b, c, d) {
		if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
		return -c/2 * ((t-=2)*t*t*t - 2) + b;
	}
	this.quartOut = function (t, b, c, d) {
		return -c * ((t=t/d-1)*t*t*t - 1) + b;
	}
	this.quintIn = function (t, b, c, d) {
		return c*(t/=d)*t*t*t*t + b;
	}
	this.quintInOut = function (t, b, c, d) {
		if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
		return c/2*((t-=2)*t*t*t*t + 2) + b;
	}
	this.quintOut = function (t, b, c, d) {
		return c*((t=t/d-1)*t*t*t*t + 1) + b;
	}
	this.sineIn = function (t, b, c, d) {
		return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
	}
	this.sineInOut = function (t, b, c, d) {
		return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
	}
	this.sineOut = function (t, b, c, d) {
		return c * Math.sin(t/d * (Math.PI/2)) + b;
	}

}

(doIt() || value);
