PageSourceSearch

https://iriver.tw/modules/gavias_sliderlayer/vendor/revolution/js/source/jquery.themepunch.tools.min.js?v=1.x

js iriver.tw collected 2026-10-07 08:14:24 UTC 380,331 bytes, 8,505 lines download raw bytes

1/********************************************
2	-	THEMEPUNCH TOOLS Ver. 1.0     -
3	 Last Update of Tools 27.02.2015
4*********************************************/
5
6
7/*
8* @fileOverview TouchSwipe - jQuery Plugin
9* @version 1.6.12
10*
11* @author Matt Bryson http://www.github.com/mattbryson
12* @see https://github.com/mattbryson/TouchSwipe-Jquery-Plugin
13* @see http://labs.rampinteractive.co.uk/touchSwipe/
14* @see http://plugins.jquery.com/project/touchSwipe
15*
16* Copyright (c) 2010-2015 Matt Bryson
17* Dual licensed under the MIT or GPL Version 2 licenses.
18*
19*/
20
21/*
22*
23* Changelog
24* $Date: 2010-12-12 (Wed, 12 Dec 2010) $
25* $version: 1.0.0
26* $version: 1.0.1 - removed multibyte comments
27*
28* $Date: 2011-21-02 (Mon, 21 Feb 2011) $
29* $version: 1.1.0 	- added allowPageScroll property to allow swiping and scrolling of page
30*					- changed handler signatures so one handler can be used for multiple events
31* $Date: 2011-23-02 (Wed, 23 Feb 2011) $
32* $version: 1.2.0 	- added click handler. This is fired if the user simply clicks and does not swipe. The event object and click target are passed to handler.
33*					- If you use the http://code.google.com/p/jquery-ui-for-ipad-and-iphone/ plugin, you can also assign jQuery mouse events to children of a touchSwipe object.
34* $version: 1.2.1 	- removed console log!
35*
36* $version: 1.2.2 	- Fixed bug where scope was not preserved in callback methods.
37*
38* $Date: 2011-28-04 (Thurs, 28 April 2011) $
39* $version: 1.2.4 	- Changed licence terms to be MIT or GPL inline with jQuery. Added check for support of touch events to stop non compatible browsers erroring.
40*
41* $Date: 2011-27-09 (Tues, 27 September 2011) $
42* $version: 1.2.5 	- Added support for testing swipes with mouse on desktop browser (thanks to https://github.com/joelhy)
43*
44* $Date: 2012-14-05 (Mon, 14 May 2012) $
45* $version: 1.2.6 	- Added timeThreshold between start and end touch, so user can ignore slow swipes (thanks to Mark Chase). Default is null, all swipes are detected
46*
47* $Date: 2012-05-06 (Tues, 05 June 2012) $
48* $version: 1.2.7 	- Changed time threshold to have null default for backwards compatibility. Added duration param passed back in events, and refactored how time is handled.
49*
50* $Date: 2012-05-06 (Tues, 05 June 2012) $
51* $version: 1.2.8 	- Added the possibility to return a value like null or false in the trigger callback. In that way we can control when the touch start/move should take effect or not (simply by returning in some cases return null; or return false;) This effects the ontouchstart/ontouchmove event.
52*
53* $Date: 2012-06-06 (Wed, 06 June 2012) $
54* $version: 1.3.0 	- Refactored whole plugin to allow for methods to be executed, as well as exposed defaults for user override. Added 'enable', 'disable', and 'destroy' methods
55*
56* $Date: 2012-05-06 (Fri, 05 June 2012) $
57* $version: 1.3.1 	- Bug fixes  - bind() with false as last argument is no longer supported in jQuery 1.6, also, if you just click, the duration is now returned correctly.
58*
59* $Date: 2012-29-07 (Sun, 29 July 2012) $
60* $version: 1.3.2	- Added fallbackToMouseEvents option to NOT capture mouse events on non touch devices.
61* 			- Added "all" fingers value to the fingers property, so any combination of fingers triggers the swipe, allowing event handlers to check the finger count
62*
63* $Date: 2012-09-08 (Thurs, 9 Aug 2012) $
64* $version: 1.3.3	- Code tidy prep for minefied version
65*
66* $Date: 2012-04-10 (wed, 4 Oct 2012) $
67* $version: 1.4.0	- Added pinch support, pinchIn and pinchOut
68*
69* $Date: 2012-11-10 (Thurs, 11 Oct 2012) $
70* $version: 1.5.0	- Added excludedElements, a jquery selector that specifies child elements that do NOT trigger swipes. By default, this is one select that removes all form, input select, button and anchor elements.
71*
72* $Date: 2012-22-10 (Mon, 22 Oct 2012) $
73* $version: 1.5.1	- Fixed bug with jQuery 1.8 and trailing comma in excludedElements
74*					- Fixed bug with IE and eventPreventDefault()
75* $Date: 2013-01-12 (Fri, 12 Jan 2013) $
76* $version: 1.6.0	- Fixed bugs with pinching, mainly when both pinch and swipe enabled, as well as adding time threshold for multifinger gestures, so releasing one finger beofre the other doesnt trigger as single finger gesture.
77*					- made the demo site all static local HTML pages so they can be run locally by a developer
78*					- added jsDoc comments and added documentation for the plugin	
79*					- code tidy
80*					- added triggerOnTouchLeave property that will end the event when the user swipes off the element.
81* $Date: 2013-03-23 (Sat, 23 Mar 2013) $
82* $version: 1.6.1	- Added support for ie8 touch events
83* $version: 1.6.2	- Added support for events binding with on / off / bind in jQ for all callback names.
84*                   - Deprecated the 'click' handler in favour of tap.
85*                   - added cancelThreshold property
86*                   - added option method to update init options at runtime
87* $version 1.6.3    - added doubletap, longtap events and longTapThreshold, doubleTapThreshold property
88*
89* $Date: 2013-04-04 (Thurs, 04 April 2013) $
90* $version 1.6.4    - Fixed bug with cancelThreshold introduced in 1.6.3, where swipe status no longer fired start event, and stopped once swiping back.
91*
92* $Date: 2013-08-24 (Sat, 24 Aug 2013) $
93* $version 1.6.5    - Merged a few pull requests fixing various bugs, added AMD support.
94*
95* $Date: 2014-06-04 (Wed, 04 June 2014) $
96* $version 1.6.6 	- Merge of pull requests.
97*    				- IE10 touch support 
98*    				- Only prevent default event handling on valid swipe
99*    				- Separate license/changelog comment
100*    				- Detect if the swipe is valid at the end of the touch event.
101*    				- Pass fingerdata to event handlers. 
102*    				- Add 'hold' gesture 
103*    				- Be more tolerant about the tap distance
104*    				- Typos and minor fixes
105*
106* $Date: 2015-22-01 (Thurs, 22 Jan 2015) $
107* $version 1.6.7    - Added patch from https://github.com/mattbryson/TouchSwipe-Jquery-Plugin/issues/206 to fix memory leak
108*
109* $Date: 2015-2-2 (Mon, 2 Feb 2015) $
110* $version 1.6.8    - Added preventDefaultEvents option to proxy events regardless.
111*					- Fixed issue with swipe and pinch not triggering at the same time
112*
113* $Date: 2015-9-6 (Tues, 9 June 2015) $
114* $version 1.6.9    - Added PR from jdalton/hybrid to fix pointer events
115*					- Added scrolling demo
116*					- Added version property to plugin
117*
118* $Date: 2015-1-10 (Wed, 1 October 2015) $
119* $version 1.6.10    - Added PR from beatspace to fix tap events
120* $version 1.6.11    - Added PRs from indri-indri ( Doc tidyup), kkirsche ( Bower tidy up ), UziTech (preventDefaultEvents fixes )
121*					 - Allowed setting multiple options via .swipe("options", options_hash) and more simply .swipe(options_hash) or exisitng instances 				
122* $version 1.6.12    - Fixed bug with multi finger releases above 2 not triggering events
123*/
124
125/**
126 * See (http://jquery.com/).
127 * @name $
128 * @class 
129 * See the jQuery Library  (http://jquery.com/) for full details.  This just
130 * documents the function and classes that are added to jQuery by this plug-in.
131 */
132 
133/**
134 * See (http://jquery.com/)
135 * @name fn
136 * @class 
137 * See the jQuery Library  (http://jquery.com/) for full details.  This just
138 * documents the function and classes that are added to jQuery by this plug-in.
139 * @memberOf $
140 */
141
142
143
144(function (factory) {
145    if (typeof define === 'function' && define.amd && define.amd.jQuery) {
146        // AMD. Register as anonymous module.
147        define(['jquery'], factory);
148    } else {
149        // Browser globals.
150        factory(jQuery);
151    }
152}(function ($) {
153	"use strict";
154
155	//Constants
156	var VERSION = "1.6.12",
157		LEFT = "left",
158		RIGHT = "right",
159		UP = "up",
160		DOWN = "down",
161		IN = "in",
162		OUT = "out",
163
164		NONE = "none",
165		AUTO = "auto",
166		
167		SWIPE = "swipe",
168		PINCH = "pinch",
169		TAP = "tap",
170		DOUBLE_TAP = "doubletap",
171		LONG_TAP = "longtap",
172		HOLD = "hold",
173		
174		HORIZONTAL = "horizontal",
175		VERTICAL = "vertical",
176
177		ALL_FINGERS = "all",
178		
179		DOUBLE_TAP_THRESHOLD = 10,
180
181		PHASE_START = "start",
182		PHASE_MOVE = "move",
183		PHASE_END = "end",
184		PHASE_CANCEL = "cancel",
185
186		SUPPORTS_TOUCH = 'ontouchstart' in window,
187		
188		SUPPORTS_POINTER_IE10 = window.navigator.msPointerEnabled && !window.navigator.pointerEnabled,
189		
190		SUPPORTS_POINTER = window.navigator.pointerEnabled || window.navigator.msPointerEnabled,
191
192		PLUGIN_NS = 'TouchSwipe';
193
194
195
196	/**
197	* The default configuration, and available options to configure touch swipe with.
198	* You can set the default values by updating any of the properties prior to instantiation.
199	* @name $.fn.swipe.defaults
200	* @namespace
201	* @property {int} [fingers=1] The number of fingers to detect in a swipe. Any swipes that do not meet this requirement will NOT trigger swipe handlers.
202	* @property {int} [threshold=75] The number of pixels that the user must move their finger by before it is considered a swipe. 
203	* @property {int} [cancelThreshold=null] The number of pixels that the user must move their finger back from the original swipe direction to cancel the gesture.
204	* @property {int} [pinchThreshold=20] The number of pixels that the user must pinch their finger by before it is considered a pinch. 
205	* @property {int} [maxTimeThreshold=null] Time, in milliseconds, between touchStart and touchEnd must NOT exceed in order to be considered a swipe. 
206	* @property {int} [fingerReleaseThreshold=250] Time in milliseconds between releasing multiple fingers.  If 2 fingers are down, and are released one after the other, if they are within this threshold, it counts as a simultaneous release. 
207	* @property {int} [longTapThreshold=500] Time in milliseconds between tap and release for a long tap
208	* @property {int} [doubleTapThreshold=200] Time in milliseconds between 2 taps to count as a double tap
209	* @property {function} [swipe=null] A handler to catch all swipes. See {@link $.fn.swipe#event:swipe}
210	* @property {function} [swipeLeft=null] A handler that is triggered for "left" swipes. See {@link $.fn.swipe#event:swipeLeft}
211	* @property {function} [swipeRight=null] A handler that is triggered for "right" swipes. See {@link $.fn.swipe#event:swipeRight}
212	* @property {function} [swipeUp=null] A handler that is triggered for "up" swipes. See {@link $.fn.swipe#event:swipeUp}
213	* @property {function} [swipeDown=null] A handler that is triggered for "down" swipes. See {@link $.fn.swipe#event:swipeDown}
214	* @property {function} [swipeStatus=null] A handler triggered for every phase of the swipe. See {@link $.fn.swipe#event:swipeStatus}
215	* @property {function} [pinchIn=null] A handler triggered for pinch in events. See {@link $.fn.swipe#event:pinchIn}
216	* @property {function} [pinchOut=null] A handler triggered for pinch out events. See {@link $.fn.swipe#event:pinchOut}
217	* @property {function} [pinchStatus=null] A handler triggered for every phase of a pinch. See {@link $.fn.swipe#event:pinchStatus}
218	* @property {function} [tap=null] A handler triggered when a user just taps on the item, rather than swipes it. If they do not move, tap is triggered, if they do move, it is not. 
219	* @property {function} [doubleTap=null] A handler triggered when a user double taps on the item. The delay between taps can be set with the doubleTapThreshold property. See {@link $.fn.swipe.defaults#doubleTapThreshold}
220	* @property {function} [longTap=null] A handler triggered when a user long taps on the item. The delay between start and end can be set with the longTapThreshold property. See {@link $.fn.swipe.defaults#longTapThreshold}
221	* @property (function) [hold=null] A handler triggered when a user reaches longTapThreshold on the item. See {@link $.fn.swipe.defaults#longTapThreshold}
222	* @property {boolean} [triggerOnTouchEnd=true] If true, the swipe events are triggered when the touch end event is received (user releases finger).  If false, it will be triggered on reaching the threshold, and then cancel the touch event automatically. 
223	* @property {boolean} [triggerOnTouchLeave=false] If true, then when the user leaves the swipe object, the swipe will end and trigger appropriate handlers. 
224	* @property {string|undefined} [allowPageScroll='auto'] How the browser handles page scrolls when the user is swiping on a touchSwipe object. See {@link $.fn.swipe.pageScroll}.  <br/><br/>
225										<code>"auto"</code> : all undefined swipes will cause the page to scroll in that direction. <br/>
226										<code>"none"</code> : the page will not scroll when user swipes. <br/>
227										<code>"horizontal"</code> : will force page to scroll on horizontal swipes. <br/>
228										<code>"vertical"</code> : will force page to scroll on vertical swipes. <br/>
229	* @property {boolean} [fallbackToMouseEvents=true] If true mouse events are used when run on a non touch device, false will stop swipes being triggered by mouse events on non tocuh devices. 
230	* @property {string} [excludedElements="button, input, select, textarea, a, .noSwipe"] A jquery selector that specifies child elements that do NOT trigger swipes. By default this excludes all form, input, select, button, anchor and .noSwipe elements. 
231	* @property {boolean} [preventDefaultEvents=true] by default default events are cancelled, so the page doesn't move.  You can dissable this so both native events fire as well as your handlers. 
232	
233	*/
234	var defaults = {
235		fingers: 1, 		
236		threshold: 75, 	
237		cancelThreshold:null,	
238		pinchThreshold:20,
239		maxTimeThreshold: null, 
240		fingerReleaseThreshold:250, 
241		longTapThreshold:500,
242		doubleTapThreshold:200,
243		swipe: null, 		
244		swipeLeft: null, 	
245		swipeRight: null, 	
246		swipeUp: null, 		
247		swipeDown: null, 	
248		swipeStatus: null, 	
249		pinchIn:null,		
250		pinchOut:null,		
251		pinchStatus:null,	
252		click:null, //Deprecated since 1.6.2
253		tap:null,
254		doubleTap:null,
255		longTap:null, 		
256		hold:null, 
257		triggerOnTouchEnd: true, 
258		triggerOnTouchLeave:false, 
259		allowPageScroll: "auto", 
260		fallbackToMouseEvents: true,	
261		excludedElements:"label, button, input, select, textarea, a, .noSwipe",
262		preventDefaultEvents:true
263	};
264
265
266
267	/**
268	* Applies TouchSwipe behaviour to one or more jQuery objects.
269	* The TouchSwipe plugin can be instantiated via this method, or methods within 
270	* TouchSwipe can be executed via this method as per jQuery plugin architecture.
271	* An existing plugin can have its options changed simply by re calling .swipe(options)
272	* @see TouchSwipe
273	* @class
274	* @param {Mixed} method If the current DOMNode is a TouchSwipe object, and <code>method</code> is a TouchSwipe method, then
275	* the <code>method</code> is executed, and any following arguments are passed to the TouchSwipe method.
276	* If <code>method</code> is an object, then the TouchSwipe class is instantiated on the current DOMNode, passing the 
277	* configuration properties defined in the object. See TouchSwipe
278	*
279	*/
280	$.fn.swipe = function (method) {
281		var $this = $(this),
282			plugin = $this.data(PLUGIN_NS);
283
284		//Check if we are already instantiated and trying to execute a method	
285		if (plugin && typeof method === 'string') {
286			if (plugin[method]) {
287				return plugin[method].apply(this, Array.prototype.slice.call(arguments, 1));
288			} else {
289				$.error('Method ' + method + ' does not exist on jQuery.swipe');
290			}
291		}
292
293		//Else update existing plugin with new options hash
294		else if (plugin && typeof method === 'object') {
295			plugin['option'].apply(this, arguments);
296		}
297
298		//Else not instantiated and trying to pass init object (or nothing)
299		else if (!plugin && (typeof method === 'object' || !method)) {
300			return init.apply(this, arguments);
301		} 
302
303		return $this;
304	};
305	
306	/**
307	 * The version of the plugin
308	 * @readonly
309	 */
310	$.fn.swipe.version = VERSION;
311
312
313
314	//Expose our defaults so a user could override the plugin defaults
315	$.fn.swipe.defaults = defaults;
316
317	/**
318	* The phases that a touch event goes through.  The <code>phase</code> is passed to the event handlers. 
319	* These properties are read only, attempting to change them will not alter the values passed to the event handlers.
320	* @namespace
321	* @readonly
322	* @property {string} PHASE_START Constant indicating the start phase of the touch event. Value is <code>"start"</code>.
323	* @property {string} PHASE_MOVE Constant indicating the move phase of the touch event. Value is <code>"move"</code>.
324	* @property {string} PHASE_END Constant indicating the end phase of the touch event. Value is <code>"end"</code>.
325	* @property {string} PHASE_CANCEL Constant indicating the cancel phase of the touch event. Value is <code>"cancel"</code>.
326	*/
327	$.fn.swipe.phases = {
328		PHASE_START: PHASE_START,
329		PHASE_MOVE: PHASE_MOVE,
330		PHASE_END: PHASE_END,
331		PHASE_CANCEL: PHASE_CANCEL
332	};
333
334	/**
335	* The direction constants that are passed to the event handlers. 
336	* These properties are read only, attempting to change them will not alter the values passed to the event handlers.
337	* @namespace
338	* @readonly
339	* @property {string} LEFT Constant indicating the left direction. Value is <code>"left"</code>.
340	* @property {string} RIGHT Constant indicating the right direction. Value is <code>"right"</code>.
341	* @property {string} UP Constant indicating the up direction. Value is <code>"up"</code>.
342	* @property {string} DOWN Constant indicating the down direction. Value is <code>"cancel"</code>.
343	* @property {string} IN Constant indicating the in direction. Value is <code>"in"</code>.
344	* @property {string} OUT Constant indicating the out direction. Value is <code>"out"</code>.
345	*/
346	$.fn.swipe.directions = {
347		LEFT: LEFT,
348		RIGHT: RIGHT,
349		UP: UP,
350		DOWN: DOWN,
351		IN : IN,
352		OUT: OUT
353	};
354	
355	/**
356	* The page scroll constants that can be used to set the value of <code>allowPageScroll</code> option
357	* These properties are read only
358	* @namespace
359	* @readonly
360	* @see $.fn.swipe.defaults#allowPageScroll
361	* @property {string} NONE Constant indicating no page scrolling is allowed. Value is <code>"none"</code>.
362	* @property {string} HORIZONTAL Constant indicating horizontal page scrolling is allowed. Value is <code>"horizontal"</code>.
363	* @property {string} VERTICAL Constant indicating vertical page scrolling is allowed. Value is <code>"vertical"</code>.
364	* @property {string} AUTO Constant indicating either horizontal or vertical will be allowed, depending on the swipe handlers registered. Value is <code>"auto"</code>.
365	*/
366	$.fn.swipe.pageScroll = {
367		NONE: NONE,
368		HORIZONTAL: HORIZONTAL,
369		VERTICAL: VERTICAL,
370		AUTO: AUTO
371	};
372
373	/**
374	* Constants representing the number of fingers used in a swipe.  These are used to set both the value of <code>fingers</code> in the 
375	* options object, as well as the value of the <code>fingers</code> event property.
376	* These properties are read only, attempting to change them will not alter the values passed to the event handlers.
377	* @namespace
378	* @readonly
379	* @see $.fn.swipe.defaults#fingers
380	* @property {string} ONE Constant indicating 1 finger is to be detected / was detected. Value is <code>1</code>.
381	* @property {string} TWO Constant indicating 2 fingers are to be detected / were detected. Value is <code>2</code>.
382	* @property {string} THREE Constant indicating 3 finger are to be detected / were detected. Value is <code>3</code>.
383	* @property {string} FOUR Constant indicating 4 finger are to be detected / were detected. Not all devices support this. Value is <code>4</code>.
384	* @property {string} FIVE Constant indicating 5 finger are to be detected / were detected. Not all devices support this. Value is <code>5</code>.
385	* @property {string} ALL Constant indicating any combination of finger are to be detected.  Value is <code>"all"</code>.
386	*/
387	$.fn.swipe.fingers = {
388		ONE: 1,
389		TWO: 2,
390		THREE: 3,
391		FOUR: 4,
392		FIVE: 5,
393		ALL: ALL_FINGERS
394	};
395
396	/**
397	* Initialise the plugin for each DOM element matched
vendor: 18,166 bytes, lines 398-938
398	* This creates a new instance of the main TouchSwipe class for each DOM element, and then
399	* saves a reference to that instance in the elements data property.
400	* @internal
401	*/
402	function init(options) {
403		//Prep and extend the options
404		if (options && (options.allowPageScroll === undefined && (options.swipe !== undefined || options.swipeStatus !== undefined))) {
405			options.allowPageScroll = NONE;
406		}
407		
408        //Check for deprecated options
409		//Ensure that any old click handlers are assigned to the new tap, unless we have a tap
410		if(options.click!==undefined && options.tap===undefined) {
411		    options.tap = options.click;
412		}
413
414		if (!options) {
415			options = {};
416		}
417		
418        //pass empty object so we dont modify the defaults
419		options = $.extend({}, $.fn.swipe.defaults, options);
420
421		//For each element instantiate the plugin
422		return this.each(function () {
423			var $this = $(this);
424
425			//Check we havent already initialised the plugin
426			var plugin = $this.data(PLUGIN_NS);
427
428			if (!plugin) {
429				plugin = new TouchSwipe(this, options);
430				$this.data(PLUGIN_NS, plugin);
431			}
432		});
433	}
434
435	/**
436	* Main TouchSwipe Plugin Class.
437	* Do not use this to construct your TouchSwipe object, use the jQuery plugin method $.fn.swipe(); {@link $.fn.swipe}
438	* @private
439	* @name TouchSwipe
440	* @param {DOMNode} element The HTML DOM object to apply to plugin to
441	* @param {Object} options The options to configure the plugin with.  @link {$.fn.swipe.defaults}
442	* @see $.fh.swipe.defaults
443	* @see $.fh.swipe
444    * @class
445	*/
446	function TouchSwipe(element, options) {
447
448		//take a local/instacne level copy of the options - should make it this.options really...
449		var options = $.extend({}, options);
450
451		var useTouchEvents = (SUPPORTS_TOUCH || SUPPORTS_POINTER || !options.fallbackToMouseEvents),
452            START_EV = useTouchEvents ? (SUPPORTS_POINTER ? (SUPPORTS_POINTER_IE10 ? 'MSPointerDown' : 'pointerdown') : 'touchstart') : 'mousedown',
453            MOVE_EV = useTouchEvents ? (SUPPORTS_POINTER ? (SUPPORTS_POINTER_IE10 ? 'MSPointerMove' : 'pointermove') : 'touchmove') : 'mousemove',
454            END_EV = useTouchEvents ? (SUPPORTS_POINTER ? (SUPPORTS_POINTER_IE10 ? 'MSPointerUp' : 'pointerup') : 'touchend') : 'mouseup',
455            LEAVE_EV = useTouchEvents ? null : 'mouseleave', //we manually detect leave on touch devices, so null event here
456            CANCEL_EV = (SUPPORTS_POINTER ? (SUPPORTS_POINTER_IE10 ? 'MSPointerCancel' : 'pointercancel') : 'touchcancel');
457
458
459
460		//touch properties
461		var distance = 0,
462			direction = null,
463			duration = 0,
464			startTouchesDistance = 0,
465			endTouchesDistance = 0,
466			pinchZoom = 1,
467			pinchDistance = 0,
468			pinchDirection = 0,
469			maximumsMap=null;
470
471		
472		
473		//jQuery wrapped element for this instance
474		var $element = $(element);
475		
476		//Current phase of th touch cycle
477		var phase = "start";
478
479		// the current number of fingers being used.
480		var fingerCount = 0; 			
481
482		//track mouse points / delta
483		var fingerData = {};
484
485		//track times
486		var startTime = 0,
487			endTime = 0,
488			previousTouchEndTime=0,
489			fingerCountAtRelease=0,
490			doubleTapStartTime=0;
491
492		//Timeouts
493		var singleTapTimeout=null,
494			holdTimeout=null;
495        
496		// Add gestures to all swipable areas if supported
497		try {
498			$element.bind(START_EV, touchStart);
499			$element.bind(CANCEL_EV, touchCancel);
500		}
501		catch (e) {
502			$.error('events not supported ' + START_EV + ',' + CANCEL_EV + ' on jQuery.swipe');
503		}
504
505		//
506		//Public methods
507		//
508		
509		/**
510		* re-enables the swipe plugin with the previous configuration
511		* @function
512		* @name $.fn.swipe#enable
513		* @return {DOMNode} The Dom element that was registered with TouchSwipe 
514		* @example $("#element").swipe("enable");
515		*/
516		this.enable = function () {
517			$element.bind(START_EV, touchStart);
518			$element.bind(CANCEL_EV, touchCancel);
519			return $element;
520		};
521
522		/**
523		* disables the swipe plugin
524		* @function
525		* @name $.fn.swipe#disable
526		* @return {DOMNode} The Dom element that is now registered with TouchSwipe
527	    * @example $("#element").swipe("disable");
528		*/
529		this.disable = function () {
530			removeListeners();
531			return $element;
532		};
533
534		/**
535		* Destroy the swipe plugin completely. To use any swipe methods, you must re initialise the plugin.
536		* @function
537		* @name $.fn.swipe#destroy
538		* @example $("#element").swipe("destroy");
539		*/
540		this.destroy = function () {
541			removeListeners();
542			$element.data(PLUGIN_NS, null);
543			$element = null;
544		};
545
546		
547        /**
548         * Allows run time updating of the swipe configuration options.
549         * @function
550    	 * @name $.fn.swipe#option
551    	 * @param {String} property The option property to get or set, or a has of multiple options to set
552         * @param {Object} [value] The value to set the property to
553		 * @return {Object} If only a property name is passed, then that property value is returned. If nothing is passed the current options hash is returned.
554		 * @example $("#element").swipe("option", "threshold"); // return the threshold
555         * @example $("#element").swipe("option", "threshold", 100); // set the threshold after init
556         * @example $("#element").swipe("option", {threshold:100, fingers:3} ); // set multiple properties after init
557         * @example $("#element").swipe({threshold:100, fingers:3} ); // set multiple properties after init - the "option" method is optional!
558         * @example $("#element").swipe("option"); // Return the current options hash
559         * @see $.fn.swipe.defaults
560         *
561         */
562        this.option = function (property, value) {
563			
564			if(typeof property === 'object') {
565        		options = $.extend(options, property);
566        	} else if(options[property]!==undefined) {
567                if(value===undefined) {
568                    return options[property];
569                } else {
570                    options[property] = value;
571                }
572            } else if (!property) {
573            	return options;   
574            } else {
575                $.error('Option ' + property + ' does not exist on jQuery.swipe.options');
576            }
577
578            return null;
579        }
580
581       
582
583		//
584		// Private methods
585		//
586		
587		//
588		// EVENTS
589		//
590		/**
591		* Event handler for a touch start event.
592		* Stops the default click event from triggering and stores where we touched
593		* @inner
594		* @param {object} jqEvent The normalised jQuery event object.
595		*/
596		function touchStart(jqEvent) {
597
598			//If we already in a touch event (a finger already in use) then ignore subsequent ones..
599			if( getTouchInProgress() )
600				return;
601			
602			//Check if this element matches any in the excluded elements selectors,  or its parent is excluded, if so, DON'T swipe
603			if( $(jqEvent.target).closest( options.excludedElements, $element ).length>0 ) 
604				return;
605				
606			//As we use Jquery bind for events, we need to target the original event object
607			//If these events are being programmatically triggered, we don't have an original event object, so use the Jq one.
608			var event = jqEvent.originalEvent ? jqEvent.originalEvent : jqEvent;
609			
610			var ret,
611				touches = event.touches,
612				evt = touches ? touches[0] : event;
613
614			phase = PHASE_START;
615
616			//If we support touches, get the finger count
617			if (touches) {
618				// get the total number of fingers touching the screen
619				fingerCount = touches.length;
620			}
621			//Else this is the desktop, so stop the browser from dragging content
622			else if(options.preventDefaultEvents !== false) {
623				jqEvent.preventDefault(); //call this on jq event so we are cross browser
624			}
625
626			//clear vars..
627			distance = 0;
628			direction = null;
629			pinchDirection=null;
630			duration = 0;
631			startTouchesDistance=0;
632			endTouchesDistance=0;
633			pinchZoom = 1;
634			pinchDistance = 0;
635			maximumsMap=createMaximumsData();
636			cancelMultiFingerRelease();
637
638			//Create the default finger data
639			createFingerData( 0, evt );
640
641			// check the number of fingers is what we are looking for, or we are capturing pinches
642			if (!touches || (fingerCount === options.fingers || options.fingers === ALL_FINGERS) || hasPinches()) {
643				// get the coordinates of the touch
644				startTime = getTimeStamp();
645				
646				if(fingerCount==2) {
647					//Keep track of the initial pinch distance, so we can calculate the diff later
648					//Store second finger data as start
649					createFingerData( 1, touches[1] );
650					startTouchesDistance = endTouchesDistance = calculateTouchesDistance(fingerData[0].start, fingerData[1].start);
651				}
652				
653				if (options.swipeStatus || options.pinchStatus) {
654					ret = triggerHandler(event, phase);
655				}
656			}
657			else {
658				//A touch with more or less than the fingers we are looking for, so cancel
659				ret = false; 
660			}
661
662			//If we have a return value from the users handler, then return and cancel
663			if (ret === false) {
664				phase = PHASE_CANCEL;
665				triggerHandler(event, phase);
666				return ret;
667			}
668			else {
669				if (options.hold) {
670					holdTimeout = setTimeout($.proxy(function() {
671						//Trigger the event
672						$element.trigger('hold', [event.target]);
673						//Fire the callback
674						if(options.hold) {
675							ret = options.hold.call($element, event, event.target);
676						}
677					}, this), options.longTapThreshold );
678				}
679
680				setTouchInProgress(true);
681			}
682
683            return null;
684		};
685		
686		
687		
688		/**
689		* Event handler for a touch move event. 
690		* If we change fingers during move, then cancel the event
691		* @inner
692		* @param {object} jqEvent The normalised jQuery event object.
693		*/
694		function touchMove(jqEvent) {
695			
696			//As we use Jquery bind for events, we need to target the original event object
697			//If these events are being programmatically triggered, we don't have an original event object, so use the Jq one.
698			var event = jqEvent.originalEvent ? jqEvent.originalEvent : jqEvent;
699			
700			//If we are ending, cancelling, or within the threshold of 2 fingers being released, don't track anything..
701			if (phase === PHASE_END || phase === PHASE_CANCEL || inMultiFingerRelease())
702				return;
703
704			var ret,
705				touches = event.touches,
706				evt = touches ? touches[0] : event;
707			
708
709			//Update the  finger data 
710			var currentFinger = updateFingerData(evt);
711			endTime = getTimeStamp();
712			
713			if (touches) {
714				fingerCount = touches.length;
715			}
716
717			if (options.hold)
718				clearTimeout(holdTimeout);
719
720			phase = PHASE_MOVE;
721
722			//If we have 2 fingers get Touches distance as well
723			if(fingerCount==2) {
724				
725				//Keep track of the initial pinch distance, so we can calculate the diff later
726				//We do this here as well as the start event, in case they start with 1 finger, and the press 2 fingers
727				if(startTouchesDistance==0) {
728					//Create second finger if this is the first time...
729					createFingerData( 1, touches[1] );
730					
731					startTouchesDistance = endTouchesDistance = calculateTouchesDistance(fingerData[0].start, fingerData[1].start);
732				} else {
733					//Else just update the second finger
734					updateFingerData(touches[1]);
735				
736					endTouchesDistance = calculateTouchesDistance(fingerData[0].end, fingerData[1].end);
737					pinchDirection = calculatePinchDirection(fingerData[0].end, fingerData[1].end);
738				}
739				
740				
741				pinchZoom = calculatePinchZoom(startTouchesDistance, endTouchesDistance);
742				pinchDistance = Math.abs(startTouchesDistance - endTouchesDistance);
743			}
744			
745			
746			
747
748			if ( (fingerCount === options.fingers || options.fingers === ALL_FINGERS) || !touches || hasPinches() ) {
749				
750				direction = calculateDirection(currentFinger.start, currentFinger.end);
751				
752				//Check if we need to prevent default event (page scroll / pinch zoom) or not
753				validateDefaultEvent(jqEvent, direction);
754
755				//Distance and duration are all off the main finger
756				distance = calculateDistance(currentFinger.start, currentFinger.end);
757				duration = calculateDuration();
758
759                //Cache the maximum distance we made in this direction
760                setMaxDistance(direction, distance);
761
762
763				if (options.swipeStatus || options.pinchStatus) {
764					ret = triggerHandler(event, phase);
765				}
766				
767				
768				//If we trigger end events when threshold are met, or trigger events when touch leaves element
769				if(!options.triggerOnTouchEnd || options.triggerOnTouchLeave) {
770					
771					var inBounds = true;
772					
773					//If checking if we leave the element, run the bounds check (we can use touchleave as its not supported on webkit)
774					if(options.triggerOnTouchLeave) {
775						var bounds = getbounds( this );
776						inBounds = isInBounds( currentFinger.end, bounds );
777					}
778					
779					//Trigger end handles as we swipe if thresholds met or if we have left the element if the user has asked to check these..
780					if(!options.triggerOnTouchEnd && inBounds) {
781						phase = getNextPhase( PHASE_MOVE );
782					} 
783					//We end if out of bounds here, so set current phase to END, and check if its modified 
784					else if(options.triggerOnTouchLeave && !inBounds ) {
785						phase = getNextPhase( PHASE_END );
786					}
787						
788					if(phase==PHASE_CANCEL || phase==PHASE_END)	{
789						triggerHandler(event, phase);
790					}				
791				}
792			}
793			else {
794				phase = PHASE_CANCEL;
795				triggerHandler(event, phase);
796			}
797
798			if (ret === false) {
799				phase = PHASE_CANCEL;
800				triggerHandler(event, phase);
801			}
802		}
803
804
805
806
807		/**
808		* Event handler for a touch end event. 
809		* Calculate the direction and trigger events
810		* @inner
811		* @param {object} jqEvent The normalised jQuery event object.
812		*/
813		function touchEnd(jqEvent) {
814			//As we use Jquery bind for events, we need to target the original event object
815			//If these events are being programmatically triggered, we don't have an original event object, so use the Jq one.
816			var event = jqEvent.originalEvent ? jqEvent.originalEvent : jqEvent,
817			    touches = event.touches;
818
819			//If we are still in a touch with the device wait a fraction and see if the other finger comes up
820			//if it does within the threshold, then we treat it as a multi release, not a single release and end the touch / swipe
821			if (touches) {
822				if(touches.length && !inMultiFingerRelease()) {
823					startMultiFingerRelease();
824					return true;
825				} else if (touches.length && inMultiFingerRelease()) {
826					return true;
827				}
828			}
829
830			//If a previous finger has been released, check how long ago, if within the threshold, then assume it was a multifinger release.
831			//This is used to allow 2 fingers to release fractionally after each other, whilst maintainig the event as containg 2 fingers, not 1
832			if(inMultiFingerRelease()) {	
833				fingerCount=fingerCountAtRelease;
834			}	
835
836			//Set end of swipe
837			endTime = getTimeStamp();
838			
839			//Get duration incase move was never fired
840			duration = calculateDuration();
841			
842			//If we trigger handlers at end of swipe OR, we trigger during, but they didnt trigger and we are still in the move phase
843			if(didSwipeBackToCancel() || !validateSwipeDistance()) {
844			    phase = PHASE_CANCEL;
845                triggerHandler(event, phase);
846			} else if (options.triggerOnTouchEnd || (options.triggerOnTouchEnd == false && phase === PHASE_MOVE)) {
847				//call this on jq event so we are cross browser 
848				if(options.preventDefaultEvents !== false) {
849					jqEvent.preventDefault(); 
850				}
851				phase = PHASE_END;
852                triggerHandler(event, phase);
853			}
854			//Special cases - A tap should always fire on touch end regardless,
855			//So here we manually trigger the tap end handler by itself
856			//We dont run trigger handler as it will re-trigger events that may have fired already
857			else if (!options.triggerOnTouchEnd && hasTap()) {
858                //Trigger the pinch events...
859			    phase = PHASE_END;
860			    triggerHandlerForGesture(event, phase, TAP);
861			}
862			else if (phase === PHASE_MOVE) {
863				phase = PHASE_CANCEL;
864				triggerHandler(event, phase);
865			}
866
867			setTouchInProgress(false);
868
869            return null;
870		}
871
872
873
874		/**
875		* Event handler for a touch cancel event. 
876		* Clears current vars
877		* @inner
878		*/
879		function touchCancel() {
880			// reset the variables back to default values
881			fingerCount = 0;
882			endTime = 0;
883			startTime = 0;
884			startTouchesDistance=0;
885			endTouchesDistance=0;
886			pinchZoom=1;
887			
888			//If we were in progress of tracking a possible multi touch end, then re set it.
889			cancelMultiFingerRelease();
890			
891			setTouchInProgress(false);
892		}
893		
894		
895		/**
896		* Event handler for a touch leave event. 
897		* This is only triggered on desktops, in touch we work this out manually
898		* as the touchleave event is not supported in webkit
899		* @inner
900		*/
901		function touchLeave(jqEvent) {
902			//If these events are being programmatically triggered, we don't have an original event object, so use the Jq one.
903			var event = jqEvent.originalEvent ? jqEvent.originalEvent : jqEvent;
904			
905			//If we have the trigger on leave property set....
906			if(options.triggerOnTouchLeave) {
907				phase = getNextPhase( PHASE_END );
908				triggerHandler(event, phase);
909			}
910		}
911		
912		/**
913		* Removes all listeners that were associated with the plugin
914		* @inner
915		*/
916		function removeListeners() {
917			$element.unbind(START_EV, touchStart);
918			$element.unbind(CANCEL_EV, touchCancel);
919			$element.unbind(MOVE_EV, touchMove);
920			$element.unbind(END_EV, touchEnd);
921			
922			//we only have leave events on desktop, we manually calculate leave on touch as its not supported in webkit
923			if(LEAVE_EV) { 
924				$element.unbind(LEAVE_EV, touchLeave);
925			}
926			
927			setTouchInProgress(false);
928		}
929
930		
931		/**
932		 * Checks if the time and distance thresholds have been met, and if so then the appropriate handlers are fired.
933		 */
934		function getNextPhase(currentPhase) {
935			
936			var nextPhase = currentPhase;
937			
938			// Ensure we have valid swipe (under time and over distance  and check if we are out of bound...)
939			var validTime = validateSwipeTime();
940			var validDistance = validateSwipeDistance();
941			var didCancel = didSwipeBackToCancel();
942						
943			//If we have exceeded our time, then cancel	
944			if(!validTime || didCancel) {
945				nextPhase = PHASE_CANCEL;
946			}
947			//Else if we are moving, and have reached distance then end
948			else if (validDistance && currentPhase == PHASE_MOVE && (!options.triggerOnTouchEnd || options.triggerOnTouchLeave) ) {
949				nextPhase = PHASE_END;
950			} 
951			//Else if we have ended by leaving and didn't reach distance, then cancel
952			else if (!validDistance && currentPhase==PHASE_END && options.triggerOnTouchLeave) {
953				nextPhase = PHASE_CANCEL;
954			}
955			
956			return nextPhase;
957		}
958		
959		
960		/**
961		* Trigger the relevant event handler
962		* The handlers are passed the original event, the element that was swiped, and in the case of the catch all handler, the direction that was swiped, "left", "right", "up", or "down"
963		* @param {object} event the original event object
964		* @param {string} phase the phase of the swipe (start, end cancel etc) {@link $.fn.swipe.phases}
965		* @inner
966		*/
967		function triggerHandler(event, phase) {
968
969			var ret,
970				touches = event.touches;
971			
972			//Swipes and pinches are not mutually exclusive - can happend at same time, so need to trigger 2 events potentially
973			if( (didSwipe() && hasSwipes()) || (didPinch() && hasPinches()) ) {
974				// SWIPE GESTURES
975				if(didSwipe() && hasSwipes()) { //hasSwipes as status needs to fire even if swipe is invalid
976					//Trigger the swipe events...
977					ret = triggerHandlerForGesture(event, phase, SWIPE);
978				}	
979
980				// PINCH GESTURES (if the above didn't cancel)
981				if((didPinch() && hasPinches()) && ret!==false) {
982					//Trigger the pinch events...
983					ret = triggerHandlerForGesture(event, phase, PINCH);
984				}
985			} 
986			else {
987			 
988				// CLICK / TAP (if the above didn't cancel)
989				if(didDoubleTap() && ret!==false) {
990					//Trigger the tap events...
991					ret = triggerHandlerForGesture(event, phase, DOUBLE_TAP);
992				}
993				
994				// CLICK / TAP (if the above didn't cancel)
995				else if(didLongTap() && ret!==false) {
996					//Trigger the tap events...
997					ret = triggerHandlerForGesture(event, phase, LONG_TAP);
998				}
999
1000				// CLICK / TAP (if the above didn't cancel)
1001				else if(didTap() && ret!==false) {
1002					//Trigger the tap event..
1003					ret = triggerHandlerForGesture(event, phase, TAP);
1004				}
1005			}
1006			
1007			// If we are cancelling the gesture, then manually trigger the reset handler
1008			if (phase === PHASE_CANCEL) {
1009				if(hasSwipes() ) {
1010					ret = triggerHandlerForGesture(event, phase, SWIPE);
1011				}
1012			
1013				if(hasPinches()) {
1014					ret = triggerHandlerForGesture(event, phase, PINCH);
1015				}
1016				touchCancel(event);
1017			}
1018			
1019			// If we are ending the gesture, then manually trigger the reset handler IF all fingers are off
1020			if(phase === PHASE_END) {
1021				//If we support touch, then check that all fingers are off before we cancel
1022				if (touches) {
1023					if(!touches.length) {
1024						touchCancel(event);	
1025					}
1026				} 
1027				else {
1028					touchCancel(event);
1029				}
1030			}
1031					
1032			return ret;
1033		}
1034		
1035		
1036		
1037		/**
1038		* Trigger the relevant event handler
1039		* The handlers are passed the original event, the element that was swiped, and in the case of the catch all handler, the direction that was swiped, "left", "right", "up", or "down"
1040		* @param {object} event the original event object
1041		* @param {string} phase the phase of the swipe (start, end cancel etc) {@link $.fn.swipe.phases}
1042		* @param {string} gesture the gesture to trigger a handler for : PINCH or SWIPE {@link $.fn.swipe.gestures}
1043		* @return Boolean False, to indicate that the event should stop propagation, or void.
1044		* @inner
1045		*/
1046		function triggerHandlerForGesture(event, phase, gesture) {	
1047			
1048			var ret;
1049			
1050			//SWIPES....
1051			if(gesture==SWIPE) {
1052				//Trigger status every time..
1053				
1054				//Trigger the event...
1055				$element.trigger('swipeStatus', [phase, direction || null, distance || 0, duration || 0, fingerCount, fingerData]);
1056				
1057				//Fire the callback
1058				if (options.swipeStatus) {
1059					ret = options.swipeStatus.call($element, event, phase, direction || null, distance || 0, duration || 0, fingerCount, fingerData);
1060					//If the status cancels, then dont run the subsequent event handlers..
1061					if(ret===false) return false;
1062				}
1063				
1064				
1065				
1066				
1067				if (phase == PHASE_END && validateSwipe()) {
vendor: 25,281 bytes, lines 1068-1915
1068					//Fire the catch all event
1069					$element.trigger('swipe', [direction, distance, duration, fingerCount, fingerData]);
1070					
1071					//Fire catch all callback
1072					if (options.swipe) {
1073						ret = options.swipe.call($element, event, direction, distance, duration, fingerCount, fingerData);
1074						//If the status cancels, then dont run the subsequent event handlers..
1075						if(ret===false) return false;
1076					}
1077					
1078					//trigger direction specific event handlers	
1079					switch (direction) {
1080						case LEFT:
1081							//Trigger the event
1082							$element.trigger('swipeLeft', [direction, distance, duration, fingerCount, fingerData]);
1083					
1084					        //Fire the callback
1085							if (options.swipeLeft) {
1086								ret = options.swipeLeft.call($element, event, direction, distance, duration, fingerCount, fingerData);
1087							}
1088							break;
1089	
1090						case RIGHT:
1091							//Trigger the event
1092					        $element.trigger('swipeRight', [direction, distance, duration, fingerCount, fingerData]);
1093					
1094					        //Fire the callback
1095							if (options.swipeRight) {
1096								ret = options.swipeRight.call($element, event, direction, distance, duration, fingerCount, fingerData);
1097							}
1098							break;
1099	
1100						case UP:
1101							//Trigger the event
1102					        $element.trigger('swipeUp', [direction, distance, duration, fingerCount, fingerData]);
1103					
1104					        //Fire the callback
1105							if (options.swipeUp) {
1106								ret = options.swipeUp.call($element, event, direction, distance, duration, fingerCount, fingerData);
1107							}
1108							break;
1109	
1110						case DOWN:
1111							//Trigger the event
1112					        $element.trigger('swipeDown', [direction, distance, duration, fingerCount, fingerData]);
1113					
1114					        //Fire the callback
1115							if (options.swipeDown) {
1116								ret = options.swipeDown.call($element, event, direction, distance, duration, fingerCount, fingerData);
1117							}
1118							break;
1119					}
1120				}
1121			}
1122			
1123			
1124			//PINCHES....
1125			if(gesture==PINCH) {
1126				//Trigger the event
1127			     $element.trigger('pinchStatus', [phase, pinchDirection || null, pinchDistance || 0, duration || 0, fingerCount, pinchZoom, fingerData]);
1128					
1129                //Fire the callback
1130				if (options.pinchStatus) {
1131					ret = options.pinchStatus.call($element, event, phase, pinchDirection || null, pinchDistance || 0, duration || 0, fingerCount, pinchZoom, fingerData);
1132					//If the status cancels, then dont run the subsequent event handlers..
1133					if(ret===false) return false;
1134				}
1135				
1136				if(phase==PHASE_END && validatePinch()) {
1137					
1138					switch (pinchDirection) {
1139						case IN:
1140							//Trigger the event
1141                            $element.trigger('pinchIn', [pinchDirection || null, pinchDistance || 0, duration || 0, fingerCount, pinchZoom, fingerData]);
1142                    
1143                            //Fire the callback
1144                            if (options.pinchIn) {
1145								ret = options.pinchIn.call($element, event, pinchDirection || null, pinchDistance || 0, duration || 0, fingerCount, pinchZoom, fingerData);
1146							}
1147							break;
1148						
1149						case OUT:
1150							//Trigger the event
1151                            $element.trigger('pinchOut', [pinchDirection || null, pinchDistance || 0, duration || 0, fingerCount, pinchZoom, fingerData]);
1152                    
1153                            //Fire the callback
1154                            if (options.pinchOut) {
1155								ret = options.pinchOut.call($element, event, pinchDirection || null, pinchDistance || 0, duration || 0, fingerCount, pinchZoom, fingerData);
1156							}
1157							break;	
1158					}
1159				}
1160			}
1161			
1162
1163
1164                
1165	    		
1166			if(gesture==TAP) {
1167				if(phase === PHASE_CANCEL || phase === PHASE_END) {
1168					
1169    			    
1170    			    //Cancel any existing double tap
1171				    clearTimeout(singleTapTimeout);
1172    			    //Cancel hold timeout
1173				    clearTimeout(holdTimeout);
1174				           
1175					//If we are also looking for doubelTaps, wait incase this is one...
1176				    if(hasDoubleTap() && !inDoubleTap()) {
1177				        //Cache the time of this tap
1178                        doubleTapStartTime = getTimeStamp();
1179                       
1180				        //Now wait for the double tap timeout, and trigger this single tap
1181				        //if its not cancelled by a double tap
1182				        singleTapTimeout = setTimeout($.proxy(function() {
1183        			        doubleTapStartTime=null;
1184        			        //Trigger the event
1185                			$element.trigger('tap', [event.target]);
1186
1187                        
1188                            //Fire the callback
1189                            if(options.tap) {
1190                                ret = options.tap.call($element, event, event.target);
1191                            }
1192    			        }, this), options.doubleTapThreshold );
1193    			    	
1194    			    } else {
1195                        doubleTapStartTime=null;
1196                        
1197                        //Trigger the event
1198                        $element.trigger('tap', [event.target]);
1199
1200                        
1201                        //Fire the callback
1202                        if(options.tap) {
1203                            ret = options.tap.call($element, event, event.target);
1204                        }
1205	    		    }
1206	    		}
1207			}
1208			
1209			else if (gesture==DOUBLE_TAP) {
1210				if(phase === PHASE_CANCEL || phase === PHASE_END) {
1211					//Cancel any pending singletap 
1212				    clearTimeout(singleTapTimeout);
1213				    doubleTapStartTime=null;
1214				        
1215                    //Trigger the event
1216                    $element.trigger('doubletap', [event.target]);
1217                
1218                    //Fire the callback
1219                    if(options.doubleTap) {
1220                        ret = options.doubleTap.call($element, event, event.target);
1221                    }
1222	    		}
1223			}
1224			
1225			else if (gesture==LONG_TAP) {
1226				if(phase === PHASE_CANCEL || phase === PHASE_END) {
1227					//Cancel any pending singletap (shouldnt be one)
1228				    clearTimeout(singleTapTimeout);
1229				    doubleTapStartTime=null;
1230				        
1231                    //Trigger the event
1232                    $element.trigger('longtap', [event.target]);
1233                
1234                    //Fire the callback
1235                    if(options.longTap) {
1236                        ret = options.longTap.call($element, event, event.target);
1237                    }
1238	    		}
1239			}				
1240				
1241			return ret;
1242		}
1243
1244
1245
1246		
1247		//
1248		// GESTURE VALIDATION
1249		//
1250		
1251		/**
1252		* Checks the user has swipe far enough
1253		* @return Boolean if <code>threshold</code> has been set, return true if the threshold was met, else false.
1254		* If no threshold was set, then we return true.
1255		* @inner
1256		*/
1257		function validateSwipeDistance() {
1258			var valid = true;
1259			//If we made it past the min swipe distance..
1260			if (options.threshold !== null) {
1261				valid = distance >= options.threshold;
1262			}
1263			
1264            return valid;
1265		}
1266		
1267		/**
1268		* Checks the user has swiped back to cancel.
1269		* @return Boolean if <code>cancelThreshold</code> has been set, return true if the cancelThreshold was met, else false.
1270		* If no cancelThreshold was set, then we return true.
1271		* @inner
1272		*/
1273		function didSwipeBackToCancel() {
1274            var cancelled = false;
1275    		if(options.cancelThreshold !== null && direction !==null)  {
1276    		    cancelled =  (getMaxDistance( direction ) - distance) >= options.cancelThreshold;
1277			}
1278			
1279			return cancelled;
1280		}
1281
1282		/**
1283		* Checks the user has pinched far enough
1284		* @return Boolean if <code>pinchThreshold</code> has been set, return true if the threshold was met, else false.
1285		* If no threshold was set, then we return true.
1286		* @inner
1287		*/
1288		function validatePinchDistance() {
1289			if (options.pinchThreshold !== null) {
1290				return pinchDistance >= options.pinchThreshold;
1291			}
1292			return true;
1293		}
1294
1295		/**
1296		* Checks that the time taken to swipe meets the minimum / maximum requirements
1297		* @return Boolean
1298		* @inner
1299		*/
1300		function validateSwipeTime() {
1301			var result;
1302			//If no time set, then return true
1303
1304			if (options.maxTimeThreshold) {
1305				if (duration >= options.maxTimeThreshold) {
1306					result = false;
1307				} else {
1308					result = true;
1309				}
1310			}
1311			else {
1312				result = true;
1313			}
1314
1315			return result;
1316		}
1317
1318	
1319
1320		/**
1321		* Checks direction of the swipe and the value allowPageScroll to see if we should allow or prevent the default behaviour from occurring.
1322		* This will essentially allow page scrolling or not when the user is swiping on a touchSwipe object.
1323		* @param {object} jqEvent The normalised jQuery representation of the event object.
1324		* @param {string} direction The direction of the event. See {@link $.fn.swipe.directions}
1325		* @see $.fn.swipe.directions
1326		* @inner
1327		*/
1328		function validateDefaultEvent(jqEvent, direction) {
1329
1330			//If we have no pinches, then do this
1331			//If we have a pinch, and we we have 2 fingers or more down, then dont allow page scroll.
1332
1333			//If the option is set, allways allow the event to bubble up (let user handle wiredness)
1334			if( options.preventDefaultEvents === false) {
1335				return;
1336			}
1337
1338			if (options.allowPageScroll === NONE) {
1339				jqEvent.preventDefault();
1340			} else {
1341				var auto = options.allowPageScroll === AUTO;
1342
1343				switch (direction) {
1344					case LEFT:
1345						if ((options.swipeLeft && auto) || (!auto && options.allowPageScroll != HORIZONTAL)) {
1346							jqEvent.preventDefault();
1347						}
1348						break;
1349
1350					case RIGHT:
1351						if ((options.swipeRight && auto) || (!auto && options.allowPageScroll != HORIZONTAL)) {
1352							jqEvent.preventDefault();
1353						}
1354						break;
1355
1356					case UP:
1357						if ((options.swipeUp && auto) || (!auto && options.allowPageScroll != VERTICAL)) {
1358							jqEvent.preventDefault();
1359						}
1360						break;
1361
1362					case DOWN:
1363						if ((options.swipeDown && auto) || (!auto && options.allowPageScroll != VERTICAL)) {
1364							jqEvent.preventDefault();
1365						}
1366						break;
1367				}
1368			}
1369
1370		}
1371
1372
1373		// PINCHES
1374		/**
1375		 * Returns true of the current pinch meets the thresholds
1376		 * @return Boolean
1377		 * @inner
1378		*/
1379		function validatePinch() {
1380		    var hasCorrectFingerCount = validateFingers();
1381		    var hasEndPoint = validateEndPoint();
1382			var hasCorrectDistance = validatePinchDistance();
1383			return hasCorrectFingerCount && hasEndPoint && hasCorrectDistance;
1384			
1385		}
1386		
1387		/**
1388		 * Returns true if any Pinch events have been registered
1389		 * @return Boolean
1390		 * @inner
1391		*/
1392		function hasPinches() {
1393			//Enure we dont return 0 or null for false values
1394			return !!(options.pinchStatus || options.pinchIn || options.pinchOut);
1395		}
1396		
1397		/**
1398		 * Returns true if we are detecting pinches, and have one
1399		 * @return Boolean
1400		 * @inner
1401		 */
1402		function didPinch() {
1403			//Enure we dont return 0 or null for false values
1404			return !!(validatePinch() && hasPinches());
1405		}
1406
1407
1408
1409
1410		// SWIPES
1411		/**
1412		 * Returns true if the current swipe meets the thresholds
1413		 * @return Boolean
1414		 * @inner
1415		*/
1416		function validateSwipe() {
1417			//Check validity of swipe
1418			var hasValidTime = validateSwipeTime();
1419			var hasValidDistance = validateSwipeDistance();	
1420			var hasCorrectFingerCount = validateFingers();
1421		    var hasEndPoint = validateEndPoint();
1422		    var didCancel = didSwipeBackToCancel();	
1423		    
1424			// if the user swiped more than the minimum length, perform the appropriate action
1425			// hasValidDistance is null when no distance is set 
1426			var valid =  !didCancel && hasEndPoint && hasCorrectFingerCount && hasValidDistance && hasValidTime;
1427			
1428			return valid;
1429		}
1430		
1431		/**
1432		 * Returns true if any Swipe events have been registered
1433		 * @return Boolean
1434		 * @inner
1435		*/
1436		function hasSwipes() {
1437			//Enure we dont return 0 or null for false values
1438			return !!(options.swipe || options.swipeStatus || options.swipeLeft || options.swipeRight || options.swipeUp || options.swipeDown);
1439		}
1440		
1441		
1442		/**
1443		 * Returns true if we are detecting swipes and have one
1444		 * @return Boolean
1445		 * @inner
1446		*/
1447		function didSwipe() {
1448			//Enure we dont return 0 or null for false values
1449			return !!(validateSwipe() && hasSwipes());
1450		}
1451
1452        /**
1453		 * Returns true if we have matched the number of fingers we are looking for
1454		 * @return Boolean
1455		 * @inner
1456		*/
1457        function validateFingers() {
1458            //The number of fingers we want were matched, or on desktop we ignore
1459    		return ((fingerCount === options.fingers || options.fingers === ALL_FINGERS) || !SUPPORTS_TOUCH);
1460    	}
1461        
1462        /**
1463		 * Returns true if we have an end point for the swipe
1464		 * @return Boolean
1465		 * @inner
1466		*/
1467        function validateEndPoint() {
1468            //We have an end value for the finger
1469		    return fingerData[0].end.x !== 0;
1470        }
1471
1472		// TAP / CLICK
1473		/**
1474		 * Returns true if a click / tap events have been registered
1475		 * @return Boolean
1476		 * @inner
1477		*/
1478		function hasTap() {
1479			//Enure we dont return 0 or null for false values
1480			return !!(options.tap) ;
1481		}
1482		
1483		/**
1484		 * Returns true if a double tap events have been registered
1485		 * @return Boolean
1486		 * @inner
1487		*/
1488		function hasDoubleTap() {
1489			//Enure we dont return 0 or null for false values
1490			return !!(options.doubleTap) ;
1491		}
1492		
1493		/**
1494		 * Returns true if any long tap events have been registered
1495		 * @return Boolean
1496		 * @inner
1497		*/
1498		function hasLongTap() {
1499			//Enure we dont return 0 or null for false values
1500			return !!(options.longTap) ;
1501		}
1502		
1503		/**
1504		 * Returns true if we could be in the process of a double tap (one tap has occurred, we are listening for double taps, and the threshold hasn't past.
1505		 * @return Boolean
1506		 * @inner
1507		*/
1508		function validateDoubleTap() {
1509		    if(doubleTapStartTime==null){
1510		        return false;
1511		    }
1512		    var now = getTimeStamp();
1513		    return (hasDoubleTap() && ((now-doubleTapStartTime) <= options.doubleTapThreshold));
1514		}
1515		
1516		/**
1517		 * Returns true if we could be in the process of a double tap (one tap has occurred, we are listening for double taps, and the threshold hasn't past.
1518		 * @return Boolean
1519		 * @inner
1520		*/
1521		function inDoubleTap() {
1522		    return validateDoubleTap();
1523		}
1524		
1525		
1526		/**
1527		 * Returns true if we have a valid tap
1528		 * @return Boolean
1529		 * @inner
1530		*/
1531		function validateTap() {
1532		    return ((fingerCount === 1 || !SUPPORTS_TOUCH) && (isNaN(distance) || distance < options.threshold));
1533		}
1534		
1535		/**
1536		 * Returns true if we have a valid long tap
1537		 * @return Boolean
1538		 * @inner
1539		*/
1540		function validateLongTap() {
1541		    //slight threshold on moving finger
1542            return ((duration > options.longTapThreshold) && (distance < DOUBLE_TAP_THRESHOLD)); 
1543		}
1544		
1545		/**
1546		 * Returns true if we are detecting taps and have one
1547		 * @return Boolean
1548		 * @inner
1549		*/
1550		function didTap() {
1551		    //Enure we dont return 0 or null for false values
1552			return !!(validateTap() && hasTap());
1553		}
1554		
1555		
1556		/**
1557		 * Returns true if we are detecting double taps and have one
1558		 * @return Boolean
1559		 * @inner
1560		*/
1561		function didDoubleTap() {
1562		    //Enure we dont return 0 or null for false values
1563			return !!(validateDoubleTap() && hasDoubleTap());
1564		}
1565		
1566		/**
1567		 * Returns true if we are detecting long taps and have one
1568		 * @return Boolean
1569		 * @inner
1570		*/
1571		function didLongTap() {
1572		    //Enure we dont return 0 or null for false values
1573			return !!(validateLongTap() && hasLongTap());
1574		}
1575		
1576		
1577		
1578		
1579		// MULTI FINGER TOUCH
1580		/**
1581		 * Starts tracking the time between 2 finger releases, and keeps track of how many fingers we initially had up
1582		 * @inner
1583		*/
1584		function startMultiFingerRelease() {
1585			previousTouchEndTime = getTimeStamp();
1586			fingerCountAtRelease = event.touches.length+1;
1587		}
1588		
1589		/**
1590		 * Cancels the tracking of time between 2 finger releases, and resets counters
1591		 * @inner
1592		*/
1593		function cancelMultiFingerRelease() {
1594			previousTouchEndTime = 0;
1595			fingerCountAtRelease = 0;
1596		}
1597		
1598		/**
1599		 * Checks if we are in the threshold between 2 fingers being released 
1600		 * @return Boolean
1601		 * @inner
1602		*/
1603		function inMultiFingerRelease() {
1604			
1605			var withinThreshold = false;
1606			
1607			if(previousTouchEndTime) {	
1608				var diff = getTimeStamp() - previousTouchEndTime	
1609				if( diff<=options.fingerReleaseThreshold ) {
1610					withinThreshold = true;
1611				}
1612			}
1613			
1614			return withinThreshold;	
1615		}
1616		
1617
1618		/**
1619		* gets a data flag to indicate that a touch is in progress
1620		* @return Boolean
1621		* @inner
1622		*/
1623		function getTouchInProgress() {
1624			//strict equality to ensure only true and false are returned
1625			return !!($element.data(PLUGIN_NS+'_intouch') === true);
1626		}
1627		
1628		/**
1629		* Sets a data flag to indicate that a touch is in progress
1630		* @param {boolean} val The value to set the property to
1631		* @inner
1632		*/
1633		function setTouchInProgress(val) {
1634			
1635			//Add or remove event listeners depending on touch status
1636			if(val===true) {
1637				$element.bind(MOVE_EV, touchMove);
1638				$element.bind(END_EV, touchEnd);
1639
1640				//we only have leave events on desktop, we manually calcuate leave on touch as its not supported in webkit
1641				if(LEAVE_EV) { 
1642					$element.bind(LEAVE_EV, touchLeave);
1643				}
1644			} else {
1645
1646				$element.unbind(MOVE_EV, touchMove, false);
1647				$element.unbind(END_EV, touchEnd, false);
1648			
1649				//we only have leave events on desktop, we manually calcuate leave on touch as its not supported in webkit
1650				if(LEAVE_EV) { 
1651					$element.unbind(LEAVE_EV, touchLeave, false);
1652				}
1653			}
1654			
1655		
1656			//strict equality to ensure only true and false can update the value
1657			$element.data(PLUGIN_NS+'_intouch', val === true);
1658		}
1659		
1660		
1661		/**
1662		 * Creates the finger data for the touch/finger in the event object.
1663		 * @param {int} id The id to store the finger data under (usually the order the fingers were pressed)
1664		 * @param {object} evt The event object containing finger data
1665		 * @return finger data object
1666		 * @inner
1667		*/
1668		function createFingerData(id, evt) {
1669			var f = {
1670				start:{ x: 0, y: 0 },
1671				end:{ x: 0, y: 0 }
1672			};
1673			f.start.x = f.end.x = evt.pageX||evt.clientX;
1674			f.start.y = f.end.y = evt.pageY||evt.clientY;
1675			fingerData[id] = f;
1676			return f;
1677		}
1678		
1679		/**
1680		 * Updates the finger data for a particular event object
1681		 * @param {object} evt The event object containing the touch/finger data to upadte
1682		 * @return a finger data object.
1683		 * @inner
1684		*/
1685		function updateFingerData(evt) {
1686			var id = evt.identifier!==undefined ? evt.identifier : 0; 
1687			var f = getFingerData( id );
1688			
1689			if (f === null) {
1690				f = createFingerData(id, evt);
1691			}
1692
1693			f.end.x = evt.pageX||evt.clientX;
1694			f.end.y = evt.pageY||evt.clientY;
1695
1696			return f;
1697		}
1698		
1699		/**
1700		 * Returns a finger data object by its event ID.
1701		 * Each touch event has an identifier property, which is used 
1702		 * to track repeat touches
1703		 * @param {int} id The unique id of the finger in the sequence of touch events.
1704		 * @return a finger data object.
1705		 * @inner
1706		*/
1707		function getFingerData(id) {
1708			return fingerData[id] || null;
1709		}
1710
1711		
1712		/**
1713		 * Sets the maximum distance swiped in the given direction. 
1714		 * If the new value is lower than the current value, the max value is not changed.
1715		 * @param {string}  direction The direction of the swipe
1716		 * @param {int}  distance The distance of the swipe
1717		 * @inner
1718		*/
1719		function setMaxDistance(direction, distance) {
1720    		distance = Math.max(distance, getMaxDistance(direction) );
1721    		maximumsMap[direction].distance = distance;
1722		}
1723        
1724        /**
1725		 * gets the maximum distance swiped in the given direction. 
1726		 * @param {string}  direction The direction of the swipe
1727		 * @return int  The distance of the swipe
1728		 * @inner
1729		*/        
1730		function getMaxDistance(direction) {
1731			if (maximumsMap[direction]) return maximumsMap[direction].distance;
1732			return undefined;
1733		}
1734		
1735		/**
1736		 * Creats a map of directions to maximum swiped values.
1737		 * @return Object A dictionary of maximum values, indexed by direction.
1738		 * @inner
1739		*/
1740		function createMaximumsData() {
1741			var maxData={};
1742			maxData[LEFT]=createMaximumVO(LEFT);
1743			maxData[RIGHT]=createMaximumVO(RIGHT);
1744			maxData[UP]=createMaximumVO(UP);
1745			maxData[DOWN]=createMaximumVO(DOWN);
1746			
1747			return maxData;
1748		}
1749		
1750		/**
1751		 * Creates a map maximum swiped values for a given swipe direction
1752		 * @param {string} The direction that these values will be associated with
1753		 * @return Object Maximum values
1754		 * @inner
1755		*/
1756		function createMaximumVO(dir) {
1757		    return { 
1758		        direction:dir, 
1759		        distance:0
1760		    }
1761		}
1762		
1763		
1764		//
1765		// MATHS / UTILS
1766		//
1767
1768		/**
1769		* Calculate the duration of the swipe
1770		* @return int
1771		* @inner
1772		*/
1773		function calculateDuration() {
1774			return endTime - startTime;
1775		}
1776		
1777		/**
1778		* Calculate the distance between 2 touches (pinch)
1779		* @param {point} startPoint A point object containing x and y co-ordinates
1780	    * @param {point} endPoint A point object containing x and y co-ordinates
1781	    * @return int;
1782		* @inner
1783		*/
1784		function calculateTouchesDistance(startPoint, endPoint) {
1785			var diffX = Math.abs(startPoint.x - endPoint.x);
1786			var diffY = Math.abs(startPoint.y - endPoint.y);
1787				
1788			return Math.round(Math.sqrt(diffX*diffX+diffY*diffY));
1789		}
1790		
1791		/**
1792		* Calculate the zoom factor between the start and end distances
1793		* @param {int} startDistance Distance (between 2 fingers) the user started pinching at
1794	    * @param {int} endDistance Distance (between 2 fingers) the user ended pinching at
1795	    * @return float The zoom value from 0 to 1.
1796		* @inner
1797		*/
1798		function calculatePinchZoom(startDistance, endDistance) {
1799			var percent = (endDistance/startDistance) * 1;
1800			return percent.toFixed(2);
1801		}
1802		
1803		
1804		/**
1805		* Returns the pinch direction, either IN or OUT for the given points
1806		* @return string Either {@link $.fn.swipe.directions.IN} or {@link $.fn.swipe.directions.OUT}
1807		* @see $.fn.swipe.directions
1808		* @inner
1809		*/
1810		function calculatePinchDirection() {
1811			if(pinchZoom<1) {
1812				return OUT;
1813			}
1814			else {
1815				return IN;
1816			}
1817		}
1818		
1819		
1820		/**
1821		* Calculate the length / distance of the swipe
1822		* @param {point} startPoint A point object containing x and y co-ordinates
1823	    * @param {point} endPoint A point object containing x and y co-ordinates
1824	    * @return int
1825		* @inner
1826		*/
1827		function calculateDistance(startPoint, endPoint) {
1828			return Math.round(Math.sqrt(Math.pow(endPoint.x - startPoint.x, 2) + Math.pow(endPoint.y - startPoint.y, 2)));
1829		}
1830
1831		/**
1832		* Calculate the angle of the swipe
1833		* @param {point} startPoint A point object containing x and y co-ordinates
1834	    * @param {point} endPoint A point object containing x and y co-ordinates
1835	    * @return int
1836		* @inner
1837		*/
1838		function calculateAngle(startPoint, endPoint) {
1839			var x = startPoint.x - endPoint.x;
1840			var y = endPoint.y - startPoint.y;
1841			var r = Math.atan2(y, x); //radians
1842			var angle = Math.round(r * 180 / Math.PI); //degrees
1843
1844			//ensure value is positive
1845			if (angle < 0) {
1846				angle = 360 - Math.abs(angle);
1847			}
1848
1849			return angle;
1850		}
1851
1852		/**
1853		* Calculate the direction of the swipe
1854		* This will also call calculateAngle to get the latest angle of swipe
1855		* @param {point} startPoint A point object containing x and y co-ordinates
1856	    * @param {point} endPoint A point object containing x and y co-ordinates
1857	    * @return string Either {@link $.fn.swipe.directions.LEFT} / {@link $.fn.swipe.directions.RIGHT} / {@link $.fn.swipe.directions.DOWN} / {@link $.fn.swipe.directions.UP}
1858		* @see $.fn.swipe.directions
1859		* @inner
1860		*/
1861		function calculateDirection(startPoint, endPoint ) {
1862			var angle = calculateAngle(startPoint, endPoint);
1863
1864			if ((angle <= 45) && (angle >= 0)) {
1865				return LEFT;
1866			} else if ((angle <= 360) && (angle >= 315)) {
1867				return LEFT;
1868			} else if ((angle >= 135) && (angle <= 225)) {
1869				return RIGHT;
1870			} else if ((angle > 45) && (angle < 135)) {
1871				return DOWN;
1872			} else {
1873				return UP;
1874			}
1875		}
1876		
1877
1878		/**
1879		* Returns a MS time stamp of the current time
1880		* @return int
1881		* @inner
1882		*/
1883		function getTimeStamp() {
1884			var now = new Date();
1885			return now.getTime();
1886		}
1887		
1888		
1889		
1890		/**
1891		 * Returns a bounds object with left, right, top and bottom properties for the element specified.
1892		 * @param {DomNode} The DOM node to get the bounds for.
1893		 */
1894		function getbounds( el ) {
1895			el = $(el);
1896			var offset = el.offset();
1897			
1898			var bounds = {	
1899					left:offset.left,
1900					right:offset.left+el.outerWidth(),
1901					top:offset.top,
1902					bottom:offset.top+el.outerHeight()
1903					}
1904			
1905			return bounds;	
1906		}
1907		
1908		
1909		/**
1910		 * Checks if the point object is in the bounds object.
1911		 * @param {object} point A point object.
1912		 * @param {int} point.x The x value of the point.
1913		 * @param {int} point.y The x value of the point.
1914		 * @param {object} bounds The bounds object to test
1915		 * @param {int}
1915 bounds.left The leftmost value
1916		 * @param {int} bounds.right The righttmost value
1917		 * @param {int} bounds.top The topmost value
1918		* @param {int} bounds.bottom The bottommost value
1919		 */
1920		function isInBounds(point, bounds) {
1921			return (point.x > bounds.left && point.x < bounds.right && point.y > bounds.top && point.y < bounds.bottom);
1922		};
1923	
1924	
1925	}
1926	
1927	
1928
1929
1930/**
1931 * A catch all handler that is triggered for all swipe directions. 
1932 * @name $.fn.swipe#swipe
1933 * @event
1934 * @default null
1935 * @param {EventObject} event The original event object
1936 * @param {int} direction The direction the user swiped in. See {@link $.fn.swipe.directions}
1937 * @param {int} distance The distance the user swiped
1938 * @param {int} duration The duration of the swipe in milliseconds
1939 * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
1940 * @param {object} fingerData The coordinates of fingers in event
1941 */
1942 
1943
1944
1945
1946/**
1947 * A handler that is triggered for "left" swipes.
1948 * @name $.fn.swipe#swipeLeft
1949 * @event
1950 * @default null
1951 * @param {EventObject} event The original event object
1952 * @param {int} direction The direction the user swiped in. See {@link $.fn.swipe.directions}
1953 * @param {int} distance The distance the user swiped
1954 * @param {int} duration The duration of the swipe in milliseconds
1955 * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
1956 * @param {object} fingerData The coordinates of fingers in event
1957 */
1958 
1959/**
1960 * A handler that is triggered for "right" swipes.
1961 * @name $.fn.swipe#swipeRight
1962 * @event
1963 * @default null
1964 * @param {EventObject} event The original event object
1965 * @param {int} direction The direction the user swiped in. See {@link $.fn.swipe.directions}
1966 * @param {int} distance The distance the user swiped
1967 * @param {int} duration The duration of the swipe in milliseconds
1968 * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
1969 * @param {object} fingerData The coordinates of fingers in event
1970 */
1971
1972/**
1973 * A handler that is triggered for "up" swipes.
1974 * @name $.fn.swipe#swipeUp
1975 * @event
1976 * @default null
1977 * @param {EventObject} event The original event object
1978 * @param {int} direction The direction the user swiped in. See {@link $.fn.swipe.directions}
1979 * @param {int} distance The distance the user swiped
1980 * @param {int} duration The duration of the swipe in milliseconds
1981 * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
1982 * @param {object} fingerData The coordinates of fingers in event
1983 */
1984 
1985/**
1986 * A handler that is triggered for "down" swipes.
1987 * @name $.fn.swipe#swipeDown
1988 * @event
1989 * @default null
1990 * @param {EventObject} event The original event object
1991 * @param {int} direction The direction the user swiped in. See {@link $.fn.swipe.directions}
1992 * @param {int} distance The distance the user swiped
1993 * @param {int} duration The duration of the swipe in milliseconds
1994 * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
1995 * @param {object} fingerData The coordinates of fingers in event
1996 */
1997 
1998/**
1999 * A handler triggered for every phase of the swipe. This handler is constantly fired for the duration of the pinch.
2000 * This is triggered regardless of swipe thresholds.
2001 * @name $.fn.swipe#swipeStatus
2002 * @event
2003 * @default null
2004 * @param {EventObject} event The original event object
2005 * @param {string} phase The phase of the swipe event. See {@link $.fn.swipe.phases}
2006 * @param {string} direction The direction the user swiped in. This is null if the user has yet to move. See {@link $.fn.swipe.directions}
2007 * @param {int} distance The distance the user swiped. This is 0 if the user has yet to move.
2008 * @param {int} duration The duration of the swipe in milliseconds
2009 * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
2010 * @param {object} fingerData The coordinates of fingers in event
2011 */
2012 
2013/**
2014 * A handler triggered for pinch in events.
2015 * @name $.fn.swipe#pinchIn
2016 * @event
2017 * @default null
2018 * @param {EventObject} event The original event object
2019 * @param {int} direction The direction the user pinched in. See {@link $.fn.swipe.directions}
2020 * @param {int} distance The distance the user pinched
2021 * @param {int} duration The duration of the swipe in milliseconds
2022 * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
2023 * @param {int} zoom The zoom/scale level the user pinched too, 0-1.
2024 * @param {object} fingerData The coordinates of fingers in event
2025 */
2026
2027/**
2028 * A handler triggered for pinch out events.
2029 * @name $.fn.swipe#pinchOut
2030 * @event
2031 * @default null
2032 * @param {EventObject} event The original event object
2033 * @param {int} direction The direction the user pinched in. See {@link $.fn.swipe.directions}
2034 * @param {int} distance The distance the user pinched
2035 * @param {int} duration The duration of the swipe in milliseconds
2036 * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
2037 * @param {int} zoom The zoom/scale level the user pinched too, 0-1.
2038 * @param {object} fingerData The coordinates of fingers in event
2039 */ 
2040
2041/**
2042 * A handler triggered for all pinch events. This handler is constantly f
2042ired for the duration of the pinch. This is triggered regardless of thresholds.
2043 * @name $.fn.swipe#pinchStatus
2044 * @event
2045 * @default null
2046 * @param {EventObject} event The original event object
2047 * @param {int} direction The direction the user pinched in. See {@link $.fn.swipe.directions}
2048 * @param {int} distance The distance the user pinched
2049 * @param {int} duration The duration of the swipe in milliseconds
2050 * @param {int} fingerCount The number of fingers used. See {@link $.fn.swipe.fingers}
2051 * @param {int} zoom The zoom/scale level the user pinched too, 0-1.
2052 * @param {object} fingerData The coordinates of fingers in event
2053 */
2054
2055/**
2056 * A click handler triggered when a user simply clicks, rather than swipes on an element.
2057 * This is deprecated since version 1.6.2, any assignment to click will be assigned to the tap handler.
2058 * You cannot use <code>on</code> to bind to this event as the default jQ <code>click</code> event will be triggered.
2059 * Use the <code>tap</code> event instead.
2060 * @name $.fn.swipe#click
2061 * @event
2062 * @deprecated since version 1.6.2, please use {@link $.fn.swipe#tap} instead 
2063 * @default null
2064 * @param {EventObject} event The original event object
2065 * @param {DomObject} target The element clicked on.
2066 */
2067 
2068 /**
2069 * A click / tap handler triggered when a user simply clicks or taps, rather than swipes on an element.
2070 * @name $.fn.swipe#tap
2071 * @event
2072 * @default null
2073 * @param {EventObject} event The original event object
2074 * @param {DomObject} target The element clicked on.
2075 */
2076 
2077/**
2078 * A double tap handler triggered when a user double clicks or taps on an element.
2079 * You can set the time delay for a double tap with the {@link $.fn.swipe.defaults#doubleTapThreshold} property. 
2080 * Note: If you set both <code>doubleTap</code> and <code>tap</code> handlers, the <code>tap</code> event will be delayed by the <code>doubleTapThreshold</code>
2081 * as the script needs to check if its a double tap.
2082 * @name $.fn.swipe#doubleTap
2083 * @see  $.fn.swipe.defaults#doubleTapThreshold
2084 * @event
2085 * @default null
2086 * @param {EventObject} event The original event object
2087 * @param {DomObject} target The element clicked on.
2088 */
2089 
2090 /**
2091 * A long tap handler triggered once a tap has been release if the tap was longer than the longTapThreshold.
2092 * You can set the time delay for a long tap with the {@link $.fn.swipe.defaults#longTapThreshold} property. 
2093 * @name $.fn.swipe#longTap
2094 * @see  $.fn.swipe.defaults#longTapThreshold
2095 * @event
2096 * @default null
2097 * @param {EventObject} event The original event object
2098 * @param {DomObject} target The element clicked on.
2099 */
2100
2101  /**
2102 * A hold tap handler triggered as soon as the longTapThreshold is reached
2103 * You can set the time delay for a long tap with the {@link $.fn.swipe.defaults#longTapThreshold} property. 
2104 * @name $.fn.swipe#hold
2105 * @see  $.fn.swipe.defaults#longTapThreshold
2106 * @event
2107 * @default null
2108 * @param {EventObject} event The original event object
2109 * @param {DomObject} target The element clicked on.
2110 */
2111
2112}));
2113
2114
2115// THEMEPUNCH INTERNAL HANDLINGS
2116if(typeof(console) === 'undefined') {
2117    var console = {};
2118    console.log = console.error = console.info = console.debug = console.warn = console.trace = console.dir = console.dirxml = console.group = console.groupEnd = console.time = console.timeEnd = console.assert = console.profile = console.groupCollapsed = function() {};
2119}
2120
2121// THEMEPUNCH LOGS
2122if (window.tplogs==true)
2123	try {
2124		console.groupCollapsed("ThemePunch GreenSocks Logs");
2125	} catch(e) { }
2126
2127// SANDBOX GREENSOCK
2128var oldgs = window.GreenSockGlobals;
2129	oldgs_queue = window._gsQueue;
2130	
2131var punchgs = window.GreenSockGlobals = {};
2132
2133if (window.tplogs==true)
2134	try {
2135		console.info("Build GreenSock SandBox for ThemePunch Plugins");
2136		console.info("GreenSock TweenLite Engine Initalised by ThemePunch Plugin");
2137	} catch(e) {}
2138
2139/*!
2140 * VERSION: 1.18.0
2141 * DATE: 2015-09-03
2142 * UPDATES AND DOCS AT: http://greensock.com
2143 *
2144 * @license Copyright (c) 2008-2015, GreenSock. All rights reserved.
2145 * This work is subject to the terms at http://greensock.com/standard-license or for
2146 * Club GreenSock members, the software agreement that was issued with your membership.
2147 * 
2148 * @author: Jack Doyle, [email protected]
2149 */
2150(function(window, moduleName) {
2151
2152		"use strict";
2153		var _globals = window.GreenSockGlobals = window.GreenSockGlobals || window;
2154		if (_globals.TweenLite) {
2155			return; //in case the core set of classes is already loaded, don't instantiate twice.
2156		}
2157		var _namespace = function(ns) {
2158				var a = ns.split("."),
2159					p = _globals, i;
2160				for (i = 0; i < a.length; i++) {
2161					p[a[i]] = p = p[a[i]] || {};
2162				}
2163				return p;
2164			},
2165			gs = _namespace("com.greensock"),
2166			_tinyNum = 0.0000000001,
2167			_slice = function(a) { //don't use Array.prototype.slice.call(target, 0) because that doesn't work in IE8 with a NodeList that's returned by querySelectorAll()
2168				var b = [],
2169					l = a.length,
2170					i;
2171				for (i = 0; i !== l; b.push(a[i++])) {}
2172				return b;
2173			},
2174			_emptyFunc = function() {},
2175			_isArray = (function() { //works around issues in iframe environments where the Array global isn't shared, thus if the object originates in a different window/iframe, "(obj instanceof Array)" will evaluate false. We added some speed optimizations to avoid Object.prototype.toString.call() unless it's absolutely necessary because it's VERY slow (like 20x slower)
2176				var toString = Object.prototype.toString,
2177					array = toString.call([]);
2178				return function(obj) {
2179					return obj != null && (obj instanceof Array || (typeof(obj) === "object" && !!obj.push && toString.call(obj) === array));
2180				};
2181			}()),
2182			a, i, p, _ticker, _tickerActive,
2183			_defLookup = {},
2184
2185			/**
2186			 * @constructor
2187			 * Defines a GreenSock class, optionally with an array of dependencies that must be instantiated first and passed into the definition.
2188			 * This allows users to load GreenSock JS files in any order even if they have interdependencies (like CSSPlugin extends TweenPlugin which is
2189			 * inside TweenLite.js, but if CSSPlugin is loaded first, it should wait to run its code until TweenLite.js loads and instantiates TweenPlugin
2190			 * and then pass TweenPlugin to CSSPlugin's definition). This is all done automatically and internally.
2191			 *
2192			 * Every definition will be added to a "com.greensock" global object (typically window, but if a window.GreenSockGlobals object is found,
2193			 * it will go there as of v1.7). For example, TweenLite will be found at window.com.greensock.TweenLite and since it's a global class that should be available anywhere,
2194			 * it is ALSO referenced at window.TweenLite. However some classes aren't considered global, like the base com.greensock.core.Animation class, so
2195			 * those will only be at the package like window.com.greensock.core.Animation. Again, if you define a GreenSockGlobals object on the window, everything
2196			 * gets tucked neatly inside there instead of on the window directly. This allows you to do advanced things like load multiple versions of GreenSock
2197			 * files and put them into distinct objects (imagine a banner ad uses a newer version but the main site uses an older one). In that case, you could
2198			 * sandbox the banner one like:
2199			 *
2200			 * <script>
2201			 *     var gs = window.GreenSockGlobals = {}; //the newer version we're about to load could now be referenced in a "gs" object, like gs.TweenLite.to(...). Use whatever alias you want as long as it's unique, "gs" or "banner" or whatever.
2202			 * </script>
2203			 * <script src="js/greensock/v1.7/TweenMax.js"></script>
2204			 * <script>
2205			 *     window.GreenSockGlobals = window._gsQueue = window._gsDefine = null; //reset it back to null (along with the special _gsQueue variable) so that the next load of TweenMax affects the window and we can reference things directly like TweenLite.to(...)
2206			 * </script>
2207			 * <script src="js/greensock/v1.6/TweenMax.js"></script>
2208			 * <script>
2209			 *     gs.TweenLite.to(...); //would use v1.7
2210			 *     TweenLite.to(...); //would use v1.6
2211			 * </script>
2212			 *
2213			 * @param {!string} ns The namespace of the class definition, leaving off "com.greensock." as that's assumed. For example, "TweenLite" or "plugins.CSSPlugin" or "easing.Back".
2214			 * @param {!Array.<string>}
2214 dependencies An array of dependencies (described as their namespaces minus "com.greensock." prefix). For example ["TweenLite","plugins.TweenPlugin","core.Animation"]
2215			 * @param {!function():Object} func The function that should be called and passed the resolved dependencies which will return the actual class for this definition.
2216			 * @param {boolean=} global If true, the class will be added to the global scope (typically window unless you define a window.GreenSockGlobals object)
2217			 */
2218			Definition = function(ns, dependencies, func, global) {
2219				this.sc = (_defLookup[ns]) ? _defLookup[ns].sc : []; //subclasses
2220				_defLookup[ns] = this;
2221				this.gsClass = null;
2222				this.func = func;
2223				var _classes = [];
2224				this.check = function(init) {
2225					var i = dependencies.length,
2226						missing = i,
2227						cur, a, n, cl, hasModule;
2228					while (--i > -1) {
2229						if ((cur = _defLookup[dependencies[i]] || new Definition(dependencies[i], [])).gsClass) {
2230							_classes[i] = cur.gsClass;
2231							missing--;
2232						} else if (init) {
2233							cur.sc.push(this);
2234						}
2235					}
2236					if (missing === 0 && func) {
2237						a = ("com.greensock." + ns).split(".");
2238						n = a.pop();
2239						cl = _namespace(a.join("."))[n] = this.gsClass = func.apply(func, _classes);
2240
2241						//exports to multiple environments
2242						if (global) {
2243							_globals[n] = cl; //provides a way to avoid global namespace pollution. By default, the main classes like TweenLite, Power1, Strong, etc. are added to window unless a GreenSockGlobals is defined. So if you want to have things added to a custom object instead, just do something like window.GreenSockGlobals = {} before loading any GreenSock files. You can even set up an alias like window.GreenSockGlobals = windows.gs = {} so that you can access everything like gs.TweenLite. Also remember that ALL classes are added to the window.com.greensock object (in their respective packages, like com.greensock.easing.Power1, com.greensock.TweenLite, etc.)
2244							hasModule = (typeof(module) !== "undefined" && module.exports);
2245							if (!hasModule && typeof(define) === "function" && define.amd){ //AMD
2246								define((window.GreenSockAMDPath ? window.GreenSockAMDPath + "/" : "") + ns.split(".").pop(), [], function() { return cl; });
2247							} else if (ns === moduleName && hasModule){ //node
2248								module.exports = cl;
2249							}
2250						}
2251						for (i = 0; i < this.sc.length; i++) {
2252							this.sc[i].check();
2253						}
2254					}
2255				};
2256				this.check(true);
2257			},
2258
2259			//used to create Definition instances (which basically registers a class that has dependencies).
2260			_gsDefine = window._gsDefine = function(ns, dependencies, func, global) {
2261				return new Definition(ns, dependencies, func, global);
2262			},
2263
2264			//a quick way to create a class that doesn't have any dependencies. Returns the class, but first registers it in the GreenSock namespace so that other classes can grab it (other classes might be dependent on the class).
2265			_class = gs._class = function(ns, func, global) {
2266				func = func || function() {};
2267				_gsDefine(ns, [], function(){ return func; }, global);
2268				return func;
2269			};
2270
2271		_gsDefine.globals = _globals;
2272
2273
2274
2275/*
2276 * ----------------------------------------------------------------
2277 * Ease
2278 * ----------------------------------------------------------------
2279 */
2280		var _baseParams = [0, 0, 1, 1],
2281			_blankArray = [],
2282			Ease = _class("easing.Ease", function(func, extraParams, type, power) {
2283				this._func = func;
2284				this._type = type || 0;
2285				this._power = power || 0;
2286				this._params = extraParams ? _baseParams.concat(extraParams) : _baseParams;
2287			}, true),
2288			_easeMap = Ease.map = {},
2289			_easeReg = Ease.register = function(ease, names, types, create) {
2290				var na = names.split(","),
2291					i = na.length,
2292					ta = (types || "easeIn,easeOut,easeInOut").split(","),
2293					e, name, j, type;
2294				while (--i > -1) {
2295					name = na[i];
2296					e = create ? _class("easing."+name, null, true) : gs.easing[name] || {};
2297					j = ta.length;
2298					while (--j > -1) {
2299						type = ta[j];
2300						_easeMap[name + "." + type] = _easeMap[type + name] = e[type] = ease.getRatio ? ease : ease[type] || new ease();
2301					}
2302				}
2303			};
2304
2305		p = Ease.prototype;
2306		p._calcEnd = false;
2307		p.getRatio = function(p) {
2308			if (this._func) {
2309				this._params[0] = p;
2310				return this._func.apply(null, this._params);
2311			}
2312			var t = this._type,
2313				pw = this._power,
2314				r = (t === 1) ? 1 - p : (t === 2) ? p : (p < 0.5) ? p * 2 : (1 - p) * 2;
2315			if (pw === 1) {
2316				r *= r;
2317			} else if (pw === 2) {
2318				r *= r * r;
2319			} else if (pw === 3) {
2320				r *= r * r * r;
2321			} else if (pw === 4) {
2322				r *= r * r * r * r;
2323			}
2324			return (t === 1) ? 1 - r : (t === 2) ? r : (p < 0.5) ? r / 2 : 1 - (r / 2);
2325		};
2326
2327		//create all the standard eases like Linear, Quad, Cubic, Quart, Quint, Strong, Power0, Power1, Power2, Power3, and Power4 (each with easeIn, easeOut, and easeInOut)
2328		a = ["Linear","Quad","Cubic","Quart","Quint,Strong"];
2329		i = a.length;
2330		while (--i > -1) {
2331			p = a[i]+",Power"+i;
2332			_easeReg(new Ease(null,null,1,i), p, "easeOut", true);
2333			_easeReg(new Ease(null,null,2,i), p, "easeIn" + ((i === 0) ? ",easeNone" : ""));
2334			_easeReg(new Ease(null,null,3,i), p, "easeInOut");
2335		}
2336		_easeMap.linear = gs.easing.Linear.easeIn;
2337		_easeMap.swing = gs.easing.Quad.easeInOut; //for jQuery folks
2338
2339
2340/*
2341 * ----------------------------------------------------------------
2342 * EventDispatcher
2343 * ----------------------------------------------------------------
2344 */
2345		var EventDispatcher = _class("events.EventDispatcher", function(target) {
2346			this._listeners = {};
2347			this._eventTarget = target || this;
2348		});
2349		p = EventDispatcher.prototype;
2350
2351		p.addEventListener = function(type, callback, scope, useParam, priority) {
2352			priority = priority || 0;
2353			var list = this._listeners[type],
2354				index = 0,
2355				listener, i;
2356			if (list == null) {
2357				this._listeners[type] = list = [];
2358			}
2359			i = list.length;
2360			while (--i > -1) {
2361				listener = list[i];
2362				if (listener.c === callback && listener.s === scope) {
2363					list.splice(i, 1);
2364				} else if (index === 0 && listener.pr < priority) {
2365					index = i + 1;
2366				}
2367			}
2368			list.splice(index, 0, {c:callback, s:scope, up:useParam, pr:priority});
2369			if (this === _ticker && !_tickerActive) {
2370				_ticker.wake();
2371			}
2372		};
2373
2374		p.removeEventListener = function(type, callback) {
2375			var list = this._listeners[type], i;
2376			if (list) {
2377				i = list.length;
2378				while (--i > -1) {
2379					if (list[i].c === callback) {
2380						list.splice(i, 1);
2381						return;
2382					}
2383				}
2384			}
2385		};
2386
2387		p.dispatchEvent = function(type) {
2388			var list = this._listeners[type],
2389				i, t, listener;
2390			if (list) {
2391				i = list.length;
2392				t = this._eventTarget;
2393				while (--i > -1) {
2394					listener = list[i];
2395					if (listener) {
2396						if (listener.up) {
2397							listener.c.call(listener.s || t, {type:type, target:t});
2398						} else {
2399							listener.c.call(listener.s || t);
2400						}
2401					}
2402				}
2403			}
2404		};
2405
2406
2407/*
2408 * ----------------------------------------------------------------
2409 * Ticker
2410 * ----------------------------------------------------------------
2411 */
2412 		var _reqAnimFrame = window.requestAnimationFrame,
2413			_cancelAnimFrame = window.cancelAnimationFrame,
2414			_getTime = Date.now || function() {return new Date().getTime();},
2415			_lastUpdate = _getTime();
2416
2417		//now try to determine the requestAnimationFrame and cancelAnimationFrame functions and if none are found, we'll use a setTimeout()/clearTimeout() polyfill.
2418		a = ["ms","moz","webkit","o"];
2419		i = a.length;
2420		while (--i > -1 && !_reqAnimFrame) {
2421			_reqAnimFrame = window[a[i] + "RequestAnimationFrame"];
2422			_cancelAnimFrame = window[a[i] + "CancelAnimationFrame"] || window[a[i] + "CancelRequestAnimationFrame"];
2423		}
2424
2425		_class("Ticker", function(fps, useRAF) {
2426			var _self = this,
2427				_startTime = _getTime(),
2428				_useRAF = (useRAF !== false && _reqAnimFrame),
2429				_lagThreshold = 500,
2430				_adjustedLag = 33,
2431				_tickWord = "tick", //helps reduce gc burden
2432				_fps, _req, _id, _gap, _nextTime,
2433				_tick = function(manual) {
2434					var elapsed = _getTime() - _lastUpdate,
2435						overlap, dispatch;
2436					if (elapsed > _lagThreshold) {
2437						_startTime += elapsed - _adjustedLag;
2438					}
2439					_lastUpdate += elapsed;
2440					_self.time = (_lastUpdate - _startTime) / 1000;
2441					overlap = _self.time - _nextTime;
2442					if (!_fps || overlap > 0 || manual === true) {
2443						_self.frame++;
2444						_nextTime += overlap + (overlap >= _gap ? 0.004 : _gap - overlap);
2445						dispatch = true;
2446					}
2447					if (manual !== true) { //make sure the request is made before we dispatch the "tick" event so that timing is maintained. Otherwise, if processing the "tick" requires a bunch of time (like 15ms) and we're using a setTimeout() that's based on 16.7ms, it'd technically take 31.7ms between frames otherwise.
2448						_id = _req(_tick);
2449					}
2450					if (dispatch) {
2451						_self.dispatchEvent(_tickWord);
2452					}
2453				};
2454
2455			EventDispatcher.call(_self);
2456			_self.time = _self.frame = 0;
2457			_self.tick = function() {
2458				_tick(true);
2459			};
2460
2461			_self.lagSmoothing = function(threshold, adjustedLag) {
2462				_lagThreshold = threshold || (1 / _tinyNum); //zero should be interpreted as basically unlimited
2463				_adjustedLag = Math.min(adjustedLag, _lagThreshold, 0);
2464			};
2465
2466			_self.sleep = function() {
2467				if (_id == null) {
2468					return;
2469				}
2470				if (!_useRAF || !_cancelAnimFrame) {
2471					clearTimeout(_id);
2472				} else {
2473					_cancelAnimFrame(_id);
2474				}
2475				_req = _emptyFunc;
2476				_id = null;
2477				if (_self === _ticker) {
2478					_tickerActive = false;
2479				}
2480			};
2481
2482			_self.wake = function() {
2483				if (_id !== null) {
2484					_self.sleep();
2485				} else if (_self.frame > 10) { //don't trigger lagSmoothing if we're just waking up, and make sure that at least 10 frames have elapsed because of the iOS bug that we work around below with the 1.5-second setTimout().
2486					_lastUpdate = _getTime() - _lagThreshold + 5;
2487				}
2488				_req = (_fps === 0) ? _emptyFunc : (!_useRAF || !_reqAnimFrame) ? function(f) { return setTimeout(f, ((_nextTime - _self.time) * 1000 + 1) | 0); } : _reqAnimFrame;
2489				if (_self === _ticker) {
2490					_tickerActive = true;
2491				}
2492				_tick(2);
2493			};
2494
2495			_self.fps = function(value) {
2496				if (!arguments.length) {
2497					return _fps;
2498				}
2499				_fps = value;
2500				_gap = 1 / (_fps || 60);
2501				_nextTime = this.time + _gap;
2502				_self.wake();
2503			};
2504
2505			_self.useRAF = function(value) {
2506				if (!arguments.length) {
2507					return _useRAF;
2508				}
2509				_self.sleep();
2510				_useRAF = value;
2511				_self.fps(_fps);
2512			};
2513			_self.fps(fps);
2514
2515			//a bug in iOS 6 Safari occasionally prevents the requestAnimationFrame from working initially, so we use a 1.5-second timeout that automatically falls back to setTimeout() if it senses this condition.
2516			setTimeout(function() {
2517				if (_useRAF && _self.frame < 5) {
2518					_self.useRAF(false);
2519				}
2520			}, 1500);
2521		});
2522
2523		p = gs.Ticker.prototype = new gs.events.EventDispatcher();
2524		p.constructor = gs.Ticker;
2525
2526
2527/*
2528 * ----------------------------------------------------------------
2529 * Animation
2530 * ----------------------------------------------------------------
2531 */
2532		var Animation = _class("core.Animation", function(duration, vars) {
2533				this.vars = vars = vars || {};
2534				this._duration = this._totalDuration = duration || 0;
2535				this._delay = Number(vars.delay) || 0;
2536				this._timeScale = 1;
2537				this._active = (vars.immediateRender === true);
2538				this.data = vars.data;
2539				this._reversed = (vars.reversed === true);
2540
2541				if (!_rootTimeline) {
2542					return;
2543				}
2544				if (!_tickerActive) { //some browsers (like iOS 6 Safari) shut down JavaScript execution when the tab is disabled and they [occasionally] neglect to start up requestAnimationFrame again when returning - this code ensures that the engine starts up again properly.
2545					_ticker.wake();
2546				}
2547
2548				var tl = this.vars.useFrames ? _rootFramesTimeline : _rootTimeline;
2549				tl.add(this, tl._time);
2550
2551				if (this.vars.paused) {
2552					this.paused(true);
2553				}
2554			});
2555
2556		_ticker = Animation.ticker = new gs.Ticker();
2557		p = Animation.prototype;
2558		p._dirty = p._gc = p._initted = p._paused = false;
2559		p._totalTime = p._time = 0;
2560		p._rawPrevTime = -1;
2561		p._next = p._last = p._onUpdate = p._timeline = p.timeline = null;
2562		p._paused = false;
2563
2564
2565		//some browsers (like iOS) occasionally drop the requestAnimationFrame event when the user switches to a different tab and then comes back again, so we use a 2-second setTimeout() to sense if/when that condition occurs and then wake() the ticker.
2566		var _checkTimeout = function() {
2567				if (_tickerActive && _getTime() - _lastUpdate > 2000) {
2568					_ticker.wake();
2569				}
2570				setTimeout(_checkTimeout, 2000);
2571			};
2572		_checkTimeout();
2573
2574
2575		p.play = function(from, suppressEvents) {
2576			if (from != null) {
2577				this.seek(from, suppressEvents);
2578			}
2579			return this.reversed(false).paused(false);
2580		};
2581
2582		p.pause = function(atTime, suppressEvents) {
2583			if (atTime != null) {
2584				this.seek(atTime, suppressEvents);
2585			}
2586			return this.paused(true);
2587		};
2588
2589		p.resume = function(from, suppressEvents) {
2590			if (from != null) {
2591				this.seek(from, suppressEvents);
2592			}
2593			return this.paused(false);
2594		};
2595
2596		p.seek = function(time, suppressEvents) {
2597			return this.totalTime(Number(time), suppressEvents !== false);
2598		};
2599
2600		p.restart = function(includeDelay, suppressEvents) {
2601			return this.reversed(false).paused(false).totalTime(includeDelay ? -this._delay : 0, (suppressEvents !== false), true);
2602		};
2603
2604		p.reverse = function(from, suppressEvents) {
2605			if (from != null) {
2606				this.seek((from || this.totalDuration()), suppressEvents);
2607			}
2608			return this.reversed(true).paused(false);
2609		};
2610
2611		p.render = function(time, suppressEvents, force) {
2612			//stub - we override this method in subclasses.
2613		};
2614
2615		p.invalidate = function() {
2616			this._time = this._totalTime = 0;
2617			this._initted = this._gc = false;
2618			this._rawPrevTime = -1;
2619			if (this._gc || !this.timeline) {
2620				this._enabled(true);
2621			}
2622			return this;
2623		};
2624
2625		p.isActive = function() {
2626			var tl = this._timeline, //the 2 root timelines won't have a _timeline; they're always active.
2627				startTime = this._startTime,
2628				rawTime;
2629			return (!tl || (!this._gc && !this._paused && tl.isActive() && (rawTime = tl.rawTime()) >= startTime && rawTime < startTime + this.totalDuration() / this._timeScale));
2630		};
2631
2632		p._enabled = function (enabled, ignoreTimeline) {
2633			if (!_tickerActive) {
2634				_ticker.wake();
2635			}
2636			this._gc = !enabled;
2637			this._active = this.isActive();
2638			if (ignoreTimeline !== true) {
2639				if (enabled && !this.timeline) {
2640					this._timeline.add(this, this._startTime - this._delay);
2641				} else if (!enabled && this.timeline) {
2642					this._timeline._remove(this, true);
2643				}
2644			}
2645			return false;
2646		};
2647
2648
2649		p._kill = function(vars, target) {
2650			return this._enabled(false, false);
2651		};
2652
2653		p.kill = function(vars, target) {
2654			this._kill(vars, target);
2655			return this;
2656		};
2657
2658		p._uncache = function(includeSelf) {
2659			var tween = includeSelf ? this : this.timeline;
2660			while (tween) {
2661				tween._dirty = true;
2662				tween = tween.timeline;
2663			}
2664			return this;
2665		};
2666
2667		p._swapSelfInParams = function(params) {
2668			var i = params.length,
2669				copy = params.concat();
2670			while (--i > -1) {
2671				if (params[i] === "{self}") {
2672					copy[i] = this;
2673				}
2674			}
2675			return copy;
2676		};
2677
2678		p._callback = function(type) {
2679			var v = this.vars;
2680			v[type].apply(v[type + "Scope"] || v.callbackScope || this, v[type + "Params"] || _blankArray);
2681		};
2682
2683//----Animation getters/setters --------------------------------------------------------
2684
2685		p.eventCallback = function(type, callback, params, scope) {
2686			if ((type || "").substr(0,2) === "on") {
2687				var v = this.vars;
2688				if (arguments.length === 1) {
2689					return v[type];
2690				}
2691				if (callback == null) {
2692					delete v[type];
2693				} else {
2694					v[type] = callback;
2695					v[type + "Params"] = (_isArray(params) && params.join("").indexOf("{self}") !== -1) ? this._swapSelfInParams(params) : params;
2696					v[type + "Scope"] = scope;
2697				}
2698				if (type === "onUpdate") {
2699					this._onUpdate = callback;
2700				}
2701			}
2702			return this;
2703		};
2704
2705		p.delay = function(value) {
2706			if (!arguments.length) {
2707				return this._delay;
2708			}
2709			if (this._timeline.smoothChildTiming) {
2710				this.startTime( this._startTime + value - this._delay );
2711			}
2712			this._delay = value;
2713			return this;
2714		};
2715
2716		p.duration = function(value) {
2717			if (!arguments.length) {
2718				this._dirty = false;
2719				return this._duration;
2720			}
2721			this._duration = this._totalDuration = value;
2722			this._uncache(true); //true in case it's a TweenMax or TimelineMax that has a repeat - we'll need to refresh the totalDuration.
2723			if (this._timeline.smoothChildTiming) if (this._time > 0) if (this._time < this._duration) if (value !== 0) {
2724				this.totalTime(this._totalTime * (value / this._duration), true);
2725			}
2726			return this;
2727		};
2728
2729		p.totalDuration = function(value) {
2730			this._dirty = false;
2731			return (!arguments.length) ? this._totalDuration : this.duration(value);
2732		};
2733
2734		p.time = function(value, suppressEvents) {
2735			if (!arguments.length) {
2736				return this._time;
2737			}
2738			if (this._dirty) {
2739				this.totalDuration();
2740			}
2741			return this.totalTime((value > this._duration) ? this._duration : value, suppressEvents);
2742		};
2743
2744		p.totalTime = function(time, suppressEvents, uncapped) {
2745			if (!_tickerActive) {
2746				_ticker.wake();
2747			}
2748			if (!arguments.length) {
2749				return this._totalTime;
2750			}
2751			if (this._timeline) {
2752				if (time < 0 && !uncapped) {
2753					time += this.totalDuration();
2754				}
2755				if (this._timeline.smoothChildTiming) {
2756					if (this._dirty) {
2757						this.totalDuration();
2758					}
2759					var totalDuration = this._totalDuration,
2760						tl = this._timeline;
2761					if (time > totalDuration && !uncapped) {
2762						time = totalDuration;
2763					}
2764					this._startTime = (this._paused ? this._pauseTime : tl._time) - ((!this._reversed ? time : totalDuration - time) / this._timeScale);
2765					if (!tl._dirty) { //for performance improvement. If the parent's cache is already dirty, it already took care of marking the ancestors as dirty too, so skip the function call here.
2766						this._uncache(false);
2767					}
2768					//in case any of the ancestor timelines had completed but should now be enabled, we should reset their totalTime() which will also ensure that they're lined up properly and enabled. Skip for animations that are on the root (wasteful). Example: a TimelineLite.exportRoot() is performed when there's a paused tween on the root, the export will not complete until that tween is unpaused, but imagine a child gets restarted later, after all [unpaused] tweens have completed. The startTime of that child would get pushed out, but one of the ancestors may have completed.
2769					if (tl._timeline) {
2770						while (tl._timeline) {
2771							if (tl._timeline._time !== (tl._startTime + tl._totalTime) / tl._timeScale) {
2772								tl.totalTime(tl._totalTime, true);
2773							}
2774							tl = tl._timeline;
2775						}
2776					}
2777				}
2778				if (this._gc) {
2779					this._enabled(true, false);
2780				}
2781				if (this._totalTime !== time || this._duration === 0) {
2782					if (_lazyTweens.length) {
2783						_lazyRender();
2784					}
2785					this.render(time, suppressEvents, false);
2786					if (_lazyTweens.length) { //in case rendering caused any tweens to lazy-init, we should render them because typically when someone calls seek() or time() or progress(), they expect an immediate render.
2787						_lazyRender();
2788					}
2789				}
2790			}
2791			return this;
2792		};
2793
2794		p.progress = p.totalProgress = function(value, suppressEvents) {
2795			var duration = this.duration();
2796			return (!arguments.length) ? (duration ? this._time / duration : this.ratio) : this.totalTime(duration * value, suppressEvents);
2797		};
2798
2799		p.startTime = function(value) {
2800			if (!arguments.length) {
2801				return this._startTime;
2802			}
2803			if (value !== this._startTime) {
2804				this._startTime = value;
2805				if (this.timeline) if (this.timeline._sortChildren) {
2806					this.timeline.add(this, value - this._delay); //ensures that any necessary re-sequencing of Animations in the timeline occurs to make sure the rendering order is correct.
2807				}
2808			}
2809			return this;
2810		};
2811
2812		p.endTime = function(includeRepeats) {
2813			return this._startTime + ((includeRepeats != false) ? this.totalDuration() : this.duration()) / this._timeScale;
2814		};
2815
2816		p.timeScale = function(value) {
2817			if (!arguments.length) {
2818				return this._timeScale;
2819			}
2820			value = value || _tinyNum; //can't allow zero because it'll throw the math off
2821			if (this._timeline && this._timeline.smoothChildTiming) {
2822				var pauseTime = this._pauseTime,
2823					t = (pauseTime || pauseTime === 0) ? pauseTime : this._timeline.totalTime();
2824				this._startTime = t - ((t - this._startTime) * this._timeScale / value);
2825			}
2826			this._timeScale = value;
2827			return this._uncache(false);
2828		};
2829
2830		p.reversed = function(value) {
2831			if (!arguments.length) {
2832				return this._reversed;
2833			}
2834			if (value != this._reversed) {
2835				this._reversed = value;
2836				this.totalTime(((this._timeline && !this._timeline.smoothChildTiming) ? this.totalDuration() - this._totalTime : this._totalTime), true);
2837			}
2838			return this;
2839		};
2840
2841		p.paused = function(value) {
2842			if (!arguments.length) {
2843				return this._paused;
2844			}
2845			var tl = this._timeline,
2846				raw, elapsed;
2847			if (value != this._paused) if (tl) {
2848				if (!_tickerActive && !value) {
2849					_ticker.wake();
2850				}
2851				raw = tl.rawTime();
2852				elapsed = raw - this._pauseTime;
2853				if (!value && tl.smoothChildTiming) {
2854					this._startTime += elapsed;
2855					this._uncache(false);
2856				}
2857				this._pauseTime = value ? raw : null;
2858				this._paused = value;
2859				this._active = this.isActive();
2860				if (!value && elapsed !== 0 && this._initted && this.duration()) {
2861					raw = tl.smoothChildTiming ? this._totalTime : (raw - this._startTime) / this._timeScale;
2862					this.render(raw, (raw === this._totalTime), true); //in case the target's properties changed via some other tween or manual update by the user, we should force a render.
2863				}
2864			}
2865			if (this._gc && !value) {
2866				this._enabled(true, false);
2867			}
2868			return this;
2869		};
2870
2871
2872/*
2873 * ----------------------------------------------------------------
2874 * SimpleTimeline
2875 * ----------------------------------------------------------------
2876 */
2877		var SimpleTimeline = _class("core.SimpleTimeline", function(vars) {
2878			Animation.call(this, 0, vars);
2879			this.autoRemoveChildren = this.smoothChildTiming = true;
2880		});
2881
2882		p = SimpleTimeline.prototype = new Animation();
2883		p.constructor = SimpleTimeline;
2884		p.kill()._gc = false;
2885		p._first = p._last = p._recent = null;
2886		p._sortChildren = false;
2887
2888		p.add = p.insert = function(child, position, align, stagger) {
2889			var prevTween, st;
2890			child._startTime = Number(position || 0) + child._delay;
2891			if (child._paused) if (this !== child._timeline) { //we only adjust the _pauseTime if it wasn't in this timeline already. Remember, sometimes a tween will be inserted again into the same timeline when its startTime is changed so that the tweens in the TimelineLite/Max are re-ordered properly in the linked list (so everything renders in the proper order).
2892				child._pauseTime = child._startTime + ((this.rawTime() - child._startTime) / child._timeScale);
2893			}
2894			if (child.timeline) {
2895				child.timeline._remove(child, true); //removes from existing timeline so that it can be properly added to this one.
2896			}
2897			child.timeline = child._timeline = this;
2898			if (child._gc) {
2899				child._enabled(true, true);
2900			}
2901			prevTween = this._last;
2902			if (this._sortChildren) {
2903				st = child._startTime;
2904				while (prevTween && prevTween._startTime > st) {
2905					prevTween = prevTween._prev;
2906				}
2907			}
2908			if (prevTween) {
2909				child._next = prevTween._next;
2910				prevTween._next = child;
2911			} else {
2912				child._next = this._first;
2913				this._first = child;
2914			}
2915			if (child._next) {
2916				child._next._prev = child;
2917			} else {
2918				this._last = child;
2919			}
2920			child._prev = prevTween;
2921			this._recent = child;
2922			if (this._timeline) {
2923				this._uncache(true);
2924			}
2925			return this;
2926		};
2927
2928		p._remove = function(tween, skipDisable) {
2929			if (tween.timeline === this) {
2930				if (!skipDisable) {
2931					tween._enabled(false, true);
2932				}
2933
2934				if (tween._prev) {
2935					tween._prev._next = tween._next;
2936				} else if (this._first === tween) {
2937					this._first = tween._next;
2938				}
2939				if (tween._next) {
2940					tween._next._prev = tween._prev;
2941				} else if (this._last === tween) {
2942					this._last = tween._prev;
2943				}
2944				tween._next = tween._prev = tween.timeline = null;
2945				if (tween === this._recent) {
2946					this._recent = this._last;
2947				}
2948
2949				if (this._timeline) {
2950					this._uncache(true);
2951				}
2952			}
2953			return this;
2954		};
2955
2956		p.render = function(time, suppressEvents, force) {
2957			var tween = this._first,
2958				next;
2959			this._totalTime = this._time = this._rawPrevTime = time;
2960			while (tween) {
2961				next = tween._next; //record it here because the value could change after rendering...
2962				if (tween._active || (time >= tween._startTime && !tween._paused)) {
2963					if (!tween._reversed) {
2964						tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
2965					} else {
2966						tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
2967					}
2968				}
2969				tween = next;
2970			}
2971		};
2972
2973		p.rawTime = function() {
2974			if (!_tickerActive) {
2975				_ticker.wake();
2976			}
2977			return this._totalTime;
2978		};
2979
2980/*
2981 * ----------------------------------------------------------------
2982 * TweenLite
2983 * ----------------------------------------------------------------
2984 */
2985		var TweenLite = _class("TweenLite", function(target, duration, vars) {
2986				Animation.call(this, duration, vars);
2987				this.render = TweenLite.prototype.render; //speed optimization (avoid prototype lookup on this "hot" method)
2988
2989				if (target == null) {
2990					throw "Cannot tween a null target.";
2991				}
2992
2993				this.target = target = (typeof(target) !== "string") ? target : TweenLite.selector(target) || target;
2994
2995				var isSelector = (target.jquery || (target.length && target !== window && target[0] && (target[0] === window || (target[0].nodeType && target[0].style && !target.nodeType)))),
2996					overwrite = this.vars.overwrite,
2997					i, targ, targets;
2998
2999				this._overwrite = overwrite = (overwrite == null) ? _overwriteLookup[TweenLite.defaultOverwrite] : (typeof(overwrite) === "number") ? overwrite >> 0 : _overwriteLookup[overwrite];
3000
3001				if ((isSelector || target instanceof Array || (target.push && _isArray(target))) && typeof(target[0]) !== "number") {
3002					this._targets = targets = _slice(target);  //don't use Array.prototype.slice.call(target, 0) because that doesn't work in IE8 with a NodeList that's returned by querySelectorAll()
3003					this._propLookup = [];
3004					this._siblings = [];
3005					for (i = 0; i < targets.length; i++) {
3006						targ = targets[i];
3007						if (!targ) {
3008							targets.splice(i--, 1);
3009							continue;
3010						} else if (typeof(targ) === "string") {
3011							targ = targets[i--] = TweenLite.selector(targ); //in case it's an array of strings
3012							if (typeof(targ) === "string") {
3013								targets.splice(i+1, 1); //to avoid an endless loop (can't imagine why the selector would return a string, but just in case)
3014							}
3015							continue;
3016						} else if (targ.length && targ !== window && targ[0] && (targ[0] === window || (targ[0].nodeType && targ[0].style && !targ.nodeType))) { //in case the user is passing in an array of selector objects (like jQuery objects), we need to check one more level and pull things out if necessary. Also note that <select> elements pass all the criteria regarding length and the first child having style, so we must also check to ensure the target isn't an HTML node itself.
3017							targets.splice(i--, 1);
3018							this._targets = targets = targets.concat(_slice(targ));
3019							continue;
3020						}
3021						this._siblings[i] = _register(targ, this, false);
3022						if (overwrite === 1) if (this._siblings[i].length > 1) {
3023							_applyOverwrite(targ, this, null, 1, this._siblings[i]);
3024						}
3025					}
3026
3027				} else {
3028					this._propLookup = {};
3029					this._siblings = _register(target, this, false);
3030					if (overwrite === 1) if (this._siblings.length > 1) {
3031						_applyOverwrite(target, this, null, 1, this._siblings);
3032					}
3033				}
3034				if (this.vars.immediateRender || (duration === 0 && this._delay === 0 && this.vars.immediateRender !== false)) {
3035					this._time = -_tinyNum; //forces a render without having to set the render() "force" parameter to true because we want to allow lazying by default (using the "force" parameter always forces an immediate full render)
3036					this.render(-this._delay);
3037				}
3038			}, true),
3039			_isSelector = function(v) {
3040				return (v && v.length && v !== window && v[0] && (v[0] === window || (v[0].nodeType && v[0].style && !v.nodeType))); //we cannot check "nodeType" if the target is window from within an iframe, otherwise it will trigger a security error in some browsers like Firefox.
3041			},
3042			_autoCSS = function(vars, target) {
3043				var css = {},
3044					p;
3045				for (p in vars) {
3046					if (!_reservedProps[p] && (!(p in target) || p === "transform" || p === "x" || p === "y" || p === "width" || p === "height" || p === "className" || p === "border") && (!_plugins[p] || (_plugins[p] && _plugins[p]._autoCSS))) { //note: <img> elements contain read-only "x" and "y" properties. We should also prioritize editing css width/height rather than the element's properties.
3047						css[p] = vars[p];
3048						delete vars[p];
3049					}
3050				}
3051				vars.css = css;
3052			};
3053
3054		p = TweenLite.prototype = new Animation();
3055		p.constructor = TweenLite;
3056		p.kill()._gc = false;
3057
3058//----TweenLite defaults, overwrite management, and root updates ----------------------------------------------------
3059
3060		p.ratio = 0;
3061		p._firstPT = p._targets = p._overwrittenProps = p._startAt = null;
3062		p._notifyPluginsOfEnabled = p._lazy = false;
3063
3064		TweenLite.version = "1.18.0";
3065		TweenLite.defaultEase = p._ease = new Ease(null, null, 1, 1);
3066		TweenLite.defaultOverwrite = "auto";
3067		TweenLite.ticker = _ticker;
3068		TweenLite.autoSleep = 120;
3069		TweenLite.lagSmoothing = function(threshold, adjustedLag) {
3070			_ticker.lagSmoothing(threshold, adjustedLag);
3071		};
3072
3073		TweenLite.selector = window.$ || window.jQuery || function(e) {
3074			var selector = window.$ || window.jQuery;
3075			if (selector) {
3076				TweenLite.selector = selector;
3077				return selector(e);
3078			}
3079			return (typeof(document) === "undefined") ? e : (document.querySelectorAll ? document.querySelectorAll(e) : document.getElementById((e.charAt(0) === "#") ? e.substr(1) : e));
3080		};
3081
3082		var _lazyTweens = [],
3083			_lazyLookup = {},
3084			_numbersExp = /(?:(-|-=|\+=)?\d*\.?\d*(?:e[\-+]?\d+)?)[0-9]/ig,
3085			//_nonNumbersExp = /(?:([\-+](?!(\d|=)))|[^\d\-+=e]|(e(?![\-+][\d])))+/ig,
3086			_setRatio = function(v) {
3087				var pt = this._firstPT,
3088					min = 0.000001,
3089					val;
3090				while (pt) {
3091					val = !pt.blob ? pt.c * v + pt.s : v ? this.join("") : this.start;
3092					if (pt.r) {
3093						val = Math.round(val);
3094					} else if (val < min) if (val >
3094 -min) { //prevents issues with converting very small numbers to strings in the browser
3095						val = 0;
3096					}
3097					if (!pt.f) {
3098						pt.t[pt.p] = val;
3099					} else if (pt.fp) {
3100						pt.t[pt.p](pt.fp, val);
3101					} else {
3102						pt.t[pt.p](val);
3103					}
3104					pt = pt._next;
3105				}
3106			},
3107			//compares two strings (start/end), finds the numbers that are different and spits back an array representing the whole value but with the changing values isolated as elements. For example, "rgb(0,0,0)" and "rgb(100,50,0)" would become ["rgb(", 0, ",", 50, ",0)"]. Notice it merges the parts that are identical (performance optimization). The array also has a linked list of PropTweens attached starting with _firstPT that contain the tweening data (t, p, s, c, f, etc.). It also stores the starting value as a "start" property so that we can revert to it if/when necessary, like when a tween rewinds fully. If the quantity of numbers differs between the start and end, it will always prioritize the end value(s). The pt parameter is optional - it's for a PropTween that will be appended to the end of the linked list and is typically for actually setting the value after all of the elements have been updated (with array.join("")).
3108			_blobDif = function(start, end, filter, pt) {
3109				var a = [start, end],
3110					charIndex = 0,
3111					s = "",
3112					color = 0,
3113					startNums, endNums, num, i, l, nonNumbers, currentNum;
3114				a.start = start;
3115				if (filter) {
3116					filter(a); //pass an array with the starting and ending values and let the filter do whatever it needs to the values.
3117					start = a[0];
3118					end = a[1];
3119				}
3120				a.length = 0;
3121				startNums = start.match(_numbersExp) || [];
3122				endNums = end.match(_numbersExp) || [];
3123				if (pt) {
3124					pt._next = null;
3125					pt.blob = 1;
3126					a._firstPT = pt; //apply last in the linked list (which means inserting it first)
3127				}
3128				l = endNums.length;
3129				for (i = 0; i < l; i++) {
3130					currentNum = endNums[i];
3131					nonNumbers = end.substr(charIndex, end.indexOf(currentNum, charIndex)-charIndex);
3132					s += (nonNumbers || !i) ? nonNumbers : ","; //note: SVG spec allows omission of comma/space when a negative sign is wedged between two numbers, like 2.5-5.3 instead of 2.5,-5.3 but when tweening, the negative value may switch to positive, so we insert the comma just in case.
3133					charIndex += nonNumbers.length;
3134					if (color) { //sense rgba() values and round them.
3135						color = (color + 1) % 5;
3136					} else if (nonNumbers.substr(-5) === "rgba(") {
3137						color = 1;
3138					}
3139					if (currentNum === startNums[i] || startNums.length <= i) {
3140						s += currentNum;
3141					} else {
3142						if (s) {
3143							a.push(s);
3144							s = "";
3145						}
3146						num = parseFloat(startNums[i]);
3147						a.push(num);
3148						a._firstPT = {_next: a._firstPT, t:a, p: a.length-1, s:num, c:((currentNum.charAt(1) === "=") ? parseInt(currentNum.charAt(0) + "1", 10) * parseFloat(currentNum.substr(2)) : (parseFloat(currentNum) - num)) || 0, f:0, r:(color && color < 4)};
3149						//note: we don't set _prev because we'll never need to remove individual PropTweens from this list.
3150					}
3151					charIndex += currentNum.length;
3152				}
3153				s += end.substr(charIndex);
3154				if (s) {
3155					a.push(s);
3156				}
3157				a.setRatio = _setRatio;
3158				return a;
3159			},
3160			//note: "funcParam" is only necessary for function-based getters/setters that require an extra parameter like getAttribute("width") and setAttribute("width", value). In this example, funcParam would be "width". Used by AttrPlugin for example.
3161			_addPropTween = function(target, prop, start, end, overwriteProp, round, funcParam, stringFilter) {
3162				var s = (start === "get") ? target[prop] : start,
3163					type = typeof(target[prop]),
3164					isRelative = (typeof(end) === "string" && end.charAt(1) === "="),
3165					pt = {t:target, p:prop, s:s, f:(type === "function"), pg:0, n:overwriteProp || prop, r:round, pr:0, c:isRelative ? parseInt(end.charAt(0) + "1", 10) * parseFloat(end.substr(2)) : (parseFloat(end) - s) || 0},
3166					blob, getterName;
3167				if (type !== "number") {
3168					if (type === "function" && start === "get") {
3169						getterName = ((prop.indexOf("set") || typeof(target["get" + prop.substr(3)]) !== "function") ? prop : "get" + prop.substr(3));
3170						pt.s = s = funcParam ? target[getterName](funcParam) : target[getterName]();
3171					}
3172					if (typeof(s) === "string" && (funcParam || isNaN(s))) {
3173						//a blob (string that has multiple numbers in it)
3174						pt.fp = funcParam;
3175						blob = _blobDif(s, end, stringFilter || TweenLite.defaultStringFilter, pt);
3176						pt = {t:blob, p:"setRatio", s:0, c:1, f:2, pg:0, n:overwriteProp || prop, pr:0}; //"2" indicates it's a Blob property tween. Needed for RoundPropsPlugin for example.
3177					} else if (!isRelative) {
3178						pt.c = (parseFloat(end) - parseFloat(s)) || 0;
3179					}
3180				}
3181				if (pt.c) { //only add it to the linked list if there's a change.
3182					if ((pt._next = this._firstPT)) {
3183						pt._next._prev = pt;
3184					}
3185					this._firstPT = pt;
3186					return pt;
3187				}
3188			},
3189			_internals = TweenLite._internals = {isArray:_isArray, isSelector:_isSelector, lazyTweens:_lazyTweens, blobDif:_blobDif}, //gives us a way to expose certain private values to other GreenSock classes without contaminating tha main TweenLite object.
3190			_plugins = TweenLite._plugins = {},
3191			_tweenLookup = _internals.tweenLookup = {},
3192			_tweenLookupNum = 0,
3193			_reservedProps = _internals.reservedProps = {ease:1, delay:1, overwrite:1, onComplete:1, onCompleteParams:1, onCompleteScope:1, useFrames:1, runBackwards:1, startAt:1, onUp
3193date:1, onUpdateParams:1, onUpdateScope:1, onStart:1, onStartParams:1, onStartScope:1, onReverseComplete:1, onReverseCompleteParams:1, onReverseCompleteScope:1, onRepeat:1, onRepeatParams:1, onRepeatScope:1, easeParams:1, yoyo:1, immediateRender:1, repeat:1, repeatDelay:1, data:1, paused:1, reversed:1, autoCSS:1, lazy:1, onOverwrite:1, callbackScope:1, stringFilter:1},
3194			_overwriteLookup = {none:0, all:1, auto:2, concurrent:3, allOnStart:4, preexisting:5, "true":1, "false":0},
3195			_rootFramesTimeline = Animation._rootFramesTimeline = new SimpleTimeline(),
3196			_rootTimeline = Animation._rootTimeline = new SimpleTimeline(),
3197			_nextGCFrame = 30,
3198			_lazyRender = _internals.lazyRender = function() {
3199				var i = _lazyTweens.length,
3200					tween;
3201				_lazyLookup = {};
3202				while (--i > -1) {
3203					tween = _lazyTweens[i];
3204					if (tween && tween._lazy !== false) {
3205						tween.render(tween._lazy[0], tween._lazy[1], true);
3206						tween._lazy = false;
3207					}
3208				}
3209				_lazyTweens.length = 0;
3210			};
3211
3212		_rootTimeline._startTime = _ticker.time;
3213		_rootFramesTimeline._startTime = _ticker.frame;
3214		_rootTimeline._active = _rootFramesTimeline._active = true;
3215		setTimeout(_lazyRender, 1); //on some mobile devices, there isn't a "tick" before code runs which means any lazy renders wouldn't run before the next official "tick".
3216
3217		Animation._updateRoot = TweenLite.render = function() {
3218				var i, a, p;
3219				if (_lazyTweens.length) { //if code is run outside of the requestAnimationFrame loop, there may be tweens queued AFTER the engine refreshed, so we need to ensure any pending renders occur before we refresh again.
3220					_lazyRender();
3221				}
3222				_rootTimeline.render((_ticker.time - _rootTimeline._startTime) * _rootTimeline._timeScale, false, false);
3223				_rootFramesTimeline.render((_ticker.frame - _rootFramesTimeline._startTime) * _rootFramesTimeline._timeScale, false, false);
3224				if (_lazyTweens.length) {
3225					_lazyRender();
3226				}
3227				if (_ticker.frame >= _nextGCFrame) { //dump garbage every 120 frames or whatever the user sets TweenLite.autoSleep to
3228					_nextGCFrame = _ticker.frame + (parseInt(TweenLite.autoSleep, 10) || 120);
3229					for (p in _tweenLookup) {
3230						a = _tweenLookup[p].tweens;
3231						i = a.length;
3232						while (--i > -1) {
3233							if (a[i]._gc) {
3234								a.splice(i, 1);
3235							}
3236						}
3237						if (a.length === 0) {
3238							delete _tweenLookup[p];
3239						}
3240					}
3241					//if there are no more tweens in the root timelines, or if they're all paused, make the _timer sleep to reduce load on the CPU slightly
3242					p = _rootTimeline._first;
3243					if (!p || p._paused) if (TweenLite.autoSleep && !_rootFramesTimeline._first && _ticker._listeners.tick.length === 1) {
3244						while (p && p._paused) {
3245							p = p._next;
3246						}
3247						if (!p) {
3248							_ticker.sleep();
3249						}
3250					}
3251				}
3252			};
3253
3254		_ticker.addEventListener("tick", Animation._updateRoot);
3255
3256		var _register = function(target, tween, scrub) {
3257				var id = target._gsTweenID, a, i;
3258				if (!_tweenLookup[id || (target._gsTweenID = id = "t" + (_tweenLookupNum++))]) {
3259					_tweenLookup[id] = {target:target, tweens:[]};
3260				}
3261				if (tween) {
3262					a = _tweenLookup[id].tweens;
3263					a[(i = a.length)] = tween;
3264					if (scrub) {
3265						while (--i > -1) {
3266							if (a[i] === tween) {
3267								a.splice(i, 1);
3268							}
3269						}
3270					}
3271				}
3272				return _tweenLookup[id].tweens;
3273			},
3274			_onOverwrite = function(overwrittenTween, overwritingTween, target, killedProps) {
3275				var func = overwrittenTween.vars.onOverwrite, r1, r2;
3276				if (func) {
3277					r1 = func(overwrittenTween, overwritingTween, target, killedProps);
3278				}
3279				func = TweenLite.onOverwrite;
3280				if (func) {
3281					r2 = func(overwrittenTween, overwritingTween, target, killedProps);
3282				}
3283				return (r1 !== false && r2 !== false);
3284			},
3285			_applyOverwrite = function(target, tween, props, mode, siblings) {
3286				var i, changed, curTween, l;
3287				if (mode === 1 || mode >= 4) {
3288					l = siblings.length;
3289					for (i = 0; i < l; i++) {
3290						if ((curTween = siblings[i]) !== tween) {
3291							if (!curTween._gc) {
3292								if (curTween._kill(null, target, tween)) {
3293									changed = true;
3294								}
3295							}
3296						} else if (mode === 5) {
3297							break;
3298						}
3299					}
3300					return changed;
3301				}
3302				//NOTE: Add 0.0000000001 to overcome floating point errors that can cause the startTime to be VERY slightly off (when a tween's time() is set for example)
3303				var startTime = tween._startTime + _tinyNum,
3304					overlaps = [],
3305					oCount = 0,
3306					zeroDur = (tween._duration === 0),
3307					globalStart;
3308				i = siblings.length;
3309				while (--i > -1) {
3310					if ((curTween = siblings[i]) === tween || curTween._gc || curTween._paused) {
3311						//ignore
3312					} else if (curTween._timeline !== tween._timeline) {
3313						globalStart = globalStart || _checkOverlap(tween, 0, zeroDur);
3314						if (_checkOverlap(curTween, globalStart, zeroDur) === 0) {
3315							overlaps[oCount++] = curTween;
3316						}
3317					} else if (curTween._startTime <= startTime) if (curTween._startTime + curTween.totalDuration() / curTween._timeScale > startTime) if (!((zeroDur || !curTween._initted) && startTime - curTween._startTime <= 0.0000000002)) {
3318						overlaps[oCount++] = curTween;
3319					}
3320				}
3321
3322				i = oCount;
3323				while (--i > -1) {
3324					curTween = overlaps[i];
3325					if (mode === 2) if (curTween._kill(props, target, tween)) {
3326						changed = true;
3327					}
3328					if (mode !== 2 || (!curTween._firstPT && curTween._initted)) {
3329						if (mode !== 2 && !_onOverwrite(curTween, tween)) {
3330							continue;
3331						}
3332						if (curTween._enabled(false, false)) { //if all property tweens have been overwritten, kill the tween.
3333							changed = true;
3334						}
3335					}
3336				}
3337				return changed;
3338			},
3339			_checkOverlap = function(tween, reference, zeroDur) {
3340				var tl = tween._timeline,
3341					ts = tl._timeScale,
3342					t = tween._startTime;
3343				while (tl._timeline) {
3344					t += tl._startTime;
3345					ts *= tl._timeScale;
3346					if (tl._paused) {
3347						return -100;
3348					}
3349					tl = tl._timeline;
3350				}
3351				t /= ts;
3352				return (t > reference) ? t - reference : ((zeroDur && t === reference) || (!tween._initted && t - reference < 2 * _tinyNum)) ? _tinyNum : ((t += tween.totalDuration() / tween._timeScale / ts) > reference + _tinyNum) ? 0 : t - reference - _tinyNum;
3353			};
3354
3355
3356//---- TweenLite instance methods -----------------------------------------------------------------------------
3357
3358		p._init = function() {
3359			var v = this.vars,
3360				op = this._overwrittenProps,
3361				dur = this._duration,
3362				immediate = !!v.immediateRender,
3363				ease = v.ease,
3364				i, initPlugins, pt, p, startVars;
3365			if (v.startAt) {
3366				if (this._startAt) {
3367					this._startAt.render(-1, true); //if we've run a startAt previously (when the tween instantiated), we should revert it so that the values re-instantiate correctly particularly for relative tweens. Without this, a TweenLite.fromTo(obj, 1, {x:"+=100"}, {x:"-=100"}), for example, would actually jump to +=200 because the startAt would run twice, doubling the relative change.
3368					this._startAt.kill();
3369				}
3370				startVars = {};
3371				for (p in v.startAt) { //copy the properties/values into a new object to avoid collisions, like var to = {x:0}, from = {x:500}; timeline.fromTo(e, 1, from, to).fromTo(e, 1, to, from);
3372					startVars[p] = v.startAt[p];
3373				}
3374				startVars.overwrite = false;
3375				startVars.immediateRender = true;
3376				startVars.lazy = (immediate && v.lazy !== false);
3377				startVars.startAt = startVars.delay = null; //no nesting of startAt objects allowed (otherwise it could cause an infinite loop).
3378				this._startAt = TweenLite.to(this.target, 0, startVars);
3379				if (immediate) {
3380					if (this._time > 0) {
3381						this._startAt = null; //tweens that render immediately (like most from() and fromTo() tweens) shouldn't revert when their parent timeline's playhead goes backward past the startTime because the initial render could have happened anytime and it shouldn't be directly correlated to this tween's startTime. Imagine setting up a complex animation where the beginning states of various objects are rendered immediately but the tween doesn't happen for quite some time - if we revert to the starting values as soon as the playhead goes backward past the tween's startTime, it will throw things off visually. Reversion should only happen in TimelineLite/Max instances where immediateRender was false (which is the default in the convenience methods like from()).
3382					} else if (dur !== 0) {
3383						return; //we skip initialization here so that overwriting doesn't occur until the tween actually begins. Otherwise, if you create several immediateRender:true tweens of the same target/properties to drop into a TimelineLite or TimelineMax, the last one created would overwrite the first ones because they didn't get placed into the timeline yet before the first render occurs and kicks in overwriting.
3384					}
3385				}
3386			} else if (v.runBackwards && dur !== 0) {
3387				//from() tweens must be handled uniquely: their beginning values must be rendered but we don't want overwriting to occur yet (when time is still 0). Wait until the tween actually begins before doing all the routines like overwriting. At that time, we should render at the END of the tween to ensure that things initialize correctly (remember, from() tweens go backwards)
3388				if (this._startAt) {
3389					this._startAt.render(-1, true);
3390					this._startAt.kill();
3391					this._startAt = null;
3392				} else {
3393					if (this._time !== 0) { //in rare cases (like if a from() tween runs and then is invalidate()-ed), immediateRender could be true but the initial forced-render gets skipped, so there's no need to force the render in this context when the _time is greater than 0
3394						immediate = false;
3395					}
3396					pt = {};
3397					for (p in v) { //copy props into a new object and skip any reserved props, otherwise onComplete or onUpdate or onStart could fire. We should, however, permit autoCSS to go through.
3398						if (!_reservedProps[p] || p === "autoCSS") {
3399							pt[p] = v[p];
3400						}
3401					}
3402					pt.overwrite = 0;
3403					pt.data = "isFromStart"; //we tag the tween with as "isFromStart" so that if [inside a plugin] we need to only do something at the very END of a tween, we have a way of identifying this tween as merely the one that's setting the beginning values for a "from()" tween. For example, clearProps in CSSPlugin should only get applied at the very END of a tween and without this tag, from(...{height:100, clearProps:"height", delay:1}) would wipe the height at the beginning of the tween and after 1 second, it'd kick back in.
3404					pt.lazy = (immediate && v.lazy !== false);
3405					pt.immediateRender = immediate; //zero-duration tweens render immediately by default, but if we're not specifically instructed to render this tween immediately, we should skip this and merely _init() to record the starting values (rendering them immediately would push them to completion which is wasteful in that case - we'd have to render(-1) immediately after)
3406					this._startAt = TweenLite.to(this.target, 0, pt);
3407					if (!immediate) {
3408						this._startAt._init(); //ensures that the initial values are recorded
3409						this._startAt._enabled(false); //no need to have the tween render on the next cycle. Disable it because we'll always manually control the renders of the _startAt tween.
3410						if (this.vars.immediateRender) {
3411							this._startAt = null;
3412						}
3413					} else if (this._time === 0) {
3414						return;
3415					}
3416				}
3417			}
3418			this._ease = ease = (!ease) ? TweenLite.defaultEase : (ease instanceof Ease) ? ease : (typeof(ease) === "function") ? new Ease(ease, v.easeParams) : _easeMap[ease] || TweenLite.defaultEase;
3419			if (v.easeParams instanceof Array && ease.config) {
3420				this._ease = ease.config.apply(ease, v.easeParams);
3421			}
3422			this._easeType = this._ease._type;
3423			this._easePower = this._ease._power;
3424			this._firstPT = null;
3425
3426			if (this._targets) {
3427				i = this._targets.length;
3428				while (--i > -1) {
3429					if ( this._initProps( this._targets[i], (this._propLookup[i] = {}), this._siblings[i], (op ? op[i] : null)) ) {
3430						initPlugins = true;
3431					}
3432				}
3433			} else {
3434				initPlugins = this._initProps(this.target, this._propLookup, this._siblings, op);
3435			}
3436
3437			if (initPlugins) {
3438				TweenLite._onPluginEvent("_onInitAllProps", this); //reorders the array in order of priority. Uses a static TweenPlugin method in order to minimize file size in TweenLite
3439			}
3440			if (op) if (!this._firstPT) if (typeof(this.target) !== "function") { //if all tweening properties have been overwritten, kill the tween. If the target is a function, it's probably a delayedCall so let it live.
3441				this._enabled(false, false);
3442			}
3443			if (v.runBackwards) {
3444				pt = this._firstPT;
3445				while (pt) {
3446					pt.s += pt.c;
3447					pt.c = -pt.c;
3448					pt = pt._next;
3449				}
3450			}
3451			this._onUpdate = v.onUpdate;
3452			this._initted = true;
3453		};
3454
3455		p._initProps = function(target, propLookup, siblings, overwrittenProps) {
3456			var p, i, initPlugins, plugin, pt, v;
3457			if (target == null) {
3458				return false;
3459			}
3460
3461			if (_lazyLookup[target._gsTweenID]) {
3462				_lazyRender(); //if other tweens of the same target have recently initted but haven't rendered yet, we've got to force the render so that the starting values are correct (imagine populating a timeline with a bunch of sequential tweens and then jumping to the end)
3463			}
3464
3465			if (!this.vars.css) if (target.style) if (target !== window && target.nodeType) if (_plugins.css) if (this.vars.autoCSS !== false) { //it's so common to use TweenLite/Max to animate the css of DOM elements, we assume that if the target is a DOM element, that's what is intended (a convenience so that users don't have to wrap things in css:{}, although we still recommend it for a slight performance boost and better specificity). Note: we cannot check "nodeType" on the window inside an iframe.
3466				_autoCSS(this.vars, target);
3467			}
3468			for (p in this.vars) {
3469				v = this.vars[p];
3470				if (_reservedProps[p]) {
3471					if (v) if ((v instanceof Array) || (v.push && _isArray(v))) if (v.join("").indexOf("{self}") !== -1) {
3472						this.vars[p] = v = this._swapSelfInParams(v, this);
3473					}
3474
3475				} else if (_plugins[p] && (plugin = new _plugins[p]())._onInitTween(target, this.vars[p], this)) {
3476
3477					//t - target 		[object]
3478					//p - property 		[string]
3479					//s - start			[number]
3480					//c - change		[number]
3481					//f - isFunction	[boolean]
3482					//n - name			[string]
3483					//pg - isPlugin 	[boolean]
3484					//pr - priority		[number]
3485					this._firstPT = pt = {_next:this._firstPT, t:plugin, p:"setRatio", s:0, c:1, f:1, n:p, pg:1, pr:plugin._priority};
3486					i = plugin._overwriteProps.length;
3487					while (--i > -1) {
3488						propLookup[plugin._overwriteProps[i]] = this._firstPT;
3489					}
3490					if (plugin._priority || plugin._onInitAllProps) {
3491						initPlugins = true;
3492					}
3493					if (plugin._onDisable || plugin._onEnable) {
3494						this._notifyPluginsOfEnabled = true;
3495					}
3496					if (pt._next) {
3497						pt._next._prev = pt;
3498					}
3499
3500				} else {
3501					propLookup[p] = _addPropTween.call(this, target, p, "get", v, p, 0, null, this.vars.stringFilter);
3502				}
3503			}
3504
3505			if (overwrittenProps) if (this._kill(overwrittenProps, target)) { //another tween may have tried to overwrite properties of this tween before init() was called (like if two tweens start at the same time, the one created second will run first)
3506				return this._initProps(target, propLookup, siblings, overwrittenProps);
3507			}
3508			if (this._overwrite > 1) if (this._firstPT) if (siblings.length > 1) if (_applyOverwrite(target, this, propLookup, this._overwrite, siblings)) {
3509				this._kill(propLookup, target);
3510				return this._initProps(target, propLookup, siblings, overwrittenProps);
3511			}
3512			if (this._firstPT) if ((this.vars.lazy !== false && this._duration) || (this.vars.lazy && !this._duration)) { //zero duration tweens don't lazy render by default; everything else does.
3513				_lazyLookup[target._gsTweenID] = true;
3514			}
3515			return initPlugins;
3516		};
3517
3518		p.render = function(time, suppressEvents, force) {
3519			var prevTime = this._time,
3520				duration = this._duration,
3521				prevRawPrevTime = this._rawPrevTime,
3522				isComplete, callback, pt, rawPrevTime;
3523			if (time >= duration) {
3524				this._totalTime = this._time = duration;
3525				this.ratio = this._ease._calcEnd ? this._ease.getRatio(1) : 1;
3526				if (!this._reversed ) {
3527					isComplete = true;
3528					callback = "onComplete";
3529					force = (force || this._timeline.autoRemoveChildren); //otherwise, if the animation is unpaused/activated after it's already finished, it doesn't get removed from the parent timeline.
3530				}
3531				if (duration === 0) if (this._initted || !this.vars.lazy || force) { //zero-duration tweens are tricky because we must discern the momentum/direction of time in order to determine whether the starting values should be rendered or the ending values. If the "playhead" of its timeline goes past the zero-duration tween in the forward direction or lands directly on it, the end values should be rendered, but if the timeline's "playhead" moves past it in the backward direction (from a postitive time to a negative time), the starting values must be rendered.
3532					if (this._startTime === this._timeline._duration) { //if a zero-duration tween is at the VERY end of a timeline and that timeline renders at its end, it will typically add a tiny bit of cushion to the render time to prevent rounding errors from getting in the way of tweens rendering their VERY end. If we then reverse() that timeline, the zero-duration tween will trigger its onReverseComplete even though technically the playhead didn't pass over it again. It's a very specific edge case we must accommodate.
3533						time = 0;
3534					}
3535					if (time === 0 || prevRawPrevTime < 0 || (prevRawPrevTime === _tinyNum && this.data !== "isPause")) if (prevRawPrevTime !== time) { //note: when this.data is "isPause", it's a callback added by addPause() on a timeline that we should not be triggered when LEAVING its exact start time. In other words, tl.addPause(1).play(1) shouldn't pause.
3536						force = true;
3537						if (prevRawPrevTime > _tinyNum) {
3538							callback = "onReverseComplete";
3539						}
3540					}
3541					this._rawPrevTime = rawPrevTime = (!suppressEvents || time || prevRawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient.
3542				}
3543
3544			} else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
3545				this._totalTime = this._time = 0;
3546				this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0;
3547				if (prevTime !== 0 || (duration === 0 && prevRawPrevTime > 0)) {
3548					callback = "onReverseComplete";
3549					isComplete = this._reversed;
3550				}
3551				if (time < 0) {
3552					this._active = false;
3553					if (duration === 0) if (this._initted || !this.vars.lazy || force) { //zero-duration tweens are tricky because we must discern the momentum/direction of time in order to determine whether the starting values should be rendered or the ending values. If the "playhead" of its timeline goes past the zero-duration tween in the forward direction or lands directly on it, the end values should be rendered, but if the timeline's "playhead" moves past it in the backward direction (from a postitive time to a negative time), the starting values must be rendered.
3554						if (prevRawPrevTime >= 0 && !(prevRawPrevTime === _tinyNum && this.data === "isPause")) {
3555							force = true;
3556						}
3557						this._rawPrevTime = rawPrevTime = (!suppressEvents || time || prevRawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient.
3558					}
3559				}
3560				if (!this._initted) { //if we render the very beginning (time == 0) of a fromTo(), we must force the render (normal tweens wouldn't need to render at a time of 0 when the prevTime was also 0). This is also mandatory to make sure overwriting kicks in immediately.
3561					force = true;
3562				}
3563			} else {
3564				this._totalTime = this._time = time;
3565
3566				if (this._easeType) {
3567					var r = time / duration, type = this._easeType, pow = this._easePower;
3568					if (type === 1 || (type === 3 && r >= 0.5)) {
3569						r = 1 - r;
3570					}
3571					if (type === 3) {
3572						r *= 2;
3573					}
3574					if (pow === 1) {
3575						r *= r;
3576					} else if (pow === 2) {
3577						r *= r * r;
3578					} else if (pow === 3) {
3579						r *= r * r * r;
3580					} else if (pow === 4) {
3581						r *= r * r * r * r;
3582					}
3583
3584					if (type === 1) {
3585						this.ratio = 1 - r;
3586					} else if (type === 2) {
3587						this.ratio = r;
3588					} else if (time / duration < 0.5) {
3589						this.ratio = r / 2;
3590					} else {
3591						this.ratio = 1 - (r / 2);
3592					}
3593
3594				} else {
3595					this.ratio = this._ease.getRatio(time / duration);
3596				}
3597			}
3598
3599			if (this._time === prevTime && !force) {
3600				return;
3601			} else if (!this._initted) {
3602				this._init();
3603				if (!this._initted || this._gc) { //immediateRender tweens typically won't initialize until the playhead advances (_time is greater than 0) in order to ensure that over
3603writing occurs properly. Also, if all of the tweening properties have been overwritten (which would cause _gc to be true, as set in _init()), we shouldn't continue otherwise an onStart callback could be called for example.
3604					return;
3605				} else if (!force && this._firstPT && ((this.vars.lazy !== false && this._duration) || (this.vars.lazy && !this._duration))) {
3606					this._time = this._totalTime = prevTime;
3607					this._rawPrevTime = prevRawPrevTime;
3608					_lazyTweens.push(this);
3609					this._lazy = [time, suppressEvents];
3610					return;
3611				}
3612				//_ease is initially set to defaultEase, so now that init() has run, _ease is set properly and we need to recalculate the ratio. Overall this is faster than using conditional logic earlier in the method to avoid having to set ratio twice because we only init() once but renderTime() gets called VERY frequently.
3613				if (this._time && !isComplete) {
3614					this.ratio = this._ease.getRatio(this._time / duration);
3615				} else if (isComplete && this._ease._calcEnd) {
3616					this.ratio = this._ease.getRatio((this._time === 0) ? 0 : 1);
3617				}
3618			}
3619			if (this._lazy !== false) { //in case a lazy render is pending, we should flush it because the new render is occurring now (imagine a lazy tween instantiating and then immediately the user calls tween.seek(tween.duration()), skipping to the end - the end render would be forced, and then if we didn't flush the lazy render, it'd fire AFTER the seek(), rendering it at the wrong time.
3620				this._lazy = false;
3621			}
3622			if (!this._active) if (!this._paused && this._time !== prevTime && time >= 0) {
3623				this._active = true;  //so that if the user renders a tween (as opposed to the timeline rendering it), the timeline is forced to re-render and align it with the proper time/frame on the next rendering cycle. Maybe the tween already finished but the user manually re-renders it as halfway done.
3624			}
3625			if (prevTime === 0) {
3626				if (this._startAt) {
3627					if (time >= 0) {
3628						this._startAt.render(time, suppressEvents, force);
3629					} else if (!callback) {
3630						callback = "_dummyGS"; //if no callback is defined, use a dummy value just so that the condition at the end evaluates as true because _startAt should render AFTER the normal render loop when the time is negative. We could handle this in a more intuitive way, of course, but the render loop is the MOST important thing to optimize, so this technique allows us to avoid adding extra conditional logic in a high-frequency area.
3631					}
3632				}
3633				if (this.vars.onStart) if (this._time !== 0 || duration === 0) if (!suppressEvents) {
3634					this._callback("onStart");
3635				}
3636			}
3637			pt = this._firstPT;
3638			while (pt) {
3639				if (pt.f) {
3640					pt.t[pt.p](pt.c * this.ratio + pt.s);
3641				} else {
3642					pt.t[pt.p] = pt.c * this.ratio + pt.s;
3643				}
3644				pt = pt._next;
3645			}
3646
3647			if (this._onUpdate) {
3648				if (time < 0) if (this._startAt && time !== -0.0001) { //if the tween is positioned at the VERY beginning (_startTime 0) of its parent timeline, it's illegal for the playhead to go back further, so we should not render the recorded startAt values.
3649					this._startAt.render(time, suppressEvents, force); //note: for performance reasons, we tuck this conditional logic inside less traveled areas (most tweens don't have an onUpdate). We'd just have it at the end before the onComplete, but the values should be updated before any onUpdate is called, so we ALSO put it here and then if it's not called, we do so later near the onComplete.
3650				}
3651				if (!suppressEvents) if (this._time !== prevTime || isComplete) {
3652					this._callback("onUpdate");
3653				}
3654			}
3655			if (callback) if (!this._gc || force) { //check _gc because there's a chance that kill() could be called in an onUpdate
3656				if (time < 0 && this._startAt && !this._onUpdate && time !== -0.0001) { //-0.0001 is a special value that we use when looping back to the beginning of a repeated TimelineMax, in which case we shouldn't render the _startAt values.
3657					this._startAt.render(time, suppressEvents, force);
3658				}
3659				if (isComplete) {
3660					if (this._timeline.autoRemoveChildren) {
3661						this._enabled(false, false);
3662					}
3663					this._active = false;
3664				}
3665				if (!suppressEvents && this.vars[callback]) {
3666					this._callback(callback);
3667				}
3668				if (duration === 0 && this._rawPrevTime === _tinyNum && rawPrevTime !== _tinyNum) { //the onComplete or onReverseComplete could trigger movement of the playhead and for zero-duration tweens (which must discern direction) that land directly back on their start time, we don't want to fire again on the next render. Think of several addPause()'s in a timeline that forces the playhead to a certain spot, but what if it's already paused and another tween is tweening the "time" of the timeline? Each time it moves [forward] past that spot, it would move back, and since suppressEvents is true, it'd reset _rawPrevTime to _tinyNum so that when it begins again, the callback would fire (so ultimately it could bounce back and forth during that tween). Again, this is a very uncommon sce
3668nario, but possible nonetheless.
3669					this._rawPrevTime = 0;
3670				}
3671			}
3672		};
3673
3674		p._kill = function(vars, target, overwritingTween) {
3675			if (vars === "all") {
3676				vars = null;
3677			}
3678			if (vars == null) if (target == null || target === this.target) {
3679				this._lazy = false;
3680				return this._enabled(false, false);
3681			}
3682			target = (typeof(target) !== "string") ? (target || this._targets || this.target) : TweenLite.selector(target) || target;
3683			var simultaneousOverwrite = (overwritingTween && this._time && overwritingTween._startTime === this._startTime && this._timeline === overwritingTween._timeline),
3684				i, overwrittenProps, p, pt, propLookup, changed, killProps, record, killed;
3685			if ((_isArray(target) || _isSelector(target)) && typeof(target[0]) !== "number") {
3686				i = target.length;
3687				while (--i > -1) {
3688					if (this._kill(vars, target[i], overwritingTween)) {
3689						changed = true;
3690					}
3691				}
3692			} else {
3693				if (this._targets) {
3694					i = this._targets.length;
3695					while (--i > -1) {
3696						if (target === this._targets[i]) {
3697							propLookup = this._propLookup[i] || {};
3698							this._overwrittenProps = this._overwrittenProps || [];
3699							overwrittenProps = this._overwrittenProps[i] = vars ? this._overwrittenProps[i] || {} : "all";
3700							break;
3701						}
3702					}
3703				} else if (target !== this.target) {
3704					return false;
3705				} else {
3706					propLookup = this._propLookup;
3707					overwrittenProps = this._overwrittenProps = vars ? this._overwrittenProps || {} : "all";
3708				}
3709
3710				if (propLookup) {
3711					killProps = vars || propLookup;
3712					record = (vars !== overwrittenProps && overwrittenProps !== "all" && vars !== propLookup && (typeof(vars) !== "object" || !vars._tempKill)); //_tempKill is a super-secret way to delete a particular tweening property but NOT have it remembered as an official overwritten property (like in BezierPlugin)
3713					if (overwritingTween && (TweenLite.onOverwrite || this.vars.onOverwrite)) {
3714						for (p in killProps) {
3715							if (propLookup[p]) {
3716								if (!killed) {
3717									killed = [];
3718								}
3719								killed.push(p);
3720							}
3721						}
3722						if ((killed || !vars) && !_onOverwrite(this, overwritingTween, target, killed)) { //if the onOverwrite returned false, that means the user wants to override the overwriting (cancel it).
3723							return false;
3724						}
3725					}
3726
3727					for (p in killProps) {
3728						if ((pt = propLookup[p])) {
3729							if (simultaneousOverwrite) { //if another tween overwrites this one and they both start at exactly the same time, yet this tween has already rendered once (for example, at 0.001) because it's first in the queue, we should revert the values to where they were at 0 so that the starting values aren't contaminated on the overwriting tween.
3730								if (pt.f) {
3731									pt.t[pt.p](pt.s);
3732								} else {
3733									pt.t[pt.p] = pt.s;
3734								}
3735								changed = true;
3736							}
3737							if (pt.pg && pt.t._kill(killProps)) {
3738								changed = true; //some plugins need to be notified so they can perform cleanup tasks first
3739							}
3740							if (!pt.pg || pt.t._overwriteProps.length === 0) {
3741								if (pt._prev) {
3742									pt._prev._next = pt._next;
3743								} else if (pt === this._firstPT) {
3744									this._firstPT = pt._next;
3745								}
3746								if (pt._next) {
3747									pt._next._prev = pt._prev;
3748								}
3749								pt._next = pt._prev = null;
3750							}
3751							delete propLookup[p];
3752						}
3753						if (record) {
3754							overwrittenProps[p] = 1;
3755						}
3756					}
3757					if (!this._firstPT && this._initted) { //if all tweening properties are killed, kill the tween. Without this line, if there's a tween with multiple targets and then you killTweensOf() each target individually, the tween would technically still remain active and fire its onComplete even though there aren't any more properties tweening.
3758						this._enabled(false, false);
3759					}
3760				}
3761			}
3762			return changed;
3763		};
3764
3765		p.invalidate = function() {
3766			if (this._notifyPluginsOfEnabled) {
3767				TweenLite._onPluginEvent("_onDisable", this);
3768			}
3769			this._firstPT = this._overwrittenProps = this._startAt = this._onUpdate = null;
3770			this._notifyPluginsOfEnabled = this._active = this._lazy = false;
3771			this._propLookup = (this._targets) ? {} : [];
3772			Animation.prototype.invalidate.call(this);
3773			if (this.vars.immediateRender) {
3774				this._time = -_tinyNum; //forces a render without having to set the render() "force" parameter to true because we want to allow lazying by default (using the "force" parameter always forces an immediate full render)
3775				this.render(-this._delay);
3776			}
3777			return this;
3778		};
3779
3780		p._enabled = function(enabled, ignoreTimeline) {
3781			if (!_tickerActive) {
3782				_ticker.wake();
3783			}
3784			if (enabled && this._gc) {
3785				var targets = this._targets,
3786					i;
3787				if (targets) {
3788					i = targets.length;
3789					while (--i > -1) {
3790						this._siblings[i] = _register(targets[i], this, true);
3791					}
3792				} else {
3793					this._siblings = _register(this.target, this, true);
3794				}
3795			}
3796			Animation.prototype._enabled.call(this, enabled, ignoreTimeline);
3797			if (this._notifyPluginsOfEnabled) if (this._firstPT) {
3798				return TweenLite._onPluginEvent((enabled ? "_onEnable" : "_onDisable"), this);
3799			}
3800			return false;
3801		};
3802
3803
3804//----TweenLite static methods -----------------------------------------------------
3805
3806		TweenLite.to = function(target, duration, vars) {
3807			return new TweenLite(target, duration, vars);
3808		};
3809
3810		TweenLite.from = function(target, duration, vars) {
3811			vars.runBackwards = true;
3812			vars.immediateRender = (vars.immediateRender != false);
3813			return new TweenLite(target, duration, vars);
3814		};
3815
3816		TweenLite.fromTo = function(target, duration, fromVars, toVars) {
3817			toVars.startAt = fromVars;
3818			toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
3819			return new TweenLite(target, duration, toVars);
3820		};
3821
3822		TweenLite.delayedCall = function(delay, callback, params, scope, useFrames) {
3823			return new TweenLite(callback, 0, {delay:delay, onComplete:callback, onCompleteParams:params, callbackScope:scope, onReverseComplete:callback, onReverseCompleteParams:params, immediateRender:false, lazy:false, useFrames:useFrames, overwrite:0});
3824		};
3825
3826		TweenLite.set = function(target, vars) {
3827			return new TweenLite(target, 0, vars);
3828		};
3829
3830		TweenLite.getTweensOf = function(target, onlyActive) {
3831			if (target == null) { return []; }
3832			target = (typeof(target) !== "string") ? target : TweenLite.selector(target) || target;
3833			var i, a, j, t;
3834			if ((_isArray(target) || _isSelector(target)) && typeof(target[0]) !== "number") {
3835				i = target.length;
3836				a = [];
3837				while (--i > -1) {
3838					a = a.concat(TweenLite.getTweensOf(target[i], onlyActive));
3839				}
3840				i = a.length;
3841				//now get rid of any duplicates (tweens of arrays of objects could cause duplicates)
3842				while (--i > -1) {
3843					t = a[i];
3844					j = i;
3845					while (--j > -1) {
3846						if (t === a[j]) {
3847							a.splice(i, 1);
3848						}
3849					}
3850				}
3851			} else {
3852				a = _register(target).concat();
3853				i = a.length;
3854				while (--i > -1) {
3855					if (a[i]._gc || (onlyActive && !a[i].isActive())) {
3856						a.splice(i, 1);
3857					}
3858				}
3859			}
3860			return a;
3861		};
3862
3863		TweenLite.killTweensOf = TweenLite.killDelayedCallsTo = function(target, onlyActive, vars) {
3864			if (typeof(onlyActive) === "object") {
3865				vars = onlyActive; //for backwards compatibility (before "onlyActive" parameter was inserted)
3866				onlyActive = false;
3867			}
3868			var a = TweenLite.getTweensOf(target, onlyActive),
3869				i = a.length;
3870			while (--i > -1) {
3871				a[i]._kill(vars, target);
3872			}
3873		};
3874
3875
3876
3877/*
3878 * ----------------------------------------------------------------
3879 * TweenPlugin   (could easily be split out as a separate file/class, but included for ease of use (so that people don't need to include another script call before loading plugins which is easy to forget)
3880 * ----------------------------------------------------------------
3881 */
3882		var TweenPlugin = _class("plugins.TweenPlugin", function(props, priority) {
3883					this._overwriteProps = (props || "").split(",");
3884					this._propName = this._overwriteProps[0];
3885					this._priority = priority || 0;
3886					this._super = TweenPlugin.prototype;
3887				}, true);
3888
3889		p = TweenPlugin.prototype;
3890		TweenPlugin.version = "1.18.0";
3891		TweenPlugin.API = 2;
3892		p._firstPT = null;
3893		p._addTween = _addPropTween;
3894		p.setRatio = _setRatio;
3895
3896		p._kill = function(lookup) {
3897			var a = this._overwriteProps,
3898				pt = this._firstPT,
3899				i;
3900			if (lookup[this._propName] != null) {
3901				this._overwriteProps = [];
3902			} else {
3903				i = a.length;
3904				while (--i > -1) {
3905					if (lookup[a[i]] != null) {
3906						a.splice(i, 1);
3907					}
3908				}
3909			}
3910			while (pt) {
3911				if (lookup[pt.n] != null) {
3912					if (pt._next) {
3913						pt._next._prev = pt._prev;
3914					}
3915					if (pt._prev) {
3916						pt._prev._next = pt._next;
3917						pt._prev = null;
3918					} else if (this._firstPT === pt) {
3919						this._firstPT = pt._next;
3920					}
3921				}
3922				pt = pt._next;
3923			}
3924			return false;
3925		};
3926
3927		p._roundProps = function(lookup, value) {
3928			var pt = this._firstPT;
3929			while (pt) {
3930				if (lookup[this._propName] || (pt.n != null && lookup[ pt.n.split(this._propName + "_").join("") ])) { //some properties that are very plugin-specific add a prefix named after the _propName plus an underscore, so we need to ignore that extra stuff here.
3931					pt.r = value;
3932				}
3933				pt = pt._next;
3934			}
3935		};
3936
3937		TweenLite._onPluginEvent = function(type, tween) {
3938			var pt = tween._firstPT,
3939				changed, pt2, first, last, next;
3940			if (type === "_onInitAllProps") {
3941				//sorts the PropTween linked list in order of priority because some plugins need to render earlier/later than others, like MotionBlurPlugin applies its effects after all x/y/alpha tweens have rendered on each frame.
3942				while (pt) {
3943					next = pt._next;
3944					pt2 = first;
3945					while (pt2 && pt2.pr > pt.pr) {
3946						pt2 = pt2._next;
3947					}
3948					if ((pt._prev = pt2 ? pt2._prev : last)) {
3949						pt._prev._next = pt;
3950					} else {
3951						first = pt;
3952					}
3953					if ((pt._next = pt2)) {
3954						pt2._prev = pt;
3955					} else {
3956						last = pt;
3957					}
3958					pt = next;
3959				}
3960				pt = tween._firstPT = first;
3961			}
3962			while (pt) {
3963				if (pt.pg) if (typeof(pt.t[type]) === "function") if (pt.t[type]()) {
3964					changed = true;
3965				}
3966				pt = pt._next;
3967			}
3968			return changed;
3969		};
3970
3971		TweenPlugin.activate = function(plugins) {
3972			var i = plugins.length;
3973			while (--i > -1) {
3974				if (plugins[i].API === TweenPlugin.API) {
3975					_plugins[(new plugins[i]())._propName] = plugins[i];
3976				}
3977			}
3978			return true;
3979		};
3980
3981		//provides a more concise way to define plugins that have no depen
3981dencies besides TweenPlugin and TweenLite, wrapping common boilerplate stuff into one function (added in 1.9.0). You don't NEED to use this to define a plugin - the old way still works and can be useful in certain (rare) situations.
3982		_gsDefine.plugin = function(config) {
3983			if (!config || !config.propName || !config.init || !config.API) { throw "illegal plugin definition."; }
3984			var propName = config.propName,
3985				priority = config.priority || 0,
3986				overwriteProps = config.overwriteProps,
3987				map = {init:"_onInitTween", set:"setRatio", kill:"_kill", round:"_roundProps", initAll:"_onInitAllProps"},
3988				Plugin = _class("plugins." + propName.charAt(0).toUpperCase() + propName.substr(1) + "Plugin",
3989					function() {
3990						TweenPlugin.call(this, propName, priority);
3991						this._overwriteProps = overwriteProps || [];
3992					}, (config.global === true)),
3993				p = Plugin.prototype = new TweenPlugin(propName),
3994				prop;
3995			p.constructor = Plugin;
3996			Plugin.API = config.API;
3997			for (prop in map) {
3998				if (typeof(config[prop]) === "function") {
3999					p[map[prop]] = config[prop];
4000				}
4001			}
4002			Plugin.version = config.version;
4003			TweenPlugin.activate([Plugin]);
4004			return Plugin;
4005		};
4006
4007
4008		//now run through all the dependencies discovered and if any are missing, log that to the console as a warning. This is why it's best to have TweenLite load last - it can check all the dependencies for you.
4009		a = window._gsQueue;
4010		if (a) {
4011			for (i = 0; i < a.length; i++) {
4012				a[i]();
4013			}
4014			for (p in _defLookup) {
4015				if (!_defLookup[p].func) {
4016					window.console.log("GSAP encountered missing dependency: com.greensock." + p);
4017				}
4018			}
4019		}
4020
4021		_tickerActive = false; //ensures that the first official animation forces a ticker.tick() to update the time when it is instantiated
4022
4023})((typeof(module) !== "undefined" && module.exports && typeof(global) !== "undefined") ? global : this || window, "TweenLite");
4024
4025/*!
4026 * VERSION: 1.18.0
4027 * DATE: 2015-08-29
4028 * UPDATES AND DOCS AT: http://greensock.com
4029 *
4030 * @license Copyright (c) 2008-2015, GreenSock. All rights reserved.
4031 * This work is subject to the terms at http://greensock.com/standard-license or for
4032 * Club GreenSock members, the software agreement that was issued with your membership.
4033 * 
4034 * @author: Jack Doyle, [email protected]
4035 */
4036var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(global) !== "undefined") ? global : this || window; //helps ensure compatibility with AMD/RequireJS and CommonJS/Node
4037(_gsScope._gsQueue || (_gsScope._gsQueue = [])).push( function() {
4038
4039	"use strict";
4040
4041	_gsScope._gsDefine("TimelineLite", ["core.Animation","core.SimpleTimeline","TweenLite"], function(Animation, SimpleTimeline, TweenLite) {
4042
4043		var TimelineLite = function(vars) {
4044				SimpleTimeline.call(this, vars);
4045				this._labels = {};
4046				this.autoRemoveChildren = (this.vars.autoRemoveChildren === true);
4047				this.smoothChildTiming = (this.vars.smoothChildTiming === true);
4048				this._sortChildren = true;
4049				this._onUpdate = this.vars.onUpdate;
4050				var v = this.vars,
4051					val, p;
4052				for (p in v) {
4053					val = v[p];
4054					if (_isArray(val)) if (val.join("").indexOf("{self}") !== -1) {
4055						v[p] = this._swapSelfInParams(val);
4056					}
4057				}
4058				if (_isArray(v.tweens)) {
4059					this.add(v.tweens, 0, v.align, v.stagger);
4060				}
4061			},
4062			_tinyNum = 0.0000000001,
4063			TweenLiteInternals = TweenLite._internals,
4064			_internals = TimelineLite._internals = {},
4065			_isSelector = TweenLiteInternals.isSelector,
4066			_isArray = TweenLiteInternals.isArray,
4067			_lazyTweens = TweenLiteInternals.lazyTweens,
4068			_lazyRender = TweenLiteInternals.lazyRender,
4069			_globals = _gsScope._gsDefine.globals,
4070			_copy = function(vars) {
4071				var copy = {}, p;
4072				for (p in vars) {
4073					copy[p] = vars[p];
4074				}
4075				return copy;
4076			},
4077			_applyCycle = function(vars, targets, i) {
4078				var alt = vars.cycle,
4079					p, val;
4080				for (p in alt) {
4081					val = alt[p];
4082					vars[p] = (typeof(val) === "function") ? val.call(targets[i], i) : val[i % val.length];
4083				}
4084				delete vars.cycle;
4085			},
4086			_pauseCallback = _internals.pauseCallback = function() {},
4087			_slice = function(a) { //don't use [].slice because that doesn't work in IE8 with a NodeList that's returned by querySelectorAll()
4088				var b = [],
4089					l = a.length,
4090					i;
4091				for (i = 0; i !== l; b.push(a[i++]));
4092				return b;
4093			},
4094			p = TimelineLite.prototype = new SimpleTimeline();
4095
4096		TimelineLite.version = "1.18.0";
4097		p.constructor = TimelineLite;
4098		p.kill()._gc = p._forcingPlayhead = p._hasPause = false;
4099
4100		/* might use later...
4101		//translates a local time inside an animation to the corresponding time on the root/global timeline, factoring in all nesting and timeScales.
4102		function localToGlobal(time, animation) {
4103			while (animation) {
4104				time = (time / animation._timeScale) + animation._startTime;
4105				animation = animation.timeline;
4106			}
4107			return time;
4108		}
4109
4110		//translates the supplied time on the root/global timeline into the corresponding local time inside a particular animation, factoring in all nesting and timeScales
4111		function globalToLocal(time, animation) {
4112			var scale = 1;
4113			time -= localToGlobal(0, animation);
4114			while (animation) {
4115				scale *= animation._timeScale;
4116				animation = animation.timeline;
4117			}
4118			return time * scale;
4119		}
4120		*/
4121
4122		p.to = function(target, duration, vars, position) {
4123			var Engine = (vars.repeat && _globals.TweenMax) || TweenLite;
4124			return duration ? this.add( new Engine(target, duration, vars), position) : this.set(target, vars, position);
4125		};
4126
4127		p.from = function(target, duration, vars, position) {
4128			return this.add( ((vars.repeat && _globals.TweenMax) || TweenLite).from(target, duration, vars), position);
4129		};
4130
4131		p.fromTo = function(target, duration, fromVars, toVars, position) {
4132			var Engine = (toVars.repeat && _globals.TweenMax) || TweenLite;
4133			return duration ? this.add( Engine.fromTo(target, duration, fromVars, toVars), position) : this.set(target, toVars, position);
4134		};
4135
4136		p.staggerTo = function(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
4137			var tl = new TimelineLite({onComplete:onCompleteAll, onCompleteParams:onCompleteAllParams, callbackScope:onCompleteAllScope, smoothChildTiming:this.smoothChildTiming}),
4138				cycle = vars.cycle,
4139				copy, i;
4140			if (typeof(targets) === "string") {
4141				targets = TweenLite.selector(targets) || targets;
4142			}
4143			targets = targets || [];
4144			if (_isSelector(targets)) { //senses if the targets object is a selector. If it is, we should translate it into an array.
4145				targets = _slice(targets);
4146			}
4147			stagger = stagger || 0;
4148			if (stagger < 0) {
4149				targets = _slice(targets);
4150				targets.reverse();
4151				stagger *= -1;
4152			}
4153			for (i = 0; i < targets.length; i++) {
4154				copy = _copy(vars);
4155				if (copy.startAt) {
4156					copy.startAt = _copy(copy.startAt);
4157					if (copy.startAt.cycle) {
4158						_applyCycle(copy.startAt, targets, i);
4159					}
4160				}
4161				if (cycle) {
4162					_applyCycle(copy, targets, i);
4163				}
4164				tl.to(targets[i], duration, copy, i * stagger);
4165			}
4166			return this.add(tl, position);
4167		};
4168
4169		p.staggerFrom = function(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
4170			vars.immediateRender = (vars.immediateRender != false);
4171			vars.runBackwards = true;
4172			return this.staggerTo(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
4173		};
4174
4175		p.staggerFromTo = function(targets, duration, fromVars, toVars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
4176			toVars.startAt = fromVars;
4177			toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
4178			return this.staggerTo(targets, duration, toVars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
4179		};
4180
4181		p.call = function(callback, params, scope, position) {
4182			return this.add( TweenLite.delayedCall(0, callback, params, scope), position);
4183		};
4184
4185		p.set = function(target, vars, position) {
4186			position = this._parseTimeOrLabel(position, 0, true);
4187			if (vars.immediateRender == null) {
4188				vars.immediateRender = (position === this._time && !this._paused);
4189			}
4190			return this.add( new TweenLite(target, 0, vars), position);
4191		};
4192
4193		TimelineLite.exportRoot = function(vars, ignoreDelayedCalls) {
4194			vars = vars || {};
4195			if (vars.smoothChildTiming == null) {
4196				vars.smoothChildTiming = true;
4197			}
4198			var tl = new TimelineLite(vars),
4199				root = tl._timeline,
4200				tween, next;
4201			if (ignoreDelayedCalls == null) {
4202				ignoreDelayedCalls = true;
4203			}
4204			root._remove(tl, true);
4205			tl._startTime = 0;
4206			tl._rawPrevTime = tl._time = tl._totalTime = root._time;
4207			tween = root._first;
4208			while (tween) {
4209				next = tween._next;
4210				if (!ignoreDelayedCalls || !(tween instanceof TweenLite && tween.target === tween.vars.onComplete)) {
4211					tl.add(tween, tween._startTime - tween._delay);
4212				}
4213				tween = next;
4214			}
4215			root.add(tl, 0);
4216			return tl;
4217		};
4218
4219		p.add = function(value, position, align, stagger) {
4220			var curTime, l, i, child, tl, beforeRawTime;
4221			if (typeof(position) !== "number") {
4222				position = this._parseTimeOrLabel(position, 0, true, value);
4223			}
4224			if (!(value instanceof Animation)) {
4225				if ((value instanceof Array) || (value && value.push && _isArray(value))) {
4226					align = align || "normal";
4227					stagger = stagger || 0;
4228					curTime = position;
4229					l = value.length;
4230					for (i = 0; i < l; i++) {
4231						if (_isArray(child = value[i])) {
4232							child = new TimelineLite({tweens:child});
4233						}
4234						this.add(child, curTime);
4235						if (typeof(child) !== "string" && typeof(child) !== "function") {
4236							if (align === "sequence") {
4237								curTime = child._startTime + (child.totalDuration() / child._timeScale);
4238							} else if (align === "start") {
4239								child._startTime -= child.delay();
4240							}
4241						}
4242						curTime += stagger;
4243					}
4244					return this._uncache(true);
4245				} else if (typeof(value) === "string") {
4246					return this.addLabel(value, position);
4247				} else if (typeof(value) === "function") {
4248					value = TweenLite.delayedCall(0, value);
4249				} else {
4250					throw("Cannot add " + value + " into the timeline; it is not a tween, timeline, function, or string.");
4251				}
4252			}
4253
4254			SimpleTimeline.prototype.add.call(this, value, position);
4255
4256			//if the timeline has already ended but the inserted tween/timeline extends the duration, we should enable this timeline again so that it renders properly. We should also align the playhead with the parent timeline's when appropriate.
4257			if (this._gc || this._time === this._duration) if (!this._paused) if (this._duration < this.duration()) {
4258				//in case any of the ancestors had completed but should now be enabled...
4259				tl = this;
4260				beforeRawTime = (tl.rawTime() > value._startTime); //if the tween is placed on the timeline so that it starts BEFORE the current rawTime, we should align the playhead (move the timeline). This is because sometimes users will create a timeline, let it finish, and much later append a tween and expect it to run instead of jumping to its end state. While technically one could argue that it should jump to its end state, that's not what users intuitively expect.
4261				while (tl._timeline) {
4262					if (beforeRawTime && tl._timeline.smoothChildTiming) {
4263						tl.totalTime(tl._totalTime, true); //moves the timeline (shifts its startTime) if necessary, and also enables it.
4264					} else if (tl._gc) {
4265						tl._enabled(true, false);
4266					}
4267					tl = tl._timeline;
4268				}
4269			}
4270
4271			return this;
4272		};
4273
4274		p.remove = function(value) {
4275			if (value instanceof Animation) {
4276				this._remove(value, false);
4277				var tl = value._timeline = value.vars.useFrames ? Animation._rootFramesTimeline : Animation._rootTimeline; //now that it's removed, default it to the root timeline so that if it gets played again, it doesn't jump back into this timeline.
4278				value._startTime = (value._paused ? value._pauseTime : tl._time) - ((!value._reversed ? value._totalTime : value.totalDuration() - value._totalTime) / value._timeScale); //ensure that if it gets played again, the timing is correct.
4279				return this;
4280			} else if (value instanceof Array || (value && value.push && _isArray(value))) {
4281				var i = value.length;
4282				while (--i > -1) {
4283					this.remove(value[i]);
4284				}
4285				return this;
4286			} else if (typeof(value) === "string") {
4287				return this.removeLabel(value);
4288			}
4289			return this.kill(null, value);
4290		};
4291
4292		p._remove = function(tween, skipDisable) {
4293			SimpleTimeline.prototype._remove.call(this, tween, skipDisable);
4294			var last = this._last;
4295			if (!last) {
4296				this._time = this._totalTime = this._duration = this._totalDuration = 0;
4297			} else if (this._time > last._startTime + last._totalDuration / last._timeScale) {
4298				this._time = this.duration();
4299				this._totalTime = this._totalDuration;
4300			}
4301			return this;
4302		};
4303
4304		p.append = function(value, offsetOrLabel) {
4305			return this.add(value, this._parseTimeOrLabel(null, offsetOrLabel, true, value));
4306		};
4307
4308		p.insert = p.insertMultiple = function(value, position, align, stagger) {
4309			return this.add(value, position || 0, align, stagger);
4310		};
4311
4312		p.appendMultiple = function(tweens, offsetOrLabel, align, stagger) {
4313			return this.add(tweens, this._parseTimeOrLabel(null, offsetOrLabel, true, tweens), align, stagger);
4314		};
4315
4316		p.addLabel = function(label, position) {
4317			this._labels[label] = this._parseTimeOrLabel(position);
4318			return this;
4319		};
4320
4321		p.addPause = function(position, callback, params, scope) {
4322			var t = TweenLite.delayedCall(0, _pauseCallback, params, scope || this);
4323			t.vars.onComplete = t.vars.onReverseComplete = callback;
4324			t.data = "isPause";
4325			this._hasPause = true;
4326			return this.add(t, position);
4327		};
4328
4329		p.removeLabel = function(label) {
4330			delete this._labels[label];
4331			return this;
4332		};
4333
4334		p.getLabelTime = function(label) {
4335			return (this._labels[label] != null) ? this._labels[label] : -1;
4336		};
4337
4338		p._parseTimeOrLabel = function(timeOrLabel, offsetOrLabel, appendIfAbsent, ignore) {
4339			var i;
4340			//if we're about to add a tween/timeline (or an array of them) that's already a child of this timeline, we should remove it first so that it doesn't contaminate the duration().
4341			if (ignore instanceof Animation && ignore.timeline === this) {
4342				this.remove(ignore);
4343			} else if (ignore && ((ignore instanceof Array) || (ignore.push && _isArray(ignore)))) {
4344				i = ignore.length;
4345				while (--i > -1) {
4346					if (ignore[i] instanceof Animation && ignore[i].timeline === this) {
4347						this.remove(ignore[i]);
4348					}
4349				}
4350			}
4351			if (typeof(offsetOrLabel) === "string") {
4352				return this._parseTimeOrLabel(offsetOrLabel, (appendIfAbsent && typeof(timeOrLabel) === "number" && this._labels[offsetOrLabel] == null) ? timeOrLabel - this.duration() : 0, appendIfAbsent);
4353			}
4354			offsetOrLabel = offsetOrLabel || 0;
4355			if (typeof(timeOrLabel) === "string" && (isNaN(timeOrLabel) || this._labels[timeOrLabel] != null)) { //if the string is a number like "1", check to see if there's a label with that name, otherwise interpret it as a number (absolute value).
4356				i = timeOrLabel.indexOf("=");
4357				if (i === -1) {
4358					if (this._labels[timeOrLabel] == null) {
4359						return appendIfAbsent ? (this._labels[timeOrLabel] = this.duration() + offsetOrLabel) : offsetOrLabel;
4360					}
4361					return this._labels[timeOrLabel] + offsetOrLabel;
4362				}
4363				offsetOrLabel = parseInt(timeOrLabel.charAt(i-1) + "1", 10) * Number(timeOrLabel.substr(i+1));
4364				timeOrLabel = (i > 1) ? this._parseTimeOrLabel(timeOrLabel.substr(0, i-1), 0, appendIfAbsent) : this.duration();
4365			} else if (timeOrLabel == null) {
4366				timeOrLabel = this.duration();
4367			}
4368			return Number(timeOrLabel) + offsetOrLabel;
4369		};
4370
4371		p.seek = function(position, suppressEvents) {
4372			return this.totalTime((typeof(position) === "number") ? position : this._parseTimeOrLabel(position), (suppressEvents !== false));
4373		};
4374
4375		p.stop = function() {
4376			return this.paused(true);
4377		};
4378
4379		p.gotoAndPlay = function(position, suppressEvents) {
4380			return this.play(position, suppressEvents);
4381		};
4382
4383		p.gotoAndStop = function(position, suppressEvents) {
4384			return this.pause(position, suppressEvents);
4385		};
4386
4387		p.render = function(time, suppressEvents, force) {
4388			if (this._gc) {
4389				this._enabled(true, false);
4390			}
4391			var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(),
4392				prevTime = this._time,
4393				prevStart = this._startTime,
4394				prevTimeScale = this._timeScale,
4395				prevPaused = this._paused,
4396				tween, isComplete, next, callback, internalForce, pauseTween;
4397			if (time >= totalDur) {
4398				this._totalTime = this._time = totalDur;
4399				if (!this._reversed) if (!this._hasPausedChild()) {
4400					isComplete = true;
4401					callback = "onComplete";
4402					internalForce = !!this._timeline.autoRemoveChildren; //otherwise, if the animation is unpaused/activated after it's already finished, it doesn't get removed from the parent timeline.
4403					if (this._duration === 0) if (time === 0 || this._rawPrevTime < 0 || this._rawPrevTime === _tinyNum) if (this._rawPrevTime !== time && this._first) {
4404						internalForce = true;
4405						if (this._rawPrevTime > _tinyNum) {
4406							callback = "onReverseComplete";
4407						}
4408					}
4409				}
4410				this._rawPrevTime = (this._duration || !suppressEvents || time || this._rawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration timeline or tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient.
4411				time = totalDur + 0.0001; //to avoid occasional floating point rounding errors - sometimes child tweens/timelines were not being fully completed (their progress might be 0.999999999999998 instead of 1 because when _time - tween._startTime is performed, floating point errors would return a value that was SLIGHTLY off). Try (999999999999.7 - 999999999999) * 1 = 0.699951171875 instead of 0.7.
4412
4413			} else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
4414				this._totalTime = this._time = 0;
4415				if (prevTime !== 0 || (this._duration === 0 && this._rawPrevTime !== _tinyNum && (this._rawPrevTime > 0 || (time < 0 && this._rawPrevTime >= 0)))) {
4416					callback = "onReverseComplete";
4417					isComplete = this._reversed;
4418				}
4419				if (time < 0) {
4420					this._active = false;
4421					if (this._timeline.autoRemoveChildren && this._reversed) { //ensures proper GC if a timeline is resumed after it's finished reversing.
4422						internalForce = isComplete = true;
4423						callback = "onReverseComplete";
4424					} else if (this._rawPrevTime >= 0 && this._first) { //when going back beyond the start, force a render so that zero-duration tweens that sit at the very beginning render their start values properly. Otherwise, if the parent timeline's playhead lands exactly at this timeline's startTime, and then moves backwards, the zero-duration tweens at the beginning would still be at their end state.
4425						internalForce = true;
4426					}
4427					this._rawPrevTime = time;
4428				} else {
4429					this._rawPrevTime = (this._duration || !suppressEvents || time || this._rawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration timeline or tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient.
4430					if (time === 0 && isComplete) { //if there's a zero-duration tween at the very beginning of a timeline and the playhead lands EXACTLY at time 0, that tween will correctly render its end values, but we need to keep the timeline alive for one more render so that the beginning values render properly as the parent's playhead keeps moving beyond the begining. Imagine obj.x starts at 0 and then we do tl.set(obj, {x:100}).to(obj, 1, {x:200}) and then later we tl.reverse()...the goal is to have obj.x revert to 0. If the playhead happens to land on exactly 0, without this chunk of code, it'd complete the timeline and remove it from the rendering queue (not good).
4431						tween = this._first;
4432						while (tween && tween._startTime === 0) {
4433							if (!tween._duration) {
4434								isComplete = false;
4435							}
4436							tween = tween._next;
4437						}
4438					}
4439					time = 0; //to avoid occasional floating point rounding errors (could cause problems especially with zero-duration tweens at the very beginning of the timeline)
4440					if (!this._initted) {
4441						internalForce = true;
4442					}
4443				}
4444
4445			} else {
4446
4447				if (this._hasPause && !this._forcingPlayhead && !suppressEvents) {
4448					if (time >= prevTime) {
4449						tween = this._first;
4450						while (tween && tween._startTime <= time && !pauseTween) {
4451							if (!tween._duration) if (tween.data === "isPause" && !tween.ratio && !(tween._startTime === 0 && this._rawPrevTime === 0)) {
4452								pauseTween = tween;
4453							}
4454							tween = tween._next;
4455						}
4456					} else {
4457						tween = this._last;
4458						while (tween && tween._startTime >= time && !pauseTween) {
4459							if (!tween._duration) if (tween.data === "isPause" && tween._rawPrevTime > 0) {
4460								pauseTween = tween;
4461							}
4462							tween = tween._prev;
4463						}
4464					}
4465					if (pauseTween) {
4466						this._time = time = pauseTween._startTime;
4467						this._totalTime = time + (this._cycle * (this._totalDuration + this._repeatDelay));
4468					}
4469				}
4470
4471				this._totalTime = this._time = this._rawPrevTime = time;
4472			}
4473			if ((this._time === prevTime || !this._first) && !force && !internalForce && !pauseTween) {
4474				return;
4475			} else if (!this._initted) {
4476				this._initted = true;
4477			}
4478
4479			if (!this._active) if (!this._paused && this._time !== prevTime && time > 0) {
4480				this._active = true;  //so that if the user renders the timeline (as opposed to the parent timeline rendering it), it is forced to re-render and align it with the proper time/frame on the next rendering cycle. Maybe the timeline already finished but the user manually re-renders it as halfway done, for example.
4481			}
4482
4483			if (prevTime === 0) if (this.vars.onStart) if (this._time !== 0) if (!suppressEvents) {
4484				this._callback("onStart");
4485			}
4486
4487			if (this._time >= prevTime) {
4488				tween = this._first;
4489				while (tween) {
4490					next = tween._next; //record it here because the value could change after rendering...
4491					if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
4492						break;
4493					} else if (tween._active || (tween._startTime <= this._time && !tween._paused && !tween._gc)) {
4494						if (pauseTween === tween) {
4495							this.pause();
4496						}
4497						if (!tween._reversed) {
4498							tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
4499						} else {
4500							tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
4501						}
4502					}
4503					tween = next;
4504				}
4505			} else {
4506				tween = this._last;
4507				while (tween) {
4508					next = tween._prev; //record it here because the value could change after rendering...
4509					if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering
4510						break;
4511					} else if (tween._active || (tween._startTime <= prevTime && !tween._paused && !tween._gc)) {
4512						if (pauseTween === tween) {
4513							pauseTween = tween._prev; //the linked list is organized by _startTime, thus it's possible that a tween could start BEFORE the pause and end after it, in which case it would be positioned before the pause tween in the linked list, but we should render it before we pause() the timeline and cease rendering. This is only a concern when going in reverse.
4514							while (pauseTween && pauseTween.endTime() > this._time) {
4515								pauseTween.render( (pauseTween._reversed ? pauseTween.totalDuration() - ((time - pauseTween._startTime) * pauseTween._timeScale) : (time - pauseTween._startTime) * pauseTween._timeScale), suppressEvents, force);
4516								pauseTween = pauseTween._prev;
4517							}
4518							pauseTween = null;
4519							this.pause();
4520						}
4521						if (!tween._reversed) {
4522							tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force);
4523						} else {
4524							tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force);
4525						}
4526					}
4527					tween = next;
4528				}
4529			}
4530
4531			if (this._onUpdate) if (!suppressEvents) {
4532				if (_lazyTweens.length) { //in case rendering caused any tweens to lazy-init, we should render them because typically when a timeline finishes, users expect things to have rendered fully. Imagine an onUpdate on a timeline that reports/checks tweened values.
4533					_lazyRender();
4534				}
4535				this._callback("onUpdate");
4536			}
4537
4538			if (callback) if (!this._gc) if (prevStart === this._startTime || prevTimeScale !== this._timeScale) if (this._time === 0 || totalDur >= this.totalDuration()) { //if one of the tweens that was rendered altered this timeline's startTime (like if an onComplete reversed the timeline), it probably isn't complete. If it is, don't worry, because whatever call altered the startTime would complete if it was necessary at the new time. The only exception is the timeScale property. Also check _gc because there's a chance that kill() could be called in an onUpdate
4539				if (isComplete) {
4540					if (_lazyTweens.length) { //in case rendering caused any tweens to lazy-init, we should render them because typically when a timeline finishes, users expect things to have rendered fully. Imagine an onComplete on a timeline that reports/checks tweened values.
4541						_lazyRender();
4542					}
4543					if (this._timeline.autoRemoveChildren) {
4544						this._enabled(false, false);
4545					}
4546					this._active = false;
4547				}
4548				if (!suppressEvents && this.vars[callback]) {
4549					this._callback(callback);
4550				}
4551			}
4552		};
4553
4554		p._hasPausedChild = function() {
4555			var tween = this._first;
4556			while (tween) {
4557				if (tween._paused || ((tween instanceof TimelineLite) && tween._hasPausedChild())) {
4558					return true;
4559				}
4560				tween = tween._next;
4561			}
4562			return false;
4563		};
4564
4565		p.getChildren = function(nested, tweens, timelines, ignoreBeforeTime) {
4566			ignoreBeforeTime = ignoreBeforeTime || -9999999999;
4567			var a = [],
4568				tween = this._first,
4569				cnt = 0;
4570			while (tween) {
4571				if (tween._startTime < ignoreBeforeTime) {
4572					//do nothing
4573				} else if (tween instanceof TweenLite) {
4574					if (tweens !== false) {
4575						a[cnt++] = tween;
4576					}
4577				} else {
4578					if (timelines !== false) {
4579						a[cnt++] = tween;
4580					}
4581					if (nested !== false) {
4582						a = a.concat(tween.getChildren(true, tweens, timelines));
4583						cnt = a.length;
4584					}
4585				}
4586				tween = tween._next;
4587			}
4588			return a;
4589		};
4590
4591		p.getTweensOf = function(target, nested) {
4592			var disabled = this._gc,
4593				a = [],
4594				cnt = 0,
4595				tweens, i;
4596			if (disabled) {
4597				this._enabled(true, true); //getTweensOf() filters out disabled tweens, and we have to mark them as _gc = true when the timeline completes in order to allow clean garbage collection, so temporarily re-enable the timeline here.
4598			}
4599			tweens = TweenLite.getTweensOf(target);
4600			i = tweens.length;
4601			while (--i > -1) {
4602				if (tweens[i].timeline === this || (nested && this._contains(tweens[i]))) {
4603					a[cnt++] = tweens[i];
4604				}
4605			}
4606			if (disabled) {
4607				this._enabled(false, true);
4608			}
4609			return a;
4610		};
4611
4612		p.recent = function() {
4613			return this._recent;
4614		};
4615
4616		p._contains = function(tween) {
4617			var tl = tween.timeline;
4618			while (tl) {
4619				if (tl === this) {
4620					return true;
4621				}
4622				tl = tl.timeline;
4623			}
4624			return false;
4625		};
4626
4627		p.shiftChildren = function(amount, adjustLabels, ignoreBeforeTime) {
4628			ignoreBeforeTime = ignoreBeforeTime || 0;
4629			var tween = this._first,
4630				labels = this._labels,
4631				p;
4632			while (tween) {
4633				if (tween._startTime >= ignoreBeforeTime) {
4634					tween._startTime += amount;
4635				}
4636				tween = tween._next;
4637			}
4638			if (adjustLabels) {
4639				for (p in labels) {
4640					if (labels[p] >= ignoreBeforeTime) {
4641						labels[p] += amount;
4642					}
4643				}
4644			}
4645			return this._uncache(true);
4646		};
4647
4648		p._kill = function(vars, target) {
4649			if (!vars && !target) {
4650				return this._enabled(false, false);
4651			}
4652			var tweens = (!target) ? this.getChildren(true, true, false) : this.getTweensOf(target),
4653				i = tweens.length,
4654				changed = false;
4655			while (--i > -1) {
4656				if (tweens[i]._kill(vars, target)) {
4657					changed = true;
4658				}
4659			}
4660			return changed;
4661		};
4662
4663		p.clear = function(labels) {
4664			var tweens = this.getChildren(false, true, true),
4665				i = tweens.length;
4666			this._time = this._totalTime = 0;
4667			while (--i > -1) {
4668				tweens[i]._enabled(false, false);
4669			}
4670			if (labels !== false) {
4671				this._labels = {};
4672			}
4673			return this._uncache(true);
4674		};
4675
4676		p.invalidate = function() {
4677			var tween = this._first;
4678			while (tween) {
4679				tween.invalidate();
4680				tween = tween._next;
4681			}
4682			return Animation.prototype.invalidate.call(this);;
4683		};
4684
4685		p._enabled = function(enabled, ignoreTimeline) {
4686			if (enabled === this._gc) {
4687				var tween = this._first;
4688				while (tween) {
4689					tween._enabled(enabled, true);
4690					tween = tween._next;
4691				}
4692			}
4693			return SimpleTimeline.prototype._enabled.call(this, enabled, ignoreTimeline);
4694		};
4695
4696		p.totalTime = function(time, suppressEvents, uncapped) {
4697			this._forcingPlayhead = true;
4698			var val = Animation.prototype.totalTime.apply(this, arguments);
4699			this._forcingPlayhead = false;
4700			return val;
4701		};
4702
4703		p.duration = function(value) {
4704			if (!arguments.length) {
4705				if (this._dirty) {
4706					this.totalDuration(); //just triggers recalculation
4707				}
4708				return this._duration;
4709			}
4710			if (this.duration() !== 0 && value !== 0) {
4711				this.timeScale(this._duration / value);
4712			}
4713			return this;
4714		};
4715
4716		p.totalDuration = function(value) {
4717			if (!arguments.length) {
4718				if (this._dirty) {
4719					var max = 0,
4720						tween = this._last,
4721						prevStart = 999999999999,
4722						prev, end;
4723					while (tween) {
4724						prev = tween._prev; //record it here in case the tween changes position in the sequence...
4725						if (tween._dirty) {
4726							tween.totalDuration(); //could change the tween._startTime, so make sure the tween's cache is clean before analyzing it.
4727						}
4728						if (tween._startTime > prevStart && this._sortChildren && !tween._paused) { //in case one of the tweens shifted out of order, it needs to be re-inserted into the correct position in the sequence
4729							this.add(tween, tween._startTime - tween._delay);
4730						} else {
4731							prevStart = tween._startTime;
4732						}
4733						if (tween._startTime < 0 && !tween._paused) { //children aren't allowed to have negative startTimes unless smoothChildTiming is true, so adjust here if one is found.
4734							max -= tween._startTime;
4735							if (this._timeline.smoothChildTiming) {
4736								this._startTime += tween._startTime / this._timeScale;
4737							}
4738							this.shiftChildren(-tween._startTime, false, -9999999999);
4739							prevStart = 0;
4740						}
4741						end = tween._startTime + (tween._totalDuration / tween._timeScale);
4742						if (end > max) {
4743							max = end;
4744						}
4745						tween = prev;
4746					}
4747					this._duration = this._totalDuration = max;
4748					this._dirty = false;
4749				}
4750				return this._totalDuration;
4751			}
4752			if (this.totalDuration() !== 0) if (value !== 0) {
4753				this.timeScale(this._totalDuration / value);
4754			}
4755			return this;
4756		};
4757
4758		p.paused = function(value) {
4759			if (!value) { //if there's a pause directly at the spot from where we're unpausing, skip it.
4760				var tween = this._first,
4761					time = this._time;
4762				while (tween) {
4763					if (tween._startTime === time && tween.data === "isPause") {
4764						tween._rawPrevTime = 0; //remember, _rawPrevTime is how zero-duration tweens/callbacks sense directionality and determine whether or not to fire. If _rawPrevTime is the same as _startTime on the next render, it won't fire.
4765					}
4766					tween = tween._next;
4767				}
4768			}
4769			return Animation.prototype.paused.apply(this, arguments);
4770		};
4771
4772		p.usesFrames = function() {
4773			var tl = this._timeline;
4774			while (tl._timeline) {
4775				tl = tl._timeline;
4776			}
4777			return (tl === Animation._rootFramesTimeline);
4778		};
4779
4780		p.rawTime = function() {
4781			return this._paused ? this._totalTime : (this._timeline.rawTime() - this._startTime) * this._timeScale;
4782		};
4783
4784		return TimelineLite;
4785
4786	}, true);
4787
4788
4789}); if (_gsScope._gsDefine) { _gsScope._gsQueue.pop()(); }
4790
4791//export to AMD/RequireJS and CommonJS/Node (precursor to full modular build system coming at a later date)
4792(function(name) {
4793	"use strict";
4794	var getGlobal = function() {
4795		return (_gsScope.GreenSockGlobals || _gsScope)[name];
4796	};
4797	if (typeof(define) === "function" && define.amd) { //AMD
4798		define(["TweenLite"], getGlobal);
4799	} else if (typeof(module) !== "undefined" && module.exports) { //node
4800		require("./TweenLite.js"); //dependency
4801		module.exports = getGlobal();
4802	}
4803}("TimelineLite"));
4804
4805/*!
4806 * VERSION: beta 1.15.2
4807 * DATE: 2015-01-27
4808 * UPDATES AND DOCS AT: http://greensock.com
4809 *
4810 * @license Copyright (c) 2008-2015, GreenSock. All rights reserved.
4811 * This work is subject to the terms at http://greensock.com/standard-license or for
4812 * Club GreenSock members, the software agreement that was issued with your membership.
4813 * 
4814 * @author: Jack Doyle, [email protected]
4815 **/
4816var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(global) !== "undefined") ? global : this || window; //helps ensure compatibility with AMD/RequireJS and CommonJS/Node
4817(_gsScope._gsQueue || (_gsScope._gsQueue = [])).push( function() {
4818
4819	"use strict";
4820
4821	_gsScope._gsDefine("easing.Back", ["easing.Ease"], function(Ease) {
4822		
4823		var w = (_gsScope.GreenSockGlobals || _gsScope),
4824			gs = w.com.greensock,
4825			_2PI = Math.PI * 2,
4826			_HALF_PI = Math.PI / 2,
4827			_class = gs._class,
4828			_create = function(n, f) {
4829				var C = _class("easing." + n, function(){}, true),
4830					p = C.prototype = new Ease();
4831				p.constructor = C;
4832				p.getRatio = f;
4833				return C;
4834			},
4835			_easeReg = Ease.register || function(){}, //put an empty function in place just as a safety measure in case someone loads an OLD version of TweenLite.js where Ease.register doesn't exist.
4836			_wrap = function(name, EaseOut, EaseIn, EaseInOut, aliases) {
4837				var C = _class("easing."+name, {
4838					easeOut:new EaseOut(),
4839					easeIn:new EaseIn(),
4840					easeInOut:new EaseInOut()
4841				}, true);
4842				_easeReg(C, name);
4843				return C;
4844			},
4845			EasePoint = function(time, value, next) {
4846				this.t = time;
4847				this.v = value;
4848				if (next) {
4849					this.next = next;
4850					next.prev = this;
4851					this.c = next.v - value;
4852					this.gap = next.t - time;
4853				}
4854			},
4855
4856			//Back
4857			_createBack = function(n, f) {
4858				var C = _class("easing." + n, function(overshoot) {
4859						this._p1 = (overshoot || overshoot === 0) ? overshoot : 1.70158;
4860						this._p2 = this._p1 * 1.525;
4861					}, true), 
4862					p = C.prototype = new Ease();
4863				p.constructor = C;
4864				p.getRatio = f;
4865				p.config = function(overshoot) {
4866					return new C(overshoot);
4867				};
4868				return C;
4869			},
4870
4871			Back = _wrap("Back",
4872				_createBack("BackOut", function(p) {
4873					return ((p = p - 1) * p * ((this._p1 + 1) * p + this._p1) + 1);
4874				}),
4875				_createBack("BackIn", function(p) {
4876					return p * p * ((this._p1 + 1) * p - this._p1);
4877				}),
4878				_createBack("BackInOut", function(p) {
4879					return ((p *= 2) < 1) ? 0.5 * p * p * ((this._p2 + 1) * p - this._p2) : 0.5 * ((p -= 2) * p * ((this._p2 + 1) * p + this._p2) + 2);
4880				})
4881			),
4882
4883
4884			//SlowMo
4885			SlowMo = _class("easing.SlowMo", function(linearRatio, power, yoyoMode) {
4886				power = (power || power === 0) ? power : 0.7;
4887				if (linearRatio == null) {
4888					linearRatio = 0.7;
4889				} else if (linearRatio > 1) {
4890					linearRatio = 1;
4891				}
4892				this._p = (linearRatio !== 1) ? power : 0;
4893				this._p1 = (1 - linearRatio) / 2;
4894				this._p2 = linearRatio;
4895				this._p3 = this._p1 + this._p2;
4896				this._calcEnd = (yoyoMode === true);
4897			}, true),
4898			p = SlowMo.prototype = new Ease(),
4899			SteppedEase, RoughEase, _createElastic;
4900			
4901		p.constructor = SlowMo;
4902		p.getRatio = function(p) {
4903			var r = p + (0.5 - p) * this._p;
4904			if (p < this._p1) {
4905				return this._calcEnd ? 1 - ((p = 1 - (p / this._p1)) * p) : r - ((p = 1 - (p / this._p1)) * p * p * p * r);
4906			} else if (p > this._p3) {
4907				return this._calcEnd ? 1 - (p = (p - this._p3) / this._p1) * p : r + ((p - r) * (p = (p - this._p3) / this._p1) * p * p * p);
4908			}
4909			return this._calcEnd ? 1 : r;
4910		};
4911		SlowMo.ease = new SlowMo(0.7, 0.7);
4912		
4913		p.config = SlowMo.config = function(linearRatio, power, yoyoMode) {
4914			return new SlowMo(linearRatio, power, yoyoMode);
4915		};
4916
4917
4918		//SteppedEase
4919		SteppedEase = _class("easing.SteppedEase", function(steps) {
4920				steps = steps || 1;
4921				this._p1 = 1 / steps;
4922				this._p2 = steps + 1;
4923			}, true);
4924		p = SteppedEase.prototype = new Ease();	
4925		p.constructor = SteppedEase;
4926		p.getRatio = function(p) {
4927			if (p < 0) {
4928				p = 0;
4929			} else if (p >= 1) {
4930				p = 0.999999999;
4931			}
4932			return ((this._p2 * p) >> 0) * this._p1;
4933		};
4934		p.config = SteppedEase.config = function(steps) {
4935			return new SteppedEase(steps);
4936		};
4937
4938
4939		//RoughEase
4940		RoughEase = _class("easing.RoughEase", function(vars) {
4941			vars = vars || {};
4942			var taper = vars.taper || "none",
4943				a = [],
4944				cnt = 0,
4945				points = (vars.points || 20) | 0,
4946				i = points,
4947				randomize = (vars.randomize !== false),
4948				clamp = (vars.clamp === true),
4949				template = (vars.template instanceof Ease) ? vars.template : null,
4950				strength = (typeof(vars.strength) === "number") ? vars.strength * 0.4 : 0.4,
4951				x, y, bump, invX, obj, pnt;
4952			while (--i > -1) {
4953				x = randomize ? Math.random() : (1 / points) * i;
4954				y = template ? template.getRatio(x) : x;
4955				if (taper === "none") {
4956					bump = strength;
4957				} else if (taper === "out") {
4958					invX = 1 - x;
4959					bump = invX * invX * strength;
4960				} else if (taper === "in") {
4961					bump = x * x * strength;
4962				} else if (x < 0.5) {  //"both" (start)
4963					invX = x * 2;
4964					bump = invX * invX * 0.5 * strength;
4965				} else {				//"both" (end)
4966					invX = (1 - x) * 2;
4967					bump = invX * invX * 0.5 * strength;
4968				}
4969				if (randomize) {
4970					y += (Math.random() * bump) - (bump * 0.5);
4971				} else if (i % 2) {
4972					y += bump * 0.5;
4973				} else {
4974					y -= bump * 0.5;
4975				}
4976				if (clamp) {
4977					if (y > 1) {
4978						y = 1;
4979					} else if (y < 0) {
4980						y = 0;
4981					}
4982				}
4983				a[cnt++] = {x:x, y:y};
4984			}
4985			a.sort(function(a, b) {
4986				return a.x - b.x;
4987			});
4988
4989			pnt = new EasePoint(1, 1, null);
4990			i = points;
4991			while (--i > -1) {
4992				obj = a[i];
4993				pnt = new EasePoint(obj.x, obj.y, pnt);
4994			}
4995
4996			this._prev = new EasePoint(0, 0, (pnt.t !== 0) ? pnt : pnt.next);
4997		}, true);
4998		p = RoughEase.prototype = new Ease();
4999		p.constructor = RoughEase;
5000		p.getRatio = function(p) {
5001			var pnt = this._prev;
5002			if (p > pnt.t) {
5003				while (pnt.next && p >= pnt.t) {
5004					pnt = pnt.next;
5005				}
5006				pnt = pnt.prev;
5007			} else {
5008				while (pnt.prev && p <= pnt.t) {
5009					pnt = pnt.prev;
5010				}
5011			}
5012			this._prev = pnt;
5013			return (pnt.v + ((p - pnt.t) / pnt.gap) * pnt.c);
5014		};
5015		p.config = function(vars) {
5016			return new RoughEase(vars);
5017		};
5018		RoughEase.ease = new RoughEase();
5019
5020
5021		//Bounce
5022		_wrap("Bounce",
5023			_create("BounceOut", function(p) {
5024				if (p < 1 / 2.75) {
5025					return 7.5625 * p * p;
5026				} else if (p < 2 / 2.75) {
5027					return 7.5625 * (p -= 1.5 / 2.75) * p + 0.75;
5028				} else if (p < 2.5 / 2.75) {
5029					return 7.5625 * (p -= 2.25 / 2.75) * p + 0.9375;
5030				}
5031				return 7.5625 * (p -= 2.625 / 2.75) * p + 0.984375;
5032			}),
5033			_create("BounceIn", function(p) {
5034				if ((p = 1 - p) < 1 / 2.75) {
5035					return 1 - (7.5625 * p * p);
5036				} else if (p < 2 / 2.75) {
5037					return 1 - (7.5625 * (p -= 1.5 / 2.75) * p + 0.75);
5038				} else if (p < 2.5 / 2.75) {
5039					return 1 - (7.5625 * (p -= 2.25 / 2.75) * p + 0.9375);
5040				}
5041				return 1 - (7.5625 * (p -= 2.625 / 2.75) * p + 0.984375);
5042			}),
5043			_create("BounceInOut", function(p) {
5044				var invert = (p < 0.5);
5045				if (invert) {
5046					p = 1 - (p * 2);
5047				} else {
5048					p = (p * 2) - 1;
5049				}
5050				if (p < 1 / 2.75) {
5051					p = 7.5625 * p * p;
5052				} else if (p < 2 / 2.75) {
5053					p = 7.5625 * (p -= 1.5 / 2.75) * p + 0.75;
5054				} else if (p < 2.5 / 2.75) {
5055					p = 7.5625 * (p -= 2.25 / 2.75) * p + 0.9375;
5056				} else {
5057					p = 7.5625 * (p -= 2.625 / 2.75) * p + 0.984375;
5058				}
5059				return invert ? (1 - p) * 0.5 : p * 0.5 + 0.5;
5060			})
5061		);
5062
5063
5064		//CIRC
5065		_wrap("Circ",
5066			_create("CircOut", function(p) {
5067				return Math.sqrt(1 - (p = p - 1) * p);
5068			}),
5069			_create("CircIn", function(p) {
5070				return -(Math.sqrt(1 - (p * p)) - 1);
5071			}),
5072			_create("CircInOut", function(p) {
5073				return ((p*=2) < 1) ? -0.5 * (Math.sqrt(1 - p * p) - 1) : 0.5 * (Math.sqrt(1 - (p -= 2) * p) + 1);
5074			})
5075		);
5076
5077
5078		//Elastic
5079		_createElastic = function(n, f, def) {
5080			var C = _class("easing." + n, function(amplitude, period) {
5081					this._p1 = (amplitude >= 1) ? amplitude : 1; //note: if amplitude is < 1, we simply adjust the period for a more natural feel. Otherwise the math doesn't work right and the curve starts at 1.
5082					this._p2 = (period || def) / (amplitude < 1 ? amplitude : 1);
5083					this._p3 = this._p2 / _2PI * (Math.asin(1 / this._p1) || 0);
5084					this._p2 = _2PI / this._p2; //precalculate to optimize
5085				}, true),
5086				p = C.prototype = new Ease();
5087			p.constructor = C;
5088			p.getRatio = f;
5089			p.config = function(amplitude, period) {
5090				return new C(amplitude, period);
5091			};
5092			return C;
5093		};
5094		_wrap("Elastic",
5095			_createElastic("ElasticOut", function(p) {
5096				return this._p1 * Math.pow(2, -10 * p) * Math.sin( (p - this._p3) * this._p2 ) + 1;
5097			}, 0.3),
5098			_createElastic("ElasticIn", function(p) {
5099				return -(this._p1 * Math.pow(2, 10 * (p -= 1)) * Math.sin( (p - this._p3) * this._p2 ));
5100			}, 0.3),
5101			_createElastic("ElasticInOut", function(p) {
5102				return ((p *= 2) < 1) ? -0.5 * (this._p1 * Math.pow(2, 10 * (p -= 1)) * Math.sin( (p - this._p3) * this._p2)) : this._p1 * Math.pow(2, -10 *(p -= 1)) * Math.sin( (p - this._p3) * this._p2 ) * 0.5 + 1;
5103			}, 0.45)
5104		);
5105
5106
5107		//Expo
5108		_wrap("Expo",
5109			_create("ExpoOut", function(p) {
5110				return 1 - Math.pow(2, -10 * p);
5111			}),
5112			_create("ExpoIn", function(p) {
5113				return Math.pow(2, 10 * (p - 1)) - 0.001;
5114			}),
5115			_create("ExpoInOut", function(p) {
5116				return ((p *= 2) < 1) ? 0.5 * Math.pow(2, 10 * (p - 1)) : 0.5 * (2 - Math.pow(2, -10 * (p - 1)));
5117			})
5118		);
5119
5120
5121		//Sine
5122		_wrap("Sine",
5123			_create("SineOut", function(p) {
5124				return Math.sin(p * _HALF_PI);
5125			}),
5126			_create("SineIn", function(p) {
5127				return -Math.cos(p * _HALF_PI) + 1;
5128			}),
5129			_create("SineInOut", function(p) {
5130				return -0.5 * (Math.cos(Math.PI * p) - 1);
5131			})
5132		);
5133
5134		_class("easing.EaseLookup", {
5135				find:function(s) {
5136					return Ease.map[s];
5137				}
5138			}, true);
5139
5140		//register the non-standard eases
5141		_easeReg(w.SlowMo, "SlowMo", "ease,");
5142		_easeReg(RoughEase, "RoughEase", "ease,");
5143		_easeReg(SteppedEase, "SteppedEase", "ease,");
5144		
5145		return Back;
5146		
5147	}, true);
5148
5149}); if (_gsScope._gsDefine) { _gsScope._gsQueue.pop()(); }
5150
5151
5152/*!
5153 * VERSION: 1.18.0
5154 * DATE: 2015-09-05
5155 * UPDATES AND DOCS AT: http://greensock.com
5156 *
5157 * @license Copyright (c) 2008-2015, GreenSock. All rights reserved.
5158 * This work is subject to the terms at http://greensock.com/standard-license or for
5159 * Club GreenSock members, the software agreement that was issued with your membership.
5160 * 
5161 * @author: Jack Doyle, [email protected]
5162 */
5163var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(global) !== "undefined") ? global : this || window; //helps ensure compatibility with AMD/RequireJS and CommonJS/Node
5164(_gsScope._gsQueue || (_gsScope._gsQueue = [])).push( function() {
5165
5166	"use strict";
5167
5168	_gsScope._gsDefine("plugins.CSSPlugin", ["plugins.TweenPlugin","TweenLite"], function(TweenPlugin, TweenLite) {
5169
5170		/** @constructor **/
5171		var CSSPlugin = function() {
5172				TweenPlugin.call(this, "css");
5173				this._overwriteProps.length = 0;
5174				this.setRatio = CSSPlugin.prototype.setRatio; //speed optimization (avoid prototype lookup on this "hot" method)
5175			},
5176			_globals = _gsScope._gsDefine.globals,
5177			_hasPriority, //turns true whenever a CSSPropTween instance is created that has a priority other than 0. This helps us discern whether or not we should spend the time organizing the linked list or not after a CSSPlugin's _onInitTween() method is called.
5178			_suffixMap, //we set this in _onInitTween() each time as a way to have a persistent variable we can use in other methods like _parse() without having to pass it around as a parameter and we keep _parse() decoupled from a particular CSSPlugin instance
5179			_cs, //computed style (we store this in a shared variable to conserve memory and make minification tighter
5180			_overwriteProps, //alias to the currently instantiating CSSPlugin's _overwriteProps array. We use this closure in order to avoid having to pass a reference around from method to method and aid in minification.
5181			_specialProps = {},
5182			p = CSSPlugin.prototype = new TweenPlugin("css");
5183
5184		p.constructor = CSSPlugin;
5185		CSSPlugin.version = "1.18.0";
5186		CSSPlugin.API = 2;
5187		CSSPlugin.defaultTransformPerspective = 0;
5188		CSSPlugin.defaultSkewType = "compensated";
5189		CSSPlugin.defaultSmoothOrigin = true;
5190		p = "px"; //we'll reuse the "p" variable to keep file size down
5191		CSSPlugin.suffixMap = {top:p, right:p, bottom:p, left:p, width:p, height:p, fontSize:p, padding:p, margin:p, perspective:p, lineHeight:""};
5192
5193
5194		var _numExp = /(?:\d|\-\d|\.\d|\-\.\d)+/g,
5195			_relNumExp = /(?:\d|\-\d|\.\d|\-\.\d|\+=\d|\-=\d|\+=.\d|\-=\.\d)+/g,
5196			_valuesExp = /(?:\+=|\-=|\-|\b)[\d\-\.]+[a-zA-Z0-9]*(?:%|\b)/gi, //finds all the values that begin with numbers or += or -= and then a number. Includes suffixes. We use this to split complex values apart like "1px 5px 20px rgb(255,102,51)"
5197			_NaNExp = /(?![+-]?\d*\.?\d+|[+-]|e[+-]\d+)[^0-9]/g, //also allows scientific notation and doesn't kill the leading -/+ in -= and +=
5198			_suffixExp = /(?:\d|\-|\+|=|#|\.)*/g,
5199			_opacityExp = /opacity *= *([^)]*)/i,
5200			_opacityValExp = /opacity:([^;]*)/i,
5201			_alphaFilterExp = /alpha\(opacity *=.+?\)/i,
5202			_rgbhslExp = /^(rgb|hsl)/,
5203			_capsExp = /([A-Z])/g,
5204			_camelExp = /-([a-z])/gi,
5205			_urlExp = /(^(?:url\(\"|url\())|(?:(\"\))$|\)$)/gi, //for pulling out urls from url(...) or url("...") strings (some browsers wrap urls in quotes, some don't when reporting things like backgroundImage)
5206			_camelFunc = function(s, g) { return g.toUpperCase(); },
5207			_horizExp = /(?:Left|Right|Width)/i,
5208			_ieGetMatrixExp = /(M11|M12|M21|M22)=[\d\-\.e]+/gi,
5209			_ieSetMatrixExp = /progid\:DXImageTransform\.Microsoft\.Matrix\(.+?\)/i,
5210			_commasOutsideParenExp = /,(?=[^\)]*(?:\(|$))/gi, //finds any commas that are not within parenthesis
5211			_DEG2RAD = Math.PI / 180,
5212			_RAD2DEG = 180 / Math.PI,
5213			_forcePT = {},
5214			_doc = document,
5215			_createElement = function(type) {
5216				return _doc.createElementNS ? _doc.createElementNS("http://www.w3.org/1999/xhtml", type) : _doc.createElement(type);
5217			},
5218			_tempDiv = _createElement("div"),
5219			_tempImg = _createElement("img"),
5220			_internals = CSSPlugin._internals = {_specialProps:_specialProps}, //provides a hook to a few internal methods that we need to access from inside other plugins
5221			_agent = navigator.userAgent,
5222			_autoRound,
5223			_reqSafariFix, //we won't apply the Safari transform fix until we actually come across a tween that affects a transform property (to maintain best performance).
5224
5225			_isSafari,
5226			_isFirefox, //Firefox has a bug that causes 3D transformed elements to randomly disappear unless a repaint is forced after each update on each element.
5227			_isSafariLT6, //Safari (and Android 4 which uses a flavor of Safari) has a bug that prevents changes to "top" and "left" properties from rendering properly if changed on the same frame as a transform UNLESS we set the element's WebkitBackfaceVisibility to hidden (weird, I know). Doing this for Android 3 and earlier seems to actually cause other problems, though (fun!)
5228			_ieVers,
5229			_supportsOpacity = (function() { //we set _isSafari, _ieVers, _isFirefox, and _supportsOpacity all in one function here to reduce file size slightly, especially in the minified version.
5230				var i = _agent.indexOf("Android"),
5231					a = _createElement("a");
5232				_isSafari = (_agent.indexOf("Safari") !== -1 && _agent.indexOf("Chrome") === -1 && (i === -1 || Number(_agent.substr(i+8, 1)) > 3));
5233				_isSafariLT6 = (_isSafari && (Number(_agent.substr(_agent.indexOf("Version/")+8, 1)) < 6));
5234				_isFirefox = (_agent.indexOf("Firefox") !== -1);
5235				if ((/MSIE ([0-9]{1,}[\.0-9]{0,})/).exec(_agent) || (/Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/).exec(_agent)) {
5236					_ieVers = parseFloat( RegExp.$1 );
5237				}
5238				if (!a) {
5239					return false;
5240				}
5241				a.style.cssText = "top:1px;opacity:.55;";
5242				return /^0.55/.test(a.style.opacity);
5243			}()),
5244			_getIEOpacity = function(v) {
5245				return (_opacityExp.test( ((typeof(v) === "string") ? v : (v.currentStyle ? v.currentStyle.filter : v.style.filter) || "") ) ? ( parseFloat( RegExp.$1 ) / 100 ) : 1);
5246			},
5247			_log = function(s) {//for logging messages, but in a way that won't throw errors in old versions of IE.
5248				if (window.console) {
5249					console.log(s);
5250				}
5251			},
5252
5253			_prefixCSS = "", //the non-camelCase vendor prefix like "-o-", "-moz-", "-ms-", or "-webkit-"
5254			_prefix = "", //camelCase vendor prefix like "O", "ms", "Webkit", or "Moz".
5255
5256			// @private feed in a camelCase property name like "transform" and it will check to see if it is valid as-is or if it needs a vendor prefix. It returns the corrected camelCase property name (i.e. "WebkitTransform" or "MozTransform" or "transform" or null if no such property is found, like if the browser is IE8 or before, "transform" won't be found at all)
5257			_checkPropPrefix = function(p, e) {
5258				e = e || _tempDiv;
5259				var s = e.style,
5260					a, i;
5261				if (s[p] !== undefined) {
5262					return p;
5263				}
5264				p = p.charAt(0).toUpperCase() + p.substr(1);
5265				a = ["O","Moz","ms","Ms","Webkit"];
5266				i = 5;
5267				while (--i > -1 && s[a[i]+p] === undefined) { }
5268				if (i >= 0) {
5269					_prefix = (i === 3) ? "ms" : a[i];
5270					_prefixCSS = "-" + _prefix.toLowerCase() + "-";
5271					return _prefix + p;
5272				}
5273				return null;
5274			},
5275
5276			_getComputedStyle = _doc.defaultView ? _doc.defaultView.getComputedStyle : function() {},
5277
5278			/**
5279			 * @private Returns the css style for a particular property of an element. For example, to get whatever the current "left" css value for an element with an ID of "myElement", you could do:
5280			 * var currentLeft = CSSPlugin.getStyle( document.getElementById("myElement"), "left");
5281			 *
5282			 * @param {!Object} t Target element whose style property you want to query
5283			 * @param {!string} p Property name (like "left" or "top" or "marginTop", etc.)
5284			 * @param {Object=} cs Computed style object. This just provides a way to speed processing if you're going to get several properties on the same element in quick succession - you can reuse the result of the getComputedStyle() call.
5285			 * @param {boolean=} calc If true, the value will not be read directly from the element's "style" property (if it exists there), but instead the getComputedStyle() result will be used. This can be useful when you want to ensure that the browser itself is interpreting the value.
5286			 * @param {string=} dflt Default value that should be returned in the place of null, "none", "auto" or "auto auto".
5287			 * @return {?string} The current property value
5288			 */
5289			_getStyle = CSSPlugin.getStyle = function(t, p, cs, calc, dflt) {
5290				var rv;
5291				if (!_supportsOpacity) if (p === "opacity") { //several versions of IE don't use the standard "opacity" property - they use things like filter:alpha(opacity=50), so we parse that here.
5292					return _getIEOpacity(t);
5293				}
5294				if (!calc && t.style[p]) {
5295					rv = t.style[p];
5296				} else if ((cs = cs || _getComputedStyle(t))) {
5297					rv = cs[p] || cs.getPropertyValue(p) || cs.getPropertyValue(p.replace(_capsExp, "-$1").toLowerCase());
5298				} else if (t.currentStyle) {
5299					rv = t.currentStyle[p];
5300				}
5301				return (dflt != null && (!rv || rv === "none" || rv === "auto" || rv === "auto auto")) ? dflt : rv;
5302			},
5303
5304			/**
5305			 * @private Pass the target element, the property name, the numeric value, and the suffix (like "%", "em", "px", etc.) and it will spit back the equivalent pixel number.
5306			 * @param {!Object} t Target element
5307			 * @param {!string} p Property name (like "left", "top", "marginLeft", etc.)
5308			 * @param {!number} v Value
5309			 * @param {string=} sfx Suffix (like "px" or "%" or "em")
5310			 * @param {boolean=} recurse If true, the call is a recursive one. In some browsers (like IE7/8), occasionally the value isn't accurately reported initially, but if we run the function again it will take effect.
5311			 * @return {number} value in pixels
5312			 */
5313			_convertToPixels = _internals.convertToPixels = function(t, p, v, sfx, recurse) {
5314				if (sfx === "px" || !sfx) { return v; }
5315				if (sfx === "auto" || !v) { return 0; }
5316				var horiz = _horizExp.test(p),
5317					node = t,
5318					style = _tempDiv.style,
5319					neg = (v < 0),
5320					pix, cache, time;
5321				if (neg) {
5322					v = -v;
5323				}
5324				if (sfx === "%" && p.indexOf("border") !== -1) {
5325					pix = (v / 100) * (horiz ? t.clientWidth : t.clientHeight);
5326				} else {
5327					style.cssText = "border:0 solid red;position:" + _getStyle(t, "position") + ";line-height:0;";
5328					if (sfx === "%" || !node.appendChild || sfx.charAt(0) === "v" || sfx === "rem") {
5329						node = t.parentNode || _doc.body;
5330						cache = node._gsCache;
5331						time = TweenLite.ticker.frame;
5332						if (cache && horiz && cache.time === time) { //performance optimization: we record the width of elements along with the ticker frame so that we can quickly get it again on the same tick (seems relatively safe to assume it wouldn't change on the same tick)
5333							return cache.width * v / 100;
5334						}
5335						style[(horiz ? "width" : "height")] = v + sfx;
5336					} else {
5337						style[(horiz ? "borderLeftWidth" : "borderTopWidth")] = v + sfx;
5338					}
5339					node.appendChild(_tempDiv);
5340					pix = parseFloat(_tempDiv[(horiz ? "offsetWidth" : "offsetHeight")]);
5341					node.removeChild(_tempDiv);
5342					if (horiz && sfx === "%" && CSSPlugin.cacheWidths !== false) {
5343						cache = node._gsCache = node._gsCache || {};
5344						cache.time = time;
5345						cache.width = pix / v * 100;
5346					}
5347					if (pix === 0 && !recurse) {
5348						pix = _convertToPixels(t, p, v, sfx, true);
5349					}
5350				}
5351				return neg ? -pix : pix;
5352			},
5353			_calculateOffset = _internals.calculateOffset = function(t, p, cs) { //for figuring out "top" or "left" in px when it's "auto". We need to factor in margin with the offsetLeft/offsetTop
5354				if (_getStyle(t, "position", cs) !== "absolute") { return 0; }
5355				var dim = ((p === "left") ? "Left" : "Top"),
5356					v = _getStyle(t, "margin" + dim, cs);
5357				return t["offset" + dim] - (_convertToPixels(t, p, parseFloat(v), v.replace(_suffixExp, "")) || 0);
5358			},
5359
5360			// @private returns at object containing ALL of the style properties in camelCase and their associated values.
5361			_getAllStyles = function(t, cs) {
5362				var s = {},
5363					i, tr, p;
5364				if ((cs = cs || _getComputedStyle(t, null))) {
5365					if ((i = cs.length)) {
5366						while (--i > -1) {
5367							p = cs[i];
5368							if (p.indexOf("-transform") === -1 || _transformPropCSS === p) { //Some webkit browsers duplicate transform values, one non-prefixed and one prefixed ("transform" and "WebkitTransform"), so we must weed out the extra one here.
5369								s[p.replace(_camelExp, _camelFunc)] = cs.getPropertyValue(p);
5370							}
5371						}
5372					} else { //some browsers behave differently - cs.length is always 0, so we must do a for...in loop.
5373						for (i in cs) {
5374							if (i.indexOf("Transform") === -1 || _transformProp === i) { //Some webkit browsers duplicate transform values, one non-prefixed and one prefixed ("transform" and "WebkitTransform"), so we must weed out the extra one here.
5375								s[i] = cs[i];
5376							}
5377						}
5378					}
5379				} else if ((cs = t.currentStyle || t.style)) {
5380					for (i in cs) {
5381						if (typeof(i) === "string" && s[i] === undefined) {
5382							s[i.replace(_camelExp, _camelFunc)] = cs[i];
5383						}
5384					}
5385				}
5386				if (!_supportsOpacity) {
5387					s.opacity = _getIEOpacity(t);
5388				}
5389				tr = _getTransform(t, cs, false);
5390				s.rotation = tr.rotation;
5391				s.skewX = tr.skewX;
5392				s.scaleX = tr.scaleX;
5393				s.scaleY = tr.scaleY;
5394				s.x = tr.x;
5395				s.y = tr.y;
5396				if (_supports3D) {
5397					s.z = tr.z;
5398					s.rotationX = tr.rotationX;
5399					s.rotationY = tr.rotationY;
5400					s.scaleZ = tr.scaleZ;
5401				}
5402				if (s.filters) {
5403					delete s.filters;
5404				}
5405				return s;
5406			},
5407
5408			// @private analyzes two style objects (as returned by _getAllStyles()) and only looks for differences between them that contain tweenable values (like a number or color). It returns an object with a "difs" property which refers to an object c
5408ontaining only those isolated properties and values for tweening, and a "firstMPT" property which refers to the first MiniPropTween instance in a linked list that recorded all the starting values of the different properties so that we can revert to them at the end or beginning of the tween - we don't want the cascading to get messed up. The forceLookup parameter is an optional generic object with properties that should be forced into the results - this is necessary for className tweens that are overwriting others because imagine a scenario where a rollover/rollout adds/removes a class and the user swipes the mouse over the target SUPER fast, thus nothing actually changed yet and the subsequent comparison of the properties would indicate they match (especially when px rounding is taken into consideration), thus no tweening is necessary even though it SHOULD tween and remove those properties after the tween (otherwise the inline styles will contaminate things). See the className SpecialProp code for details.
5409			_cssDif = function(t, s1, s2, vars, forceLookup) {
5410				var difs = {},
5411					style = t.style,
5412					val, p, mpt;
5413				for (p in s2) {
5414					if (p !== "cssText") if (p !== "length") if (isNaN(p)) if (s1[p] !== (val = s2[p]) || (forceLookup && forceLookup[p])) if (p.indexOf("Origin") === -1) if (typeof(val) === "number" || typeof(val) === "string") {
5415						difs[p] = (val === "auto" && (p === "left" || p === "top")) ? _calculateOffset(t, p) : ((val === "" || val === "auto" || val === "none") && typeof(s1[p]) === "string" && s1[p].replace(_NaNExp, "") !== "") ? 0 : val; //if the ending value is defaulting ("" or "auto"), we check the starting value and if it can be parsed into a number (a string which could have a suffix too, like 700px), then we swap in 0 for "" or "auto" so that things actually tween.
5416						if (style[p] !== undefined) { //for className tweens, we must remember which properties already existed inline - the ones that didn't should be removed when the tween isn't in progress because they were only introduced to facilitate the transition between classes.
5417							mpt = new MiniPropTween(style, p, style[p], mpt);
5418						}
5419					}
5420				}
5421				if (vars) {
5422					for (p in vars) { //copy properties (except className)
5423						if (p !== "className") {
5424							difs[p] = vars[p];
5425						}
5426					}
5427				}
5428				return {difs:difs, firstMPT:mpt};
5429			},
5430			_dimensions = {width:["Left","Right"], height:["Top","Bottom"]},
5431			_margins = ["marginLeft","marginRight","marginTop","marginBottom"],
5432
5433			/**
5434			 * @private Gets the width or height of an element
5435			 * @param {!Object} t Target element
5436			 * @param {!string} p Property name ("width" or "height")
5437			 * @param {Object=} cs Computed style object (if one exists). Just a speed optimization.
5438			 * @return {number} Dimension (in pixels)
5439			 */
5440			_getDimension = function(t, p, cs) {
5441				var v = parseFloat((p === "width") ? t.offsetWidth : t.offsetHeight),
5442					a = _dimensions[p],
5443					i = a.length;
5444				cs = cs || _getComputedStyle(t, null);
5445				while (--i > -1) {
5446					v -= parseFloat( _getStyle(t, "padding" + a[i], cs, true) ) || 0;
5447					v -= parseFloat( _getStyle(t, "border" + a[i] + "Width", cs, true) ) || 0;
5448				}
5449				return v;
5450			},
5451
5452			// @private Parses position-related complex strings like "top left" or "50px 10px" or "70% 20%", etc. which are used for things like transformOrigin or backgroundPosition. Optionally decorates a supplied object (recObj) with the following properties: "ox" (offsetX), "oy" (offsetY), "oxp" (if true, "ox" is a percentage not a pixel value), and "oxy" (if true, "oy" is a percentage not a pixel value)
5453			_parsePosition = function(v, recObj) {
5454				if (v === "contain" || v === "auto" || v === "auto auto") {
5455					return v + " ";
5456				}
5457				if (v == null || v === "") { //note: Firefox uses "auto auto" as default whereas Chrome uses "auto".
5458					v = "0 0";
5459				}
5460				var a = v.split(" "),
5461					x = (v.indexOf("left") !== -1) ? "0%" : (v.indexOf("right") !== -1) ? "100%" : a[0],
5462					y = (v.indexOf("top") !== -1) ? "0%" : (v.indexOf("bottom") !== -1) ? "100%" : a[1];
5463				if (y == null) {
5464					y = (x === "center") ? "50%" : "0";
5465				} else if (y === "center") {
5466					y = "50%";
5467				}
5468				if (x === "center" || (isNaN(parseFloat(x)) && (x + "").indexOf("=") === -1)) { //remember, the user could flip-flop the values and say "bottom center" or "center bottom", etc. "center" is ambiguous because it c
5468ould be used to describe horizontal or vertical, hence the isNaN(). If there's an "=" sign in the value, it's relative.
5469					x = "50%";
5470				}
5471				v = x + " " + y + ((a.length > 2) ? " " + a[2] : "");
5472				if (recObj) {
5473					recObj.oxp = (x.indexOf("%") !== -1);
5474					recObj.oyp = (y.indexOf("%") !== -1);
5475					recObj.oxr = (x.charAt(1) === "=");
5476					recObj.oyr = (y.charAt(1) === "=");
5477					recObj.ox = parseFloat(x.replace(_NaNExp, ""));
5478					recObj.oy = parseFloat(y.replace(_NaNExp, ""));
5479					recObj.v = v;
5480				}
5481				return recObj || v;
5482			},
5483
5484			/**
5485			 * @private Takes an ending value (typically a string, but can be a number) and a starting value and returns the change between the two, looking for relative value indicators like += and -= and it also ignores suffixes (but make sure the ending value starts with a number or +=/-= and that the starting value is a NUMBER!)
5486			 * @param {(number|string)} e End value which is typically a string, but could be a number
5487			 * @param {(number|string)} b Beginning value which is typically a string but could be a number
5488			 * @return {number} Amount of change between the beginning and ending values (relative values that have a "+=" or "-=" are recognized)
5489			 */
5490			_parseChange = function(e, b) {
5491				return (typeof(e) === "string" && e.charAt(1) === "=") ? parseInt(e.charAt(0) + "1", 10) * parseFloat(e.substr(2)) : parseFloat(e) - parseFloat(b);
5492			},
5493
5494			/**
5495			 * @private Takes a value and a default number, checks if the value is relative, null, or numeric and spits back a normalized number accordingly. Primarily used in the _parseTransform() function.
5496			 * @param {Object} v Value to be parsed
5497			 * @param {!number} d Default value (which is also used for relative calculations if "+=" or "-=" is found in the first parameter)
5498			 * @return {number} Parsed value
5499			 */
5500			_parseVal = function(v, d) {
5501				return (v == null) ? d : (typeof(v) === "string" && v.charAt(1) === "=") ? parseInt(v.charAt(0) + "1", 10) * parseFloat(v.substr(2)) + d : parseFloat(v);
5502			},
5503
5504			/**
5505			 * @private Translates strings like "40deg" or "40" or 40rad" or "+=40deg" or "270_short" or "-90_cw" or "+=45_ccw" to a numeric radian angle. Of course a starting/default value must be fed in too so that relative values can be calculated properly.
5506			 * @param {Object} v Value to be parsed
5507			 * @param {!number} d Default value (which is also used for relative calculations if "+=" or "-=" is found in the first parameter)
5508			 * @param {string=} p property name for directionalEnd (optional - only used when the parsed value is directional ("_short", "_cw", or "_ccw" suffix). We need a way to store the uncompensated value so that at the end of the tween, we set it to exactly what was requested with no directional compensation). Property name would be "rotation", "rotationX", or "rotationY"
5509			 * @param {Object=} directionalEnd An object that will store the raw end values for directional angles ("_short", "_cw", or "_ccw" suffix). We need a way to store the uncompensated value so that at the end of the tween, we set it to exactly what was requested with no directional compensation.
5510			 * @return {number} parsed angle in radians
5511			 */
5512			_parseAngle = function(v, d, p, directionalEnd) {
5513				var min = 0.000001,
5514					cap, split, dif, result, isRelative;
5515				if (v == null) {
5516					result = d;
5517				} else if (typeof(v) === "number") {
5518					result = v;
5519				} else {
5520					cap = 360;
5521					split = v.split("_");
5522					isRelative = (v.charAt(1) === "=");
5523					dif = (isRelative ? parseInt(v.charAt(0) + "1", 10) * parseFloat(split[0].substr(2)) : parseFloat(split[0])) * ((v.indexOf("rad") === -1) ? 1 : _RAD2DEG) - (isRelative ? 0 : d);
5524					if (split.length) {
5525						if (directionalEnd) {
5526							directionalEnd[p] = d + dif;
5527						}
5528						if (v.indexOf("short") !== -1) {
5529							dif = dif % cap;
5530							if (dif !== dif % (cap / 2)) {
5531								dif = (dif < 0) ? dif + cap : dif - cap;
5532							}
5533						}
5534						if (v.indexOf("_cw") !== -1 && dif < 0) {
5535							dif = ((dif + cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
5536						} else if (v.indexOf("ccw") !== -1 && dif > 0) {
5537							dif = ((dif - cap * 9999999999) % cap) - ((dif / cap) | 0) * cap;
5538						}
5539					}
5540					result = d + dif;
5541				}
5542				if (result < min && result > -min) {
5543					result = 0;
5544				}
5545				return result;
5546			},
5547
5548			_colorLookup = {aqua:[0,255,255],
5549				lime:[0,255,0],
5550				silver:[192,192,192],
5551				black:[0,0,0],
5552				maroon:[128,0,0],
5553				teal:[0,128,128],
5554				blue:[0,0,255],
5555				navy:[0,0,128],
5556				white:[255,255,255],
5557				fuchsia:[255,0,255],
5558				olive:[128,128,0],
5559				yellow:[255,255,0],
5560				orange:[255,165,0],
5561				gray:[128,128,128],
5562				purple:[128,0,128],
5563				green:[0,128,0],
5564				red:[255,0,0],
5565				pink:[255,192,203],
5566				cyan:[0,255,255],
5567				transparent:[255,255,255,0]},
5568
5569			_hue = function(h, m1, m2) {
5570				h = (h < 0) ? h + 1 : (h > 1) ? h - 1 : h;
5571				return ((((h * 6 < 1) ? m1 + (m2 - m1) * h * 6 : (h < 0.5) ? m2 : (h * 3 < 2) ? m1 + (m2 - m1) * (2 / 3 - h) * 6 : m1) * 255) + 0.5) | 0;
5572			},
5573
5574			/**
5575			 * @private Parses a color (like #9F0, #FF9900, rgb(255,51,153) or hsl(108, 50%, 10%)) into an array with 3 elements for red, green, and blue or if toHSL parameter is true, it will populate the array with hue, saturation, and lightness values. If a relative value is found in an hsl() or hsla() string, it will preserve those relative prefixes and all the values in the array will be strings instead of numbers (in all other cases it will be populated with numbers).
5576			 * @param {(string|number)} v The value the should be parsed which could be a string like #9F0 or rgb(255,102,51) or rgba(255,0,0,0.5) or it could be a number like 0xFF00CC or even a named color like red, blue, purple, etc.
5577			 * @param {(boolean)} toHSL If true, an hsl() or hsla() value will be returned instead of rgb() or rgba()
5578			 * @return {Array.<number>} An array containing red, green, and blue (and optionally alpha) in that order, or if the toHSL parameter was true, the array will contain hue, saturation and lightness (and optionally alpha) in that order. Always numbers unless there's a relative prefix found in an hsl() or hsla() string and toHSL is true.
5579			 */
5580			_parseColor = CSSPlugin.parseColor = function(v, toHSL) {
5581				var a, r, g, b, h, s, l, max, min, d, wasHSL;
5582				if (!v) {
5583					a = _colorLookup.black;
5584				} else if (typeof(v) === "number") {
5585					a = [v >> 16, (v >> 8) & 255, v & 255];
5586				} else {
5587					if (v.charAt(v.length - 1) === ",") { //sometimes a trailing comma is included and we should chop it off (typically from a comma-delimited list of values like a textShadow:"2px 2px 2px blue, 5px 5px 5px rgb(255,0,0)" - in this example "blue," has a trailing comma. We could strip it out inside parseComplex() but we'd need to do it to the beginning and ending values plus it wouldn't provide protection from other potential scenarios like if the user passes in a similar value.
5588						v = v.substr(0, v.length - 1);
5589					}
5590					if (_colorLookup[v]) {
5591						a = _colorLookup[v];
5592					} else if (v.charAt(0) === "#") {
5593						if (v.length === 4) { //for shorthand like #9F0
5594							r = v.charAt(1);
5595							g = v.charAt(2);
5596							b = v.charAt(3);
5597							v = "#" + r + r + g + g + b + b;
5598						}
5599						v = parseInt(v.substr(1), 16);
5600						a = [v >> 16, (v >> 8) & 255, v & 255];
5601					} else if (v.substr(0, 3) === "hsl") {
5602						a = wasHSL = v.match(_numExp);
5603						if (!toHSL) {
5604							h = (Number(a[0]) % 360) / 360;
5605							s = Number(a[1]) / 100;
5606							l = Number(a[2]) / 100;
5607							g = (l <= 0.5) ? l * (s + 1) : l + s - l * s;
5608							r = l * 2 - g;
5609							if (a.length > 3) {
5610								a[3] = Number(v[3]);
5611							}
5612							a[0] = _hue(h + 1 / 3, r, g);
5613							a[1] = _hue(h, r, g);
5614							a[2] = _hue(h - 1 / 3, r, g);
5615						} else if (v.indexOf("=") !== -1) { //if relative values are found, just return the raw strings with the relative prefixes in place.
5616							return v.match(_relNumExp);
5617						}
5618					} else {
5619						a = v.match(_numExp) || _colorLookup.transparent;
5620					}
5621					a[0] = Number(a[0]);
5622					a[1] = Number(a[1]);
5623					a[2] = Number(a[2]);
5624					if (a.length > 3) {
5625						a[3] = Number(a[3]);
5626					}
5627				}
5628				if (toHSL && !wasHSL) {
5629					r = a[0] / 255;
5630					g = a[1] / 255;
5631					b = a[2] / 255;
5632					max = Math.max(r, g, b);
5633					min = Math.min(r, g, b);
5634					l = (max + min) / 2;
5635					if (max === min) {
5636						h = s = 0;
5637					} else {
5638						d = max - min;
5639						s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
5640						h = (max === r) ? (g - b) / d + (g < b ? 6 : 0) : (max === g) ? (b - r) / d + 2 : (r - g) / d + 4;
5641						h *= 60;
5642					}
5643					a[0] = (h + 0.5) | 0;
5644					a[1] = (s * 100 + 0.5) | 0;
5645					a[2] = (l * 100 + 0.5) | 0;
5646				}
5647				return a;
5648			},
5649			_formatColors = function(s, toHSL) {
5650				var colors = s.match(_colorExp) || [],
5651					charIndex = 0,
5652					parsed = colors.length ? "" : s,
5653					i, color, temp;
5654				for (i = 0; i < colors.length; i++) {
5655					color = colors[i];
5656					temp = s.substr(charIndex, s.indexOf(color, charIndex)-charIndex);
5657					charIndex += temp.length + color.length;
5658					color = _parseColor(color, toHSL);
5659					if (color.length === 3) {
5660						color.push(1);
5661					}
5662					parsed += temp + (toHSL ? "hsla(" + color[0] + "," + color[1] + "%," + color[2] + "%," + color[3] : "rgba(" + color.join(",")) + ")";
5663				}
5664				return parsed;
5665			},
5666			_colorExp = "(?:\\b(?:(?:rgb|rgba|hsl|hsla)\\(.+?\\))|\\B#.+?\\b"; //we'll dynamically build this Regular Expression to conserve file size. After building it, it will be able to find rgb(), rgba(), # (hexadecimal), and named color values like red, blue, purple, etc.
5667
5668		for (p in _colorLookup) {
5669			_colorExp += "|" + p + "\\b";
5670		}
5671		_colorExp = new RegExp(_colorExp+")", "gi");
5672
5673		CSSPlugin.colorStringFilter = function(a) {
5674			var combined = a[0] + a[1],
5675				toHSL;
5676			_colorExp.lastIndex = 0;
5677			if (_colorExp.test(combined)) {
5678				toHSL = (combined.indexOf("hsl(") !== -1 || combined.indexOf("hsla(") !== -1);
5679				a[0] = _formatColors(a[0], toHSL);
5680				a[1] = _formatColors(a[1], toHSL);
5681			}
5682		};
5683
5684		if (!TweenLite.defaultStringFilter) {
5685			TweenLite.defaultStringFilter = CSSPlugin.colorStringFilter;
5686		}
5687
5688		/**
5689		 * @private Returns a formatter function that handles taking a string (or number in some cases) and returning a consistently formatted one in terms of delimiters, quantity of values, etc. For example, we may get boxShadow values defined as "0px red" or "0px 0px 10px rgb(255,0,0)" or "0px 0px 20px 20px #F00" and we need to ensure that what we get back is described with 4 numbers and a color. This allows us to feed it into the _parseComplex() method and split the values up appropriately. The neat thing about this _getFormatter() function is that the dflt defines a pattern as well as a default, so for example, _getFormatter("0px 0px 0px 0px #777", true) not only sets the default as 0px for all distances and #777 for the color, but also sets the pattern such that 4 numbers and a color will always get returned.
5690		 * @param {!string} dflt The default value and pattern to follow. So "0px 0px 0px 0px #777" will ensure that 4 numbers and a color will always get returned.
5691		 * @param {boolean=} clr If true, the values should be searched for color-related data. For example, boxShadow values typically contain a color whereas borderRadius don't.
5692		 * @param {boolean=} collapsible If true, the value is a top/left/right/bottom style one that acts like margin or padding, where if only one value is received, it's used for all 4; if 2 are received, the first is duplicated for 3rd (bottom) and the 2nd is duplicated for the 4th spot (left), etc.
5693		 * @return {Function} formatter function
5694		 */
5695		var _getFormatter = function(dflt, clr, collapsible, multi) {
5696				if (dflt == null) {
5697					return function(v) {return v;};
5698				}
5699				var dColor = clr ? (dflt.match(_colorExp) || [""])[0] : "",
5700					dVals = dflt.split(dColor).join("").match(_valuesExp) || [],
5701					pfx = dflt.substr(0, dflt.indexOf(dVals[0])),
5702					sfx = (dflt.charAt(dflt.length - 1) === ")") ? ")" : "",
5703					delim = (dflt.indexOf(" ") !== -1) ? " " : ",",
5704					numVals = dVals.length,
5705					dSfx = (numVals > 0) ? dVals[0].replace(_numExp, "") : "",
5706					formatter;
5707				if (!numVals) {
5708					return function(v) {return v;};
5709				}
5710				if (clr) {
5711					formatter = function(v) {
5712						var color, vals, i, a;
5713						if (typeof(v) === "number") {
5714							v += dSfx;
5715						} else if (multi && _commasOutsideParenExp.test(v)) {
5716							a = v.replace(_commasOutsideParenExp, "|").split("|");
5717							for (i = 0; i < a.length; i++) {
5718								a[i] = formatter(a[i]);
5719							}
5720							return a.join(",");
5721						}
5722						color = (v.match(_colorExp) || [dColor])[0];
5723						vals = v.split(color).join("").match(_valuesExp) || [];
5724						i = vals.length;
5725						if (numVals > i--) {
5726							while (++i < numVals) {
5727								vals[i] = collapsible ? vals[(((i - 1) / 2) | 0)] : dVals[i];
5728							}
5729						}
5730						return pfx + vals.join(delim) + delim + color + sfx + (v.indexOf("inset") !== -1 ? " inset" : "");
5731					};
5732					return formatter;
5733
5734				}
5735				formatter = function(v) {
5736					var vals, a, i;
5737					if (typeof(v) === "number") {
5738						v += dSfx;
5739					} else if (multi && _commasOutsideParenExp.test(v)) {
5740						a = v.replace(_commasOutsideParenExp, "|").split("|");
5741						for (i = 0; i < a.length; i++) {
5742							a[i] = formatter(a[i]);
5743						}
5744						return a.join(",");
5745					}
5746					vals = v.match(_valuesExp) || [];
5747					i = vals.length;
5748					if (numVals > i--) {
5749						while (++i < numVals) {
5750							vals[i] = collapsible ? vals[(((i - 1) / 2) | 0)] : dVals[i];
5751						}
5752					}
5753					return pfx + vals.join(delim) + sfx;
5754				};
5755				return formatter;
5756			},
5757
5758			/**
5759			 * @private returns a formatter function that's used for edge-related values like marginTop, marginLeft, paddingBottom, paddingRight, etc. Just pass a comma-delimited list of property names related to the edges.
5760			 * @param {!string} props a comma-delimited list of property names in order from top to left, like "marginTop,marginRight,marginBottom,marginLeft"
5761			 * @return {Function} a formatter function
5762			 */
5763			_getEdgeParser = function(props) {
5764				props = props.split(",");
5765				return function(t, e, p, cssp, pt, plugin, vars) {
5766					var a = (e + "").split(" "),
5767						i;
5768					vars = {};
5769					for (i = 0; i < 4; i++) {
5770						vars[props[i]] = a[i] = a[i] || a[(((i - 1) / 2) >> 0)];
5771					}
5772					return cssp.parse(t, vars, pt, plugin);
5773				};
5774			},
5775
5776			// @private used when other plugins must tween values first, like BezierPlugin or ThrowPropsPlugin, etc. That plugin's setRatio() gets called first so that the values are updated, and then we loop through the MiniPropTweens  which handle copying the values into their appropriate slots so that they can then be applied correctly in the main CSSPlugin setRatio() method. Remember, we typically create a proxy object that has a bunch of uniquely-named properties that we feed to the sub-plugin and it does its magic normally, and then we must interpret those values and apply them to the css because often numbers must get combined/concatenated, suffixes added, etc. to work with css, like boxShadow could have 4 values plus a color.
5777			_setPluginRatio = _internals._setPluginRatio = function(v) {
5778				this.plugin.setRatio(v);
5779				var d = this.data,
5780					proxy = d.proxy,
5781					mpt = d.firstMPT,
5782					min = 0.000001,
5783					val, pt, i, str;
5784				while (mpt) {
5785					val = proxy[mpt.v];
5786					if (mpt.r) {
5787						val = Math.round(val);
5788					} else if (val < min && val > -min) {
5789						val = 0;
5790					}
5791					mpt.t[mpt.p] = val;
5792					mpt = mpt._next;
5793				}
5794				if (d.autoRotate) {
5795					d.autoRotate.rotation = proxy.rotation;
5796				}
5797				//at the end, we must set the CSSPropTween's "e" (end) value dynamically here because that's what is used in the final setRatio() method.
5798				if (v === 1) {
5799					mpt = d.firstMPT;
5800					while (mpt) {
5801						pt = mpt.t;
5802						if (!pt.type) {
5803							pt.e = pt.s + pt.xs0;
5804						} else if (pt.type === 1) {
5805							str = pt.xs0 + pt.s + pt.xs1;
5806							for (i = 1; i < pt.l; i++) {
5807								str += pt["xn"+i] + pt["xs"+(i+1)];
5808							}
5809							pt.e = str;
5810						}
5811						mpt = mpt._next;
5812					}
5813				}
5814			},
5815
5816			/**
5817			 * @private @constructor Used by a few SpecialProps to hold important values for proxies. For example, _parseToProxy() creates a MiniPropTween instance for each property that must get tweened on the proxy, and we record the original property name as well as the unique one we create for the proxy, plus whether or not the value needs to be rounded plus the original value.
5818			 * @param {!Object} t target object whose property we're tweening (often a CSSPropTween)
5819			 * @param {!string} p property name
5820			 * @param {(number|string|object)} v value
5821			 * @param {MiniPropTween=} next next MiniPropTween in the linked list
5822			 * @param {boolean=} r if true, the tweened value should be rounded to the nearest integer
5823			 */
5824			MiniPropTween = function(t, p, v, next, r) {
5825				this.t = t;
5826				this.p = p;
5827				this.v = v;
5828				this.r = r;
5829				if (next) {
5830					next._prev = this;
5831					this._next = next;
5832				}
5833			},
5834
5835			/**
5836			 * @private Most other plugins (like BezierPlugin and ThrowPropsPlugin and others) can only tween numeric values, but CSSPlugin must accommodate special values that have a bunch of extra data (like a suffix or strings between numeric values, etc.). For example, boxShadow has values like "10px 10px 20px 30px rgb(255,0,0)" which would utterly confuse other plugins. This method allows us to split that data apart and grab only the numeric data and attach it to uniquely-named properties of a generic proxy object ({}) so that we can feed that to virtually any plugin to have the numbers tweened. However, we must also keep track of which properties from the proxy go with which CSSPropTween values and instances. So we create a linked list of MiniPropTweens. Each one records a target (the original CSSPropTween), property (like "s" or "xn1" or "xn2") that we're tweening and the unique property name that was used for the proxy (like "boxShadow_xn1" and "boxShadow_xn2") and whether or not they need to be roun
5836ded. That way, in the _setPluginRatio() method we can simply copy the values over from the proxy to the CSSPropTween instance(s). Then, when the main CSSPlugin setRatio() method runs and applies the CSSPropTween values accordingly, they're updated nicely. So the external plugin tweens the numbers, _setPluginRatio() copies them over, and setRatio() acts normally, applying css-specific values to the element.
5837			 * This method returns an object that has the following properties:
5838			 *  - proxy: a generic object containing the starting values for all the properties that will be tweened by the external plugin.  This is what we feed to the external _onInitTween() as the target
5839			 *  - end: a generic object containing the ending values for all the properties that will be tweened by the external plugin. This is what we feed to the external plugin's _onInitTween() as the destination values
5840			 *  - firstMPT: the first MiniPropTween in the linked list
5841			 *  - pt: the first CSSPropTween in the linked list that was created when parsing. If shallow is true, this linked list will NOT attach to the one passed into the _parseToProxy() as the "pt" (4th) parameter.
5842			 * @param {!Object} t target object to be tweened
5843			 * @param {!(Object|string)} vars the object containing the information about the tweening values (typically the end/destination values) that should be parsed
5844			 * @param {!CSSPlugin} cssp The CSSPlugin instance
5845			 * @param {CSSPropTween=} pt the next CSSPropTween in the linked list
5846			 * @param {TweenPlugin=} plugin the external TweenPlugin instance that will be handling tweening the numeric values
5847			 * @param {boolean=} shallow if true, the resulting linked list from the parse will NOT be attached to the CSSPropTween that was passed in as the "pt" (4th) parameter.
5848			 * @return An object containing the following properties: proxy, end, firstMPT, and pt (see above for descriptions)
5849			 */
5850			_parseToProxy = _internals._parseToProxy = function(t, vars, cssp, pt, plugin, shallow) {
5851				var bpt = pt,
5852					start = {},
5853					end = {},
5854					transform = cssp._transform,
5855					oldForce = _forcePT,
5856					i, p, xp, mpt, firstPT;
5857				cssp._transform = null;
5858				_forcePT = vars;
5859				pt = firstPT = cssp.parse(t, vars, pt, plugin);
5860				_forcePT = oldForce;
5861				//break off from the linked list so the new ones are isolated.
5862				if (shallow) {
5863					cssp._transform = transform;
5864					if (bpt) {
5865						bpt._prev = null;
5866						if (bpt._prev) {
5867							bpt._prev._next = null;
5868						}
5869					}
5870				}
5871				while (pt && pt !== bpt) {
5872					if (pt.type <= 1) {
5873						p = pt.p;
5874						end[p] = pt.s + pt.c;
5875						start[p] = pt.s;
5876						if (!shallow) {
5877							mpt = new MiniPropTween(pt, "s", p, mpt, pt.r);
5878							pt.c = 0;
5879						}
5880						if (pt.type === 1) {
5881							i = pt.l;
5882							while (--i > 0) {
5883								xp = "xn" + i;
5884								p = pt.p + "_" + xp;
5885								end[p] = pt.data[xp];
5886								start[p] = pt[xp];
5887								if (!shallow) {
5888									mpt = new MiniPropTween(pt, xp, p, mpt, pt.rxp[xp]);
5889								}
5890							}
5891						}
5892					}
5893					pt = pt._next;
5894				}
5895				return {proxy:start, end:end, firstMPT:mpt, pt:firstPT};
5896			},
5897
5898
5899
5900			/**
5901			 * @constructor Each property that is tweened has at least one CSSPropTween associated with it. These instances store important information like the target, property, starting value, amount of change, etc. They can also optionally have a number of "extra" strings and numeric values named xs1, xn1, xs2, xn2, xs3, xn3, etc. where "s" indicates string and "n" indicates number. These can be pieced together in a complex-value tween (type:1) that has alternating types of data like a string, number, string, number, etc. For example, boxShadow could be "5px 5px 8px rgb(102, 102, 51)". In that value, there are 6 numbers that may need to tween and then pieced back together into a string again with spaces, suffixes, etc. xs0 is special in that it stores the suffix for standard (type:0) tweens, -OR- the first string (prefix) in a complex-value (type:1) CSSPropTween -OR- it can be the non-tweening value in a type:-1 CSSPropTween. We do this to conserve memory.
5902			 * CSSPropTweens have the following optional properties as well (not defined through the constructor):
5903			 *  - l: Length in terms of the number of extra properties that the CSSPropTween has (default: 0). For example, for a boxShadow we may need to tween 5 numbers in which case l would be 5; Keep in mind that the start/end values for the first number that's tweened are always stored in the s and c properties to conserve memory. All additional values thereafter are stored in xn1, xn2, etc.
5904			 *  - xfirst: The first instance of any sub-CSSPropTweens that are tweening properties of this instance. For example, we may split up a boxShadow tween so that there's a main CSSPropTween of type:1 that has various xs* and xn* values associated with the h-shadow, v-shadow, blur, color, etc. Then we spawn a CSSPropTween for each of those that has a higher priority and runs BEFORE the main CSSPropTween so that the values are all set by the time it needs to re-assemble them. The xfirst gives us an easy way to identify the first one in that chain which typically ends at the main one (because they're all prepende to the linked list)
5905			 *  - plugin: The TweenPlugin instance that will handle the tweening of any complex values. For example, sometimes we don't want to use normal subt
5905weens (like xfirst refers to) to tween the values - we might want ThrowPropsPlugin or BezierPlugin some other plugin to do the actual tweening, so we create a plugin instance and store a reference here. We need this reference so that if we get a request to round values or disable a tween, we can pass along that request.
5906			 *  - data: Arbitrary data that needs to be stored with the CSSPropTween. Typically if we're going to have a plugin handle the tweening of a complex-value tween, we create a generic object that stores the END values that we're tweening to and the CSSPropTween's xs1, xs2, etc. have the starting values. We store that object as data. That way, we can simply pass that object to the plugin and use the CSSPropTween as the target.
5907			 *  - setRatio: Only used for type:2 tweens that require custom functionality. In this case, we call the CSSPropTween's setRatio() method and pass the ratio each time the tween updates. This isn't quite as efficient as doing things directly in the CSSPlugin's setRatio() method, but it's very convenient and flexible.
5908			 * @param {!Object} t Target object whose property will be tweened. Often a DOM element, but not always. It could be anything.
5909			 * @param {string} p Property to tween (name). For example, to tween element.width, p would be "width".
5910			 * @param {number} s Starting numeric value
5911			 * @param {number} c Change in numeric value over the course of the entire tween. For example, if element.width starts at 5 and should end at 100, c would be 95.
5912			 * @param {CSSPropTween=} next The next CSSPropTween in the linked list. If one is defined, we will define its _prev as the new instance, and the new instance's _next will be pointed at it.
5913			 * @param {number=} type The type of CSSPropTween where -1 = a non-tweening value, 0 = a standard simple tween, 1 = a complex value (like one that has multiple numbers in a comma- or space-delimited string like border:"1px solid red"), and 2 = one that uses a custom setRatio function that does all of the work of applying the values on each update.
5914			 * @param {string=} n Name of the property that should be used for overwriting purposes which is typically the same as p but not always. For example, we may need to create a subtween for the 2nd part of a "clip:rect(...)" tween in which case "p" might be xs1 but "n" is still "clip"
5915			 * @param {boolean=} r If true, the value(s) should be rounded
5916			 * @param {number=} pr Priority in the linked list order. Higher priority CSSPropTweens will be updated before lower priority ones. The default priority is 0.
5917			 * @param {string=} b Beginning value. We store this to ensure that it is EXACTLY what it was when the tween began without any risk of interpretation issues.
5918			 * @param {string=} e Ending value. We store this to ensure that it is EXACTLY what the user defined at the end of the tween without any risk of interpretation issues.
5919			 */
5920			CSSPropTween = _internals.CSSPropTween = function(t, p, s, c, next, type, n, r, pr, b, e) {
5921				this.t = t; //target
5922				this.p = p; //property
5923				this.s = s; //starting value
5924				this.c = c; //change value
5925				this.n = n || p; //name that this CSSPropTween should be associated to (usually the same as p, but not always - n is what overwriting looks at)
5926				if (!(t instanceof CSSPropTween)) {
5927					_overwriteProps.push(this.n);
5928				}
5929				this.r = r; //round (boolean)
5930				this.type = type || 0; //0 = normal tween, -1 = non-tweening (in which case xs0 will be applied to the target's property, like tp.t[tp.p] = tp.xs0), 1 = complex-value SpecialProp, 2 = custom setRatio() that does all the work
5931				if (pr) {
5932					this.pr = pr;
5933					_hasPriority = true;
5934				}
5935				this.b = (b === undefined) ? s : b;
5936				this.e = (e === undefined) ? s + c : e;
5937				if (next) {
5938					this._next = next;
5939					next._prev = this;
5940				}
5941			},
5942
5943			_addNonTweeningNumericPT = function(target, prop, start, end, next, overwriteProp) { //cleans up some code redundancies and helps minification. Just a fast way to add a NUMERIC non-tweening CSSPropTween
5944				var pt = new CSSPropTween(target, prop, start, end - start, next, -1, overwriteProp);
5945				pt.b = start;
5946				pt.e = pt.xs0 = end;
5947				return pt;
5948			},
5949
5950			/**
5951			 * Takes a target, the beginning value and ending value (as strings) and parses them into a CSSPropTween (possibly with child CSSPropTweens) that accommodates multiple numbers, colors, comma-delimited values, etc. For example:
5952			 * sp.parseComplex(element, "boxShadow", "5px 10px 20px rgb(255,102,51)", "0px 0px 0px red", true, "0px 0px 0px rgb(0,0,0,0)", pt);
5953			 * It will walk through the beginning and ending values (which should be in the same format with the same number and type of values) and figure out which parts are numbers, what strings separate the numeric/tweenable values, and then create the CSSPropTweens accordingly. If a plugin is defined, no child CSSPropTweens will be created. Instead, the ending values will be stored in the "data" property of the returned CSSPropTween like: {s:-5, xn1:-10, xn2:-20, xn3:255, xn4:0, xn5:0} so that it can be fed to any other plugin and it'll be plain numeric tweens but the recomposition of the complex value will be handled inside CSSPlugin's setRatio().
5954			 * If a setRatio is defined, the type of the CSSPropTween will be set to 2 and recomposition of the values will be the responsibility of that method.
5955			 *
5956			 * @param {!Object} t Target whose property will be tweened
5957			 * @param {!string} p Property that will be tweened (its name, like "left" or "backgroundColor" or "boxShadow")
5958			 * @param {string} b Beginning value
5959			 * @param {string} e Ending value
5960			 * @param {boolean} clrs If true, the value could contain a color value like "rgb(255,0,0)" or "#F00" or "red". The default is false, so no colors will be recognized (a performance optimization)
5961			 * @param {(string|number|Object)} dflt The default beginning value that should be used if no valid beginning value is defined or if the number of values inside the complex beginning and ending values don't match
5962			 * @param {?CSSPropTween} pt CSSPropTween instance that is the current head of the linked list (we'll prepend to this).
5963			 * @param {number=} pr Priority in the linked list order. Higher priority properties will be updated before lower priority ones. The default priority is 0.
5964			 * @param {TweenPlugin=} plugin If a plugin should handle the tweening of extra properties, pass the plugin instance here. If one is defined, then NO subtweens will be created for any extra properties (the properties will be created - just not additional CSSPropTween instances to tween them) because the plugin is expected to do so. However, the end values WILL be populated in the "data" property, like {s:100, xn1:50, xn2:300}
5965			 * @param {function(number)=} setRatio If values should be set in a custom function instead of being pieced together in a type:1 (complex-value) CSSPropTween, define that custom function here.
5966			 * @return {CSSPropTween} The first CSSPropTween in the linked list which includes the new one(s) added by the parseComplex() call.
5967			 */
5968			_parseComplex = CSSPlugin.parseComplex = function(t, p, b, e, clrs, dflt, pt, pr, plugin, setRatio) {
5969				//DEBUG: _log("parseComplex: "+p+", b: "+b+", e: "+e);
5970				b = b || dflt || "";
5971				pt = new CSSPropTween(t, p, 0, 0, pt, (setRatio ? 2 : 1), null, false, pr, b, e);
5972				e += ""; //ensures it's a string
5973				var ba = b.split(", ").join(",").split(" "), //beginning array
5974					ea = e.split(", ").join(",").split(" "), //ending array
5975					l = ba.length,
5976					autoRound = (_autoRound !== false),
5977					i, xi, ni, bv, ev, bnums, enums, bn, hasAlpha, temp, cv, str, useHSL;
5978				if (e.indexOf(",") !== -1 || b.indexOf(",") !== -1) {
5979					ba = ba.join(" ").replace(_commasOutsideParenExp, ", ").split(" ");
5980					ea = ea.join(" ").replace(_commasOutsideParenExp, ", ").split(" ");
5981					l = ba.length;
5982				}
5983				if (l !== ea.length) {
5984					//DEBUG: _log("mismatched formatting detected on " + p + " (" + b + " vs " + e + ")");
5985					ba = (dflt || "").split(" ");
5986					l = ba.length;
5987				}
5988				pt.plugin = plugin;
5989				pt.setRatio = setRatio;
5990				_colorExp.lastIndex = 0;
5991				for (i = 0; i < l; i++) {
5992					bv = ba[i];
5993					ev = ea[i];
5994					bn = parseFloat(bv);
5995					//if the value begins with a number (most common). It's fine if it has a suffix like px
5996					if (bn || bn === 0) {
5997						pt.appendXtra("", bn, _parseChange(ev, bn), ev.replace(_relNumExp, ""), (autoRound && ev.indexOf("px") !== -1), true);
5998
5999					//if the value is a color
6000					} else if (clrs && _colorExp.test(bv)) {
6001						str = ev.charAt(ev.length - 1) === "," ? ")," : ")"; //if there's a comma at the end, retain it.
6002						useHSL = (ev.indexOf("hsl") !== -1 && _supportsOpacity);
6003						bv = _parseColor(bv, useHSL);
6004						ev = _parseColor(ev, useHSL);
6005						hasAlpha = (bv.length + ev.length > 6);
6006						if (hasAlpha && !_supportsOpacity && ev[3] === 0) { //older versions of IE don't support rgba(), so if the destination alpha is 0, just use "transparent" for the end color
6007							pt["xs" + pt.l] += pt.l ? " transparent" : "transparent";
6008							pt.e = pt.e.split(ea[i]).join("transparent");
6009						} else {
6010							if (!_supportsOpacity) { //old versions of IE don't support rgba().
6011								hasAlpha = false;
6012							}
6013							if (useHSL) {
6014								pt.appendXtra((hasAlpha ? "hsla(" : "hsl("), bv[0], _parseChange(ev[0], bv[0]), ",", false, true)
6015									.appendXtra("", bv[1], _parseChange(ev[1], bv[1]), "%,", false)
6016									.appendXtra("", bv[2], _parseChange(ev[2], bv[2]), (hasAlpha ? "%," : "%" + str), false);
6017							} else {
6018								pt.appendXtra((hasAlpha ? "rgba(" : "rgb("), bv[0], ev[0] - bv[0], ",", true, true)
6019									.appendXtra("", bv[1], ev[1] - bv[1], ",", true)
6020									.appendXtra("", bv[2], ev[2] - bv[2], (hasAlpha ? "," : str), true);
6021							}
6022
6023							if (hasAlpha) {
6024								bv = (bv.length < 4) ? 1 : bv[3];
6025								pt.appendXtra("", bv, ((ev.length < 4) ? 1 : ev[3]) - bv, str, false);
6026							}
6027						}
6028						_colorExp.lastIndex = 0; //otherwise the test() on the RegExp could move the lastIndex and taint future results.
6029
6030					} else {
6031						bnums = bv.match(_numExp); //gets each group of numbers in the beginning value string and drops them into an array
6032
6033						//if no number is found, treat it as a non-tweening value and just append the string to the current xs.
6034						if (!bnums) {
6035							pt["xs" + pt.l] += pt.l ? " " + bv : bv;
6036
6037						//loop through all the numbers that are found and construct the extra values on the pt.
6038						} else {
6039							enums = ev.match(_relNumExp); //get each group of numbers in the end value string and drop them into an array. We allow relative values too, like +=50 or -=.5
6040							if (!enums || enums.length !== bnums.length) {
6041								//DEBUG: _log("mismatched formatting detected on " + p + " (" + b + " vs " + e + ")");
6042								return pt;
6043							}
6044							ni = 0;
6045							for (xi = 0; xi < bnums.length; xi++) {
6046								cv = bnums[xi];
6047								temp = bv.indexOf(cv, ni);
6048								pt.appendXtra(bv.substr(ni, temp - ni), Number(cv), _parseChange(enums[xi], cv), "", (autoRound && bv.substr(temp + cv.length, 2) === "px"), (xi === 0));
6049								ni = temp + cv.length;
6050							}
6051							pt["xs" + pt.l] += bv.substr(ni);
6052						}
6053					}
6054				}
6055				//if there are relative values ("+=" or "-=" prefix), we need to adjust the ending value to eliminate the prefixes and combine the values properly.
6056				if (e.indexOf("=") !== -1) if (pt.data) {
6057					str = pt.xs0 + pt.data.s;
6058					for (i = 1; i < pt.l; i++) {
6059						str += pt["xs" + i] + pt.data["xn" + i];
6060					}
6061					pt.e = str + pt["xs" + i];
6062				}
6063				if (!pt.l) {
6064					pt.type = -1;
6065					pt.xs0 = pt.e;
6066				}
6067				return pt.xfirst || pt;
6068			},
6069			i = 9;
6070
6071
6072		p = CSSPropTween.prototype;
6073		p.l = p.pr = 0; //length (number of extra properties like xn1, xn2, xn3, etc.
6074		while (--i > 0) {
6075			p["xn" + i] = 0;
6076			p["xs" + i] = "";
6077		}
6078		p.xs0 = "";
6079		p._next = p._prev = p.xfirst = p.data = p.plugin = p.setRatio = p.rxp = null;
6080
6081
6082		/**
6083		 * Appends and extra tweening value to a CSSPropTween and automatically manages any prefix and suffix strings. The first extra value is stored in the s and c of the main CSSPropTween instance, but thereafter any extras are stored in the xn1, xn2, xn3, etc. The prefixes and suffixes are stored in the xs0, xs1, xs2, etc. properties. For example, if I walk through a clip value like "rect(10px, 5px, 0px, 20px)", the values would be stored like this:
6084		 * xs0:"rect(", s:10, xs1:"px, ", xn1:5, xs2:"px, ", xn2:0, xs3:"px, ", xn3:20, xn4:"px)"
6085		 * And they'd all get joined together when the CSSPlugin renders (in the setRatio() method).
6086		 * @param {string=} pfx Prefix (if any)
6087		 * @param {!number} s Starting value
6088		 * @param {!number} c Change in numeric value over the course of the entire tween. For example, if the start is 5 and the end is 100, the change would be 95.
6089		 * @param {string=} sfx Suffix (if any)
6090		 * @param {boolean=} r Round (if true).
6091		 * @param {boolean=} pad If true, this extra value should be separated by the previous one by a space. If there is no previous extra and pad is true, it will automatically drop the space.
6092		 * @return {CSSPropTween} returns itself so that multiple methods can be chained together.
6093		 */
6094		p.appendXtra = function(pfx, s, c, sfx, r, pad) {
6095			var pt = this,
6096				l = pt.l;
6097			pt["xs" + l] += (pad && l) ? " " + pfx : pfx || "";
6098			if (!c) if (l !== 0 && !pt.plugin) { //typically we'll combine non-changing values right into the xs to optimize performance, but we don't combine them when there's a plugin that will be tweening the values because it may depend on the values being split apart, like for a bezier, if a value doesn't change between the first and second iteration but then it does on the 3rd, we'll run into trouble because there's no xn slot for that value!
6099				pt["xs" + l] += s + (sfx || "");
6100				return pt;
6101			}
6102			pt.l++;
6103			pt.type = pt.setRatio ? 2 : 1;
6104			pt["xs" + pt.l] = sfx || "";
6105			if (l > 0) {
6106				pt.data["xn" + l] = s + c;
6107				pt.rxp["xn" + l] = r; //round extra property (we need to tap into this in the _parseToProxy() method)
6108				pt["xn" + l] = s;
6109				if (!pt.plugin) {
6110					pt.xfirst = new CSSPropTween(pt, "xn" + l, s, c, pt.xfirst || pt, 0, pt.n, r, pt.pr);
6111					pt.xfirst.xs0 = 0; //just to ensure that the property stays numeric which helps modern browsers speed up processing. Remember, in the setRatio() method, we do pt.t[pt.p] = val + pt.xs0 so if pt.xs0 is "" (the default), it'll cast the end value as a string. When a property is a number sometimes and a string sometimes, it prevents the compiler from locking in the data type, slowing things down slightly.
6112				}
6113				return pt;
6114			}
6115			pt.data = {s:s + c};
6116			pt.rxp = {};
6117			pt.s = s;
6118			pt.c = c;
6119			pt.r = r;
6120			return pt;
6121		};
6122
6123		/**
6124		 * @constructor A SpecialProp is basically a css property that needs to be treated in a non-standard way, like if it may contain a complex value like boxShadow:"5px 10px 15px rgb(255, 102, 51)" or if it is associated with another plugin like ThrowPropsPlugin or BezierPlugin. Every SpecialProp is associated with a particular property name like "boxShadow" or "throwProps" or "bezier" and it will intercept those values in the vars object that's passed to the CSSPlugin and handle them accordingly.
6125		 * @param {!string} p Property name (like "boxShadow" or "throwProps")
6126		 * @param {Object=}
6126 options An object containing any of the following configuration options:
6127		 *                      - defaultValue: the default value
6128		 *                      - parser: A function that should be called when the associated property name is found in the vars. This function should return a CSSPropTween instance and it should ensure that it is properly inserted into the linked list. It will receive 4 paramters: 1) The target, 2) The value defined in the vars, 3) The CSSPlugin instance (whose _firstPT should be used for the linked list), and 4) A computed style object if one was calculated (this is a speed optimization that allows retrieval of starting values quicker)
6129		 *                      - formatter: a function that formats any value received for this special property (for example, boxShadow could take "5px 5px red" and format it to "5px 5px 0px 0px red" so that both the beginning and ending values have a common order and quantity of values.)
6130		 *                      - prefix: if true, we'll determine whether or not this property requires a vendor prefix (like Webkit or Moz or ms or O)
6131		 *                      - color: set this to true if the value for this SpecialProp may contain color-related values like rgb(), rgba(), etc.
6132		 *                      - priority: priority in the linked list order. Higher priority SpecialProps will be updated before lower priority ones. The default priority is 0.
6133		 *                      - multi: if true, the formatter should accommodate a comma-delimited list of values, like boxShadow could have multiple boxShadows listed out.
6134		 *                      - collapsible: if true, the formatter should treat the value like it's a top/right/bottom/left value that could be collapsed, like "5px" would apply to all, "5px, 10px" would use 5px for top/bottom and 10px for right/left, etc.
6135		 *                      - keyword: a special keyword that can [optionally] be found inside the value (like "inset" for boxShadow). This allows us to validate beginning/ending values to make sure they match (if the keyword is found in one, it'll be added to the other for consistency by default).
6136		 */
6137		var SpecialProp = function(p, options) {
6138				options = options || {};
6139				this.p = options.prefix ? _checkPropPrefix(p) || p : p;
6140				_specialProps[p] = _specialProps[this.p] = this;
6141				this.format = options.formatter || _getFormatter(options.defaultValue, options.color, options.collapsible, options.multi);
6142				if (options.parser) {
6143					this.parse = options.parser;
6144				}
6145				this.clrs = options.color;
6146				this.multi = options.multi;
6147				this.keyword = options.keyword;
6148				this.dflt = options.defaultValue;
6149				this.pr = options.priority || 0;
6150			},
6151
6152			//shortcut for creating a new SpecialProp that can accept multiple properties as a comma-delimited list (helps minification). dflt can be an array for multiple values (we don't do a comma-delimited list because the default value may contain commas, like rect(0px,0px,0px,0px)). We attach this method to the SpecialProp class/object instead of using a private _createSpecialProp() method so that we can tap into it externally if necessary, like from another plugin.
6153			_registerComplexSpecialProp = _internals._registerComplexSpecialProp = function(p, options, defaults) {
6154				if (typeof(options) !== "object") {
6155					options = {parser:defaults}; //to make backwards compatible with older versions of BezierPlugin and ThrowPropsPlugin
6156				}
6157				var a = p.split(","),
6158					d = options.defaultValue,
6159					i, temp;
6160				defaults = defaults || [d];
6161				for (i = 0; i < a.length; i++) {
6162					options.prefix = (i === 0 && options.prefix);
6163					options.defaultValue = defaults[i] || d;
6164					temp = new SpecialProp(a[i], options);
6165				}
6166			},
6167
6168			//creates a placeholder special prop for a plugin so that the property gets caught the first time a tween of it is attempted, and at that time it makes the plugin register itself, thus taking over for all future tweens of that property. This allows us to not mandate that things load in a particular order and it also allows us to log() an error that informs the user when they attempt to tween an external plugin-related property without loading its .js file.
6169			_registerPluginProp = function(p) {
6170				if (!_specialProps[p]) {
6171					var pluginName = p.charAt(0).toUpperCase() + p.substr(1) + "Plugin";
6172					_registerComplexSpecialProp(p, {parser:function(t, e, p, cssp, pt, plugin, vars) {
6173						var pluginClass = _globals.com.greensock.plugins[pluginName];
6174						if (!pluginClass) {
6175							_log("Error: " + pluginName + " js file not loaded.");
6176							return pt;
6177						}
6178						pluginClass._cssRegister();
6179						return _specialProps[p].parse(t, e, p, cssp, pt, plugin, vars);
6180					}});
6181				}
6182			};
6183
6184
6185		p = SpecialProp.prototype;
6186
6187		/**
6188		 * Alias for _parseComplex() that automatically plugs in certain values for this SpecialProp, like its property name, whether or not colors should be sensed, the default value, and priority. It also looks for any keyword that the SpecialProp defines (like "inset" for boxSh
6188adow) and ensures that the beginning and ending values have the same number of values for SpecialProps where multi is true (like boxShadow and textShadow can have a comma-delimited list)
6189		 * @param {!Object} t target element
6190		 * @param {(string|number|object)} b beginning value
6191		 * @param {(string|number|object)} e ending (destination) value
6192		 * @param {CSSPropTween=} pt next CSSPropTween in the linked list
6193		 * @param {TweenPlugin=} plugin If another plugin will be tweening the complex value, that TweenPlugin instance goes here.
6194		 * @param {function=} setRatio If a custom setRatio() method should be used to handle this complex value, that goes here.
6195		 * @return {CSSPropTween=} First CSSPropTween in the linked list
6196		 */
6197		p.parseComplex = function(t, b, e, pt, plugin, setRatio) {
6198			var kwd = this.keyword,
6199				i, ba, ea, l, bi, ei;
6200			//if this SpecialProp's value can contain a comma-delimited list of values (like boxShadow or textShadow), we must parse them in a special way, and look for a keyword (like "inset" for boxShadow) and ensure that the beginning and ending BOTH have it if the end defines it as such. We also must ensure that there are an equal number of values specified (we can't tween 1 boxShadow to 3 for example)
6201			if (this.multi) if (_commasOutsideParenExp.test(e) || _commasOutsideParenExp.test(b)) {
6202				ba = b.replace(_commasOutsideParenExp, "|").split("|");
6203				ea = e.replace(_commasOutsideParenExp, "|").split("|");
6204			} else if (kwd) {
6205				ba = [b];
6206				ea = [e];
6207			}
6208			if (ea) {
6209				l = (ea.length > ba.length) ? ea.length : ba.length;
6210				for (i = 0; i < l; i++) {
6211					b = ba[i] = ba[i] || this.dflt;
6212					e = ea[i] = ea[i] || this.dflt;
6213					if (kwd) {
6214						bi = b.indexOf(kwd);
6215						ei = e.indexOf(kwd);
6216						if (bi !== ei) {
6217							if (ei === -1) { //if the keyword isn't in the end value, remove it from the beginning one.
6218								ba[i] = ba[i].split(kwd).join("");
6219							} else if (bi === -1) { //if the keyword isn't in the beginning, add it.
6220								ba[i] += " " + kwd;
6221							}
6222						}
6223					}
6224				}
6225				b = ba.join(", ");
6226				e = ea.join(", ");
6227			}
6228			return _parseComplex(t, this.p, b, e, this.clrs, this.dflt, pt, this.pr, plugin, setRatio);
6229		};
6230
6231		/**
6232		 * Accepts a target and end value and spits back a CSSPropTween that has been inserted into the CSSPlugin's linked list and conforms with all the conventions we use internally, like type:-1, 0, 1, or 2, setting up any extra property tweens, priority, etc. For example, if we have a boxShadow SpecialProp and call:
6233		 * this._firstPT = sp.parse(element, "5px 10px 20px rgb(2550,102,51)", "boxShadow", this);
6234		 * It should figure out the starting value of the element's boxShadow, compare it to the provided end value and create all the necessary CSSPropTweens of the appropriate types to tween the boxShadow. The CSSPropTween that gets spit back should already be inserted into the linked list (the 4th parameter is the current head, so prepend to that).
6235		 * @param {!Object} t Target object whose property is being tweened
6236		 * @param {Object} e End value as provided in the vars object (typically a string, but not always - like a throwProps would be an object).
6237		 * @param {!string} p Property name
6238		 * @param {!CSSPlugin} cssp The CSSPlugin instance that should be associated with this tween.
6239		 * @param {?CSSPropTween} pt The CSSPropTween that is the current head of the linked list (we'll prepend to it)
6240		 * @param {TweenPlugin=} plugin If a plugin will be used to tween the parsed value, this is the plugin instance.
6241		 * @param {Object=} vars Original vars object that contains the data for parsing.
6242		 * @return {CSSPropTween} The first CSSPropTween in the linked list which includes the new one(s) added by the parse() call.
6243		 */
6244		p.parse = function(t, e, p, cssp, pt, plugin, vars) {
6245			return this.parseComplex(t.style, this.format(_getStyle(t, this.p, _cs, false, this.dflt)), this.format(e), pt, plugin);
6246		};
6247
6248		/**
6249		 * Registers a special property that should be intercepted from any "css" objects defined in tweens. This allows you to handle them however you want without CSSPlugin doing it for you. The 2nd parameter should be a function that accepts 3 parameters:
6250		 *  1) Target object whose property should be tweened (typically a DOM element)
6251		 *  2) The end/destination value (could be a string, number, object, or whatever you want)
6252		 *  3) The tween instance (you probably don't need to worry about this, but it can be useful for looking up information like the duration)
6253		 *
6254		 * Then, your function should return a function which will be called each time the tween gets rendered, passing a numeric "ratio" parameter to your function that indicates the change factor (usually between 0 and 1). For example:
6255		 *
6256		 * CSSPlugin.registerSpecialProp("myCustomProp", function(target, value, tween) {
6257		 *      var start = target.style.width;
6258		 *      return function(ratio) {
6259		 *              target.style.width = (start + value * ratio) + "px";
6260		 *              console.log("set width to " + target.style.width);
6261		 *          }
6262		 * }, 0);
6263		 *
6264		 * Then, when I do this tween, it will trigger my special property:
6265		 *
6266		 * TweenLite.to(element, 1, {css:{myCustomProp:100}});
6267		 *
6268		 * In the example, of course, we're just changing the width, but you can do anything you want.
6269		 *
6270		 * @param {!string} name Property name (or comma-delimited list of property names) that should be intercepted and handled by your function. For example, if I define "myCustomProp", then it would handle that portion of the following tween: TweenLite.to(element, 1, {css:{myCustomProp:100}})
6271		 * @param {!function(Object, Object, Object, string):function(number)} onInitTween The function that will be called when a tween of this special property is performed. The function will receive 4 parameters: 1) Target object that should be tweened, 2) Value that was passed to the tween, 3) The tween instance itself (rarely used), and 4) The property name that's being tweened. Your function should return a function that should be called on every update of the tween. That function will receive a single parameter that is a "change factor" value (typically between 0 and 1) indicating the amount of change as a ratio. You can use this to determine how to set the values appropriately in your function.
6272		 * @param {number=} priority Priority that helps the engine determine the order in which to set the properties (default: 0). Higher priority properties will be updated before lower priority ones.
6273		 */
6274		CSSPlugin.registerSpecialProp = function(name, onInitTween, priority) {
6275			_registerComplexSpecialProp(name, {parser:function(t, e, p, cssp, pt, plugin, vars) {
6276				var rv = new CSSPropTween(t, p, 0, 0, pt, 2, p, false, priority);
6277				rv.plugin = plugin;
6278				rv.setRatio = onInitTween(t, e, cssp._tween, p);
6279				return rv;
6280			}, priority:priority});
6281		};
6282
6283
6284
6285
6286
6287
6288		//transform-related methods and properties
6289		CSSPlugin.useSVGTransformAttr = _isSafari || _isFirefox; //Safari and Firefox both have some rendering bugs when applying CSS transforms to SVG elements, so default to using the "transform" attribute instead (users can override this).
6290		var _transformProps = ("scaleX,scaleY,scaleZ,x,y,z,skewX,skewY,rotation,rotationX,rotationY,perspective,xPercent,yPercent").split(","),
6291			_transformProp = _checkPropPrefix("transform"), //the Javascript (camelCase) transform property, like msTransform, WebkitTransform, MozTransform, or OTransform.
6292			_transformPropCSS = _prefixCSS + "transform",
6293			_transformOriginProp = _checkPropPrefix("transformOrigin"),
6294			_supports3D = (_checkPropPrefix("perspective") !== null),
6295			Transform = _internals.Transform = function() {
6296				this.perspective = parseFloat(CSSPlugin.defaultTransformPerspective) || 0;
6297				this.force3D = (CSSPlugin.defaultForce3D === false || !_supports3D) ? false : CSSPlugin.defaultForce3D || "auto";
6298			},
6299			_SVGElement = window.SVGElement,
6300			_useSVGTransformAttr,
6301			//Some browsers (like Firefox and IE) don't honor transform-origin properly in SVG elements, so we need to manually adjust the matrix accordingly. We feature detect here rather than always doing the conversion for certain browsers because they may fix the problem at some point in the future.
6302
6303			_createSVG = function(type, container, attributes) {
6304				var element = _doc.createElementNS("http://www.w3.org/2000/svg", type),
6305					reg = /([a-z])([A-Z])/g,
6306					p;
6307				for (p in attributes) {
6308					element.setAttributeNS(null, p.replace(reg, "$1-$2").toLowerCase(), attributes[p]);
6309				}
6310				container.appendChild(element);
6311				return element;
6312			},
6313			_docElement = _doc.documentElement,
6314			_forceSVGTransformAttr = (function() {
6315				//IE and Android stock don't support CSS transforms on SVG elements, so we must write them to the "transform" attribute. We populate this variable in the _parseTransform() method, and only if/when we come across an SVG element
6316				var force = _ieVers || (/Android/i.test(_agent) && !window.chrome),
6317					svg, rect, width;
6318				if (_doc.createElementNS && !force) { //IE8 and earlier doesn't support SVG anyway
6319					svg = _createSVG("svg", _docElement);
6320					rect = _createSVG("rect", svg, {width:100, height:50, x:100});
6321					width = rect.getBoundingClientRect().width;
6322					rect.style[_transformOriginProp] = "50% 50%";
6323					rect.style[_transformProp] = "scaleX(0.5)";
6324					force = (width === rect.getBoundingClientRect().width && !(_is
6324Firefox && _supports3D)); //note: Firefox fails the test even though it does support CSS transforms in 3D. Since we can't push 3D stuff into the transform attribute, we force Firefox to pass the test here (as long as it does truly support 3D).
6325					_docElement.removeChild(svg);
6326				}
6327				return force;
6328			})(),
6329			_parseSVGOrigin = function(e, local, decoratee, absolute, smoothOrigin) {
6330				var tm = e._gsTransform,
6331					m = _getMatrix(e, true),
6332					v, x, y, xOrigin, yOrigin, a, b, c, d, tx, ty, determinant, xOriginOld, yOriginOld;
6333				if (tm) {
6334					xOriginOld = tm.xOrigin; //record the original values before we alter them.
6335					yOriginOld = tm.yOrigin;
6336				}
6337				if (!absolute || (v = absolute.split(" ")).length < 2) {
6338					b = e.getBBox();
6339					local = _parsePosition(local).split(" ");
6340					v = [(local[0].indexOf("%") !== -1 ? parseFloat(local[0]) / 100 * b.width : parseFloat(local[0])) + b.x,
6341						 (local[1].indexOf("%") !== -1 ? parseFloat(local[1]) / 100 * b.height : parseFloat(local[1])) + b.y];
6342				}
6343				decoratee.xOrigin = xOrigin = parseFloat(v[0]);
6344				decoratee.yOrigin = yOrigin = parseFloat(v[1]);
6345				if (absolute && m !== _identity2DMatrix) { //if svgOrigin is being set, we must invert the matrix and determine where the absolute point is, factoring in the current transforms. Otherwise, the svgOrigin would be based on the element's non-transformed position on the canvas.
6346					a = m[0];
6347					b = m[1];
6348					c = m[2];
6349					d = m[3];
6350					tx = m[4];
6351					ty = m[5];
6352					determinant = (a * d - b * c);
6353					x = xOrigin * (d / determinant) + yOrigin * (-c / determinant) + ((c * ty - d * tx) / determinant);
6354					y = xOrigin * (-b / determinant) + yOrigin * (a / determinant) - ((a * ty - b * tx) / determinant);
6355					xOrigin = decoratee.xOrigin = v[0] = x;
6356					yOrigin = decoratee.yOrigin = v[1] = y;
6357				}
6358				if (tm) { //avoid jump when transformOrigin is changed - adjust the x/y values accordingly
6359					if (smoothOrigin || (smoothOrigin !== false && CSSPlugin.defaultSmoothOrigin !== false)) {
6360						x = xOrigin - xOriginOld;
6361						y = yOrigin - yOriginOld;
6362						//originally, we simply adjusted the x and y values, but that would cause problems if, for example, you created a rotational tween part-way through an x/y tween. Managing the offset in a separate variable gives us ultimate flexibility.
6363						//tm.x -= x - (x * m[0] + y * m[2]);
6364						//tm.y -= y - (x * m[1] + y * m[3]);
6365						tm.xOffset += (x * m[0] + y * m[2]) - x;
6366						tm.yOffset += (x * m[1] + y * m[3]) - y;
6367					} else {
6368						tm.xOffset = tm.yOffset = 0;
6369					}
6370				}
6371				e.setAttribute("data-svg-origin", v.join(" "));
6372			},
6373			_isSVG = function(e) {
6374				return !!(_SVGElement && typeof(e.getBBox) === "function" && e.getCTM && (!e.parentNode || (e.parentNode.getBBox && e.parentNode.getCTM)));
6375			},
6376			_identity2DMatrix = [1,0,0,1,0,0],
6377			_getMatrix = function(e, force2D) {
6378				var tm = e._gsTransform || new Transform(),
6379					rnd = 100000,
6380					isDefault, s, m, n, dec;
6381				if (_transformProp) {
6382					s = _getStyle(e, _transformPropCSS, null, true);
6383				} else if (e.currentStyle) {
6384					//for older versions of IE, we need to interpret the filter portion that is in the format: progid:DXImageTransform.Microsoft.Matrix(M11=6.123233995736766e-17, M12=-1, M21=1, M22=6.123233995736766e-17, sizingMethod='auto expand') Notice that we need to swap b and c compared to a normal matrix.
6385					s = e.currentStyle.filter.match(_ieGetMatrixExp);
6386					s = (s && s.length === 4) ? [s[0].substr(4), Number(s[2].substr(4)), Number(s[1].substr(4)), s[3].substr(4), (tm.x || 0), (tm.y || 0)].join(",") : "";
6387				}
6388				isDefault = (!s || s === "none" || s === "matrix(1, 0, 0, 1, 0, 0)");
6389				if (tm.svg || (e.getBBox && _isSVG(e))) {
6390					if (isDefault && (e.style[_transformProp] + "").indexOf("matrix") !== -1) { //some browsers (like Chrome 40) don't correctly report transforms that are applied inline on an SVG element (they don't get included in the computed style), so we double-check here and accept matrix values
6391						s = e.style[_transformProp];
6392						isDefault = 0;
6393					}
6394					m = e.getAttribute("transform");
6395					if (isDefault && m) {
6396						if (m.indexOf("matrix") !== -1) { //just in case there's a "transform" value specified as an attribute instead of CSS style. Accept either a matrix() or simple translate() value though.
6397							s = m;
6398							isDefault = 0;
6399						} else if (m.indexOf("translate") !== -1) {
6400							s = "matrix(1,0,0,1," + m.match(/(?:\-|\b)[\d\-\.e]+\b/gi).join(",") + ")";
6401							isDefault = 0;
6402						}
6403					}
6404				}
6405				if (isDefault) {
6406					return _identity2DMatrix;
6407				}
6408				//split the matrix values out into an array (m for matrix)
6409				m = (s || "").match(/(?:\-|\b)[\d\-\.e]+\b/gi) || [];
6410				i = m.length;
6411				while (--i > -1) {
6412					n = Number(m[i]);
6413					m[i] = (dec = n - (n |= 0)) ? ((dec * rnd + (dec < 0 ? -0.5 : 0.5)) | 0) / rnd + n : n; //convert strings to Numbers and round to 5 decimal places to avoid issues with tiny numbers. Roughly 20x faster than Number.toFixed(). We also must make sure to round before dividing so that values like 0.9999999999 become 1 to avoid glitches in browser rendering and interpretation of flipped/rotated 3D matrices. And don't just multiply the number by rnd, floor it, and then divide by rnd because the bitwise operations max out at a 32-bit signed integer, thus it could get clipped at a relatively low value (like 22,000.00000 for example).
6414				}
6415				return (force2D && m.length > 6) ? [m[0], m[1], m[4], m[5], m[12], m[13]] : m;
6416			},
6417
6418			/**
6419			 * Parses the transform values for an element, returning an object with x, y, z, scaleX, scaleY, scaleZ, rotation, rotationX, rotationY, skewX, and skewY properties. Note: by default (for performance reasons), all skewing is combined into skewX and rotation but skewY still has a place in the transform object so that we can record how much of the skew is attributed to skewX vs skewY. Remember, a skewY of 10 looks the same as a rotation of 10 and skewX of -10.
6420			 * @param {!Object} t target element
6421			 * @param {Object=} cs computed style object (optional)
6422			 * @param {boolean=} rec if true, the transform values will be recorded to the target element's _gsTransform object, like target._gsTransform = {x:0, y:0, z:0, scaleX:1...}
6423			 * @param {boolean=} parse if true, we'll ignore any _gsTransform values that already exist on the element, and force a reparsing of the css (calculated style)
6424			 * @return {object}
6424 object containing all of the transform properties/values like {x:0, y:0, z:0, scaleX:1...}
6425			 */
6426			_getTransform = _internals.getTransform = function(t, cs, rec, parse) {
6427				if (t._gsTransform && rec && !parse) {
6428					return t._gsTransform; //if the element already has a _gsTransform, use that. Note: some browsers don't accurately return the calculated style for the transform (particularly for SVG), so it's almost always safest to just use the values we've already applied rather than re-parsing things.
6429				}
6430				var tm = rec ? t._gsTransform || new Transform() : new Transform(),
6431					invX = (tm.scaleX < 0), //in order to interpret things properly, we need to know if the user applied a negative scaleX previously so that we can adjust the rotation and skewX accordingly. Otherwise, if we always interpret a flipped matrix as affecting scaleY and the user only wants to tween the scaleX on multiple sequential tweens, it would keep the negative scaleY without that being the user's intent.
6432					min = 0.00002,
6433					rnd = 100000,
6434					zOrigin = _supports3D ? parseFloat(_getStyle(t, _transformOriginProp, cs, false, "0 0 0").split(" ")[2]) || tm.zOrigin  || 0 : 0,
6435					defaultTransformPerspective = parseFloat(CSSPlugin.defaultTransformPerspective) || 0,
6436					m, i, scaleX, scaleY, rotation, skewX;
6437
6438				tm.svg = !!(t.getBBox && _isSVG(t));
6439				if (tm.svg) {
6440					_parseSVGOrigin(t, _getStyle(t, _transformOriginProp, _cs, false, "50% 50%") + "", tm, t.getAttribute("data-svg-origin"));
6441					_useSVGTransformAttr = CSSPlugin.useSVGTransformAttr || _forceSVGTransformAttr;
6442				}
6443				m = _getMatrix(t);
6444				if (m !== _identity2DMatrix) {
6445
6446					if (m.length === 16) {
6447						//we'll only look at these position-related 6 variables first because if x/y/z all match, it's relatively safe to assume we don't need to re-parse everything which risks losing important rotational information (like rotationX:180 plus rotationY:180 would look the same as rotation:180 - there's no way to know for sure which direction was taken based solely on the matrix3d() values)
6448						var a11 = m[0], a21 = m[1], a31 = m[2], a41 = m[3],
6449							a12 = m[4], a22 = m[5], a32 = m[6], a42 = m[7],
6450							a13 = m[8], a23 = m[9], a33 = m[10],
6451							a14 = m[12], a24 = m[13], a34 = m[14],
6452							a43 = m[11],
6453							angle = Math.atan2(a32, a33),
6454							t1, t2, t3, t4, cos, sin;
6455
6456						//we manually compensate for non-zero z component of transformOrigin to work around bugs in Safari
6457						if (tm.zOrigin) {
6458							a34 = -tm.zOrigin;
6459							a14 = a13*a34-m[12];
6460							a24 = a23*a34-m[13];
6461							a34 = a33*a34+tm.zOrigin-m[14];
6462						}
6463						tm.rotationX = angle * _RAD2DEG;
6464						//rotationX
6465						if (angle) {
6466							cos = Math.cos(-angle);
6467							sin = Math.sin(-angle);
6468							t1 = a12*cos+a13*sin;
6469							t2 = a22*cos+a23*sin;
6470							t3 = a32*cos+a33*sin;
6471							a13 = a12*-sin+a13*cos;
6472							a23 = a22*-sin+a23*cos;
6473							a33 = a32*-sin+a33*cos;
6474							a43 = a42*-sin+a43*cos;
6475							a12 = t1;
6476							a22 = t2;
6477							a32 = t3;
6478						}
6479						//rotationY
6480						angle = Math.atan2(a13, a33);
6481						tm.rotationY = angle * _RAD2DEG;
6482						if (angle) {
6483							cos = Math.cos(-angle);
6484							sin = Math.sin(-angle);
6485							t1 = a11*cos-a13*sin;
6486							t2 = a21*cos-a23*sin;
6487							t3 = a31*cos-a33*sin;
6488							a23 = a21*sin+a23*cos;
6489							a33 = a31*sin+a33*cos;
6490							a43 = a41*sin+a43*cos;
6491							a11 = t1;
6492							a21 = t2;
6493							a31 = t3;
6494						}
6495						//rotationZ
6496						angle = Math.atan2(a21, a11);
6497						tm.rotation = angle * _RAD2DEG;
6498						if (angle) {
6499							cos = Math.cos(-angle);
6500							sin = Math.sin(-angle);
6501							a11 = a11*cos+a12*sin;
6502							t2 = a21*cos+a22*sin;
6503							a22 = a21*-sin+a22*cos;
6504							a32 = a31*-sin+a32*cos;
6505							a21 = t2;
6506						}
6507
6508						if (tm.rotationX && Math.abs(tm.rotationX) + Math.abs(tm.rotation) > 359.9) { //when rotationY is set, it will often be parsed as 180 degrees different than it should be, and rotationX and rotation both being 180 (it looks the same), so we adjust for that here.
6509							tm.rotationX = tm.rotation = 0;
6510							tm.rotationY += 180;
6511						}
6512
6513						tm.scaleX = ((Math.sqrt(a11 * a11 + a21 * a21) * rnd + 0.5) | 0) / rnd;
6514						tm.scaleY = ((Math.sqrt(a22 * a22 + a23 * a23) * rnd + 0.5) | 0) / rnd;
6515						tm.scaleZ = ((Math.sqrt(a32 * a32 + a33 * a33) * rnd + 0.5) | 0) / rnd;
6516						tm.skewX = 0;
6517						tm.perspective = a43 ? 1 / ((a43 < 0) ? -a43 : a43) : 0;
6518						tm.x = a14;
6519						tm.y = a24;
6520						tm.z = a34;
6521						if (tm.svg) {
6522							tm.x -= tm.xOrigin - (tm.xOrigin * a11 - tm.yOrigin * a12);
6523							tm.y -= tm.yOrigin - (tm.yOrigin * a21 - tm.xOrigin * a22);
6524						}
6525
6526					} else if ((!_supports3D || parse || !m.length || tm.x !== m[4] || tm.y !== m[5] || (!tm.rotationX && !tm.rotationY)) && !(tm.x !== undefined && _getStyle(t, "display", cs) === "
6526none")) { //sometimes a 6-element matrix is returned even when we performed 3D transforms, like if rotationX and rotationY are 180. In cases like this, we still need to honor the 3D transforms. If we just rely on the 2D info, it could affect how the data is interpreted, like scaleY might get set to -1 or rotation could get offset by 180 degrees. For example, do a TweenLite.to(element, 1, {css:{rotationX:180, rotationY:180}}) and then later, TweenLite.to(element, 1, {css:{rotationX:0}}) and without this conditional logic in place, it'd jump to a state of being unrotated when the 2nd tween starts. Then again, we need to honor the fact that the user COULD alter the transforms outside of CSSPlugin, like by manually applying new css, so we try to sense that by looking at x and y because if those changed, we know the changes were made outside CSSPlugin and we force a reinterpretation of the matrix values. Also, in Webkit browsers, if the element's "display" is "none", its calculated style value will always return empty, so if we've already recorded the values in the _gsTransform object, we'll just rely on those.
6527						var k = (m.length >= 6),
6528							a = k ? m[0] : 1,
6529							b = m[1] || 0,
6530							c = m[2] || 0,
6531							d = k ? m[3] : 1;
6532						tm.x = m[4] || 0;
6533						tm.y = m[5] || 0;
6534						scaleX = Math.sqrt(a * a + b * b);
6535						scaleY = Math.sqrt(d * d + c * c);
6536						rotation = (a || b) ? Math.atan2(b, a) * _RAD2DEG : tm.rotation || 0; //note: if scaleX is 0, we cannot accurately measure rotation. Same for skewX with a scaleY of 0. Therefore, we default to the previously recorded value (or zero if that doesn't exist).
6537						skewX = (c || d) ? Math.atan2(c, d) * _RAD2DEG + rotation : tm.skewX || 0;
6538						if (Math.abs(skewX) > 90 && Math.abs(skewX) < 270) {
6539							if (invX) {
6540								scaleX *= -1;
6541								skewX += (rotation <= 0) ? 180 : -180;
6542								rotation += (rotation <= 0) ? 180 : -180;
6543							} else {
6544								scaleY *= -1;
6545								skewX += (skewX <= 0) ? 180 : -180;
6546							}
6547						}
6548						tm.scaleX = scaleX;
6549						tm.scaleY = scaleY;
6550						tm.rotation = rotation;
6551						tm.skewX = skewX;
6552						if (_supports3D) {
6553							tm.rotationX = tm.rotationY = tm.z = 0;
6554							tm.perspective = defaultTransformPerspective;
6555							tm.scaleZ = 1;
6556						}
6557						if (tm.svg) {
6558							tm.x -= tm.xOrigin - (tm.xOrigin * a + tm.yOrigin * c);
6559							tm.y -= tm.yOrigin - (tm.xOrigin * b + tm.yOrigin * d);
6560						}
6561					}
6562					tm.zOrigin = zOrigin;
6563					//some browsers have a hard time with very small values like 2.4492935982947064e-16 (notice the "e-" towards the end) and would render the object slightly off. So we round to 0 in these cases. The conditional logic here is faster than calling Math.abs(). Also, browsers tend to render a SLIGHTLY rotated object in a fuzzy way, so we need to snap to exactly 0 when appropriate.
6564					for (i in tm) {
6565						if (tm[i] < min) if (tm[i] > -min) {
6566							tm[i] = 0;
6567						}
6568					}
6569				}
6570				//DEBUG: _log("parsed rotation of " + t.getAttribute("id")+": "+(tm.rotationX)+", "+(tm.rotationY)+", "+(tm.rotation)+", scale: "+tm.scaleX+", "+tm.scaleY+", "+tm.scaleZ+", position: "+tm.x+", "+tm.y+", "+tm.z+", perspective: "+tm.perspective+ ", origin: "+ tm.xOrigin+ ","+ tm.yOrigin);
6571				if (rec) {
6572					t._gsTransform = tm; //record to the object's _gsTransform which we use so that tweens can control individual properties independently (we need all the properties to accurately recompose the matrix in the setRatio() method)
6573					if (tm.svg) { //if we're supposed to apply transforms to the SVG element's "transform" attribute, make sure there aren't any CSS transforms applied or they'll override the attribute ones. Also clear the transform attribute if we're using CSS, just to be clean.
6574						if (_useSVGTransformAttr && t.style[_transformProp]) {
6575							TweenLite.delayedCall(0.001, function(){ //if we apply this right away (before anything has rendered), we risk there being no transforms for a brief moment and it also interferes with adjusting the transformOrigin in a tween with immediateRender:true (it'd try reading the matrix and it wouldn't have the appropriate data in place because we just removed it).
6576								_removeProp(t.style, _transformProp);
6577							});
6578						} else if (!_useSVGTransformAttr && t.getAttribute("transform")) {
6579							TweenLite.delayedCall(0.001, function(){
6580								t.removeAttribute("transform");
6581							});
6582						}
6583					}
6584				}
6585				return tm;
6586			},
6587
6588			//for setting 2D transforms in IE6, IE7, and IE8 (must use a "filter" to emulate the behavior of modern day browser transforms)
6589			_setIETransformRatio = function(v) {
6590				var t = this.data, //refers to the element's _gsTransform object
6591					ang = -t.rotation * _DEG2RAD,
6592					skew = ang + t.skewX * _DEG2RAD,
6593					rnd = 100000,
6594					a = ((Math.cos(ang) * t.scaleX * rnd) | 0) / rnd,
6595					b = ((Math.sin(ang) * t.scaleX * rnd) | 0) / rnd,
6596					c = ((Math.sin(skew) * -t.scaleY * rnd) | 0) / rnd,
6597					d = ((Math.cos(skew) * t.scaleY * rnd) | 0) / rnd,
6598					style = this.t.style,
6599					cs = this.t.currentStyle,
6600					filters, val;
6601				if (!cs) {
6602					return;
6603				}
6604				val = b; //just for swapping the variables an inverting them (reused "val" to avoid creating another variable in memory). IE's filter matrix uses a non-standard matrix configuration (angle goes the opposite way, and b and c are reversed and inverted)
6605				b = -c;
6606				c = -val;
6607				filters = cs.filter;
6608				style.filter = ""; //remove filters so that we can accurately measure offsetWidth/offsetHeight
6609				var w = this.t.offsetWidth,
6610					h = this.t.offsetHeight,
6611					clip = (cs.position !== "absolute"),
6612					m = "progid:DXImageTransform.Microsoft.Matrix(M11=" + a + ", M12=" + b + ", M21=" + c + ", M22=" + d,
6613					ox = t.x + (w * t.xPercent / 100),
6614					oy = t.y + (h * t.yPercent / 100),
6615					dx, dy;
6616
6617				//if transformOrigin is being used, adjust the offset x and y
6618				if (t.ox != null) {
6619					dx = ((t.oxp) ? w * t.ox * 0.01 : t.ox) - w / 2;
6620					dy = ((t.oyp) ? h * t.oy * 0.01 : t.oy) - h / 2;
6621					ox += dx - (dx * a + dy * b);
6622					oy += dy - (dx * c + dy * d);
6623				}
6624
6625				if (!clip) {
6626					m += ", sizingMethod='auto expand')";
6627				} else {
6628					dx = (w / 2);
6629					dy = (h / 2);
6630					//translate to ensure that transformations occur around the correct origin (default is center).
6631					m += ", Dx=" + (dx - (dx * a + dy * b) + ox) + ", Dy=" + (dy - (dx * c + dy * d) + oy) + ")";
6632				}
6633				if (filters.indexOf("DXImageTransform.Microsoft.Matrix(") !== -1) {
6634					style.filter = filters.replace(_ieSetMatrixExp, m);
6635				} else {
6636					style.filter = m + " " + filters; //we must always put the transform/matrix FIRST (before alpha(opacity=xx)) to avoid an IE bug that slices part of the object when rotation is applied with alpha.
6637				}
6638
6639				//at the end or beginning of the tween, if the matrix is normal (1, 0, 0, 1) and opacity is 100 (or doesn't exist), remove the filter to improve browser performance.
6640				if (v === 0 || v === 1) if (a === 1) if (b === 0) if (c === 0) if (d === 1) if (!clip || m.indexOf("Dx=0, Dy=0") !== -1) if (!_opacityExp.test(filters) || parseFloat(RegExp.$1) === 100) if (filters.indexOf("gradient(" && filters.indexOf("Alpha")) === -1) {
6641					style.removeAttribute("filter");
6642				}
6643
6644				//we must set the margins AFTER applying the filter in order to avoid some bugs in IE8 that could (in rare scenarios) cause them to be ignored intermittently (vibration).
6645				if (!clip) {
6646					var mult = (_ieVers < 8) ? 1 : -1, //in Internet Explorer 7 and before, the box model is broken, causing the browser to treat the width/height of the actual rotated filtered image as the width/height of the box itself, but Microsoft corrected that in IE8. We must use a negative offset in IE8 on the right/bottom
6647						marg, prop, dif;
6648					dx = t.ieOffsetX || 0;
6649					dy = t.ieOffsetY || 0;
6650					t.ieOffsetX = Math.round((w - ((a < 0 ? -a : a) * w + (b < 0 ? -b : b) * h)) / 2 + ox);
6651					t.ieOffsetY = Math.round((h - ((d < 0 ? -d : d) * h + (c < 0 ? -c : c) * w)) / 2 + oy);
6652					for (i = 0; i < 4; i++) {
6653						prop = _margins[i];
6654						marg = cs[prop];
6655						//we need to get the current margin in case it is being tweened separately (we want to respect that tween's changes)
6656						val = (marg.indexOf("px") !== -1) ? parseFloat(marg) : _convertToPixels(this.t, prop, parseFloat(marg), marg.replace(_suffixExp, "")) || 0;
6657						if (val !== t[prop]) {
6658							dif = (i < 2) ? -t.ieOffsetX : -t.ieOffsetY; //if another tween is controlling a margin, we cannot only apply the difference in the ieOffsets, so we essentially zero-out the dx and dy here in that case. We record the margin(s) later so that we can keep comparing them, making this code very flexible.
6659						} else {
6660							dif = (i < 2) ? dx - t.ieOffsetX : dy - t.ieOffsetY;
6661						}
6662						style[prop] = (t[prop] = Math.round( val - dif * ((i === 0 || i === 2) ? 1 : mult) )) + "px";
6663					}
6664				}
6665			},
6666
6667			/* translates a super small decimal to a string WITHOUT scientific notation
6668			_safeDecimal = function(n) {
6669				var s = (n < 0 ? -n : n) + "",
6670					a = s.split("e-");
6671				return (n < 0 ? "-0." : "0.") + new Array(parseInt(a[1], 10) || 0).join("0") + a[0].split(".").join("");
6672			},
6673			*/
6674
6675			_setTransformRatio = _internals.set3DTransformRatio = _internals.setTransformRatio = function(v) {
6676				var t = this.data, //refers to the element's _gsTransform object
6677					style = this.t.style,
6678					angle = t.rotation,
6679					rotationX = t.rotationX,
6680					rotationY = t.rotationY,
6681					sx = t.scaleX,
6682					sy = t.scaleY,
6683					sz = t.scaleZ,
6684					x = t.x,
6685					y = t.y,
6686					z = t.z,
6687					isSVG = t.svg,
6688					perspective = t.perspective,
6689					force3D = t.force3D,
6690					a11, a12, a13, a21, a22, a23, a31, a32, a33, a41, a42, a43,
6691					zOrigin, min, cos, sin, t1, t2, transform, comma, zero, skew, rnd;
6692				//check to see if we should render as 2D (and SVGs must use 2D when _useSVGTransformAttr is true)
6693				if (((((v === 1 || v === 0) && force3D === "auto" && (this.tween._totalTime === this.tween._totalDuration || !this.tween._totalTime)) || !force3D) && !z && !perspective && !rotationY && !rotationX) || (_useSVGTransformAttr && isSVG) || !_supports3D) { //on the final render (which could be 0 for a from tween), if there are no 3D aspects, render in 2D to free up memory and improve performance especially on mobile devices. Check the tween's totalTime/totalDuration too in order to make sure it doesn't happen between repeats if it's a repeating tween.
6694
6695					//2D
6696					if (angle || t.skewX || isSVG) {
6697						angle *= _DEG2RAD;
6698						skew = t.skewX * _DEG2RAD;
6699						rnd = 100000;
6700						a11 = Math.cos(angle) * sx;
6701						a21 = Math.sin(angle) * sx;
6702						a12 = Math.sin(angle - skew) * -sy;
6703						a22 = Math.cos(angle - skew) * sy;
6704						if (skew && t.skewType === "simple") { //by default, we compensate skewing on the other axis to make it look more natural, but you can set the skewType to "simple" to use the uncompensated skewing that CSS does
6705							t1 = Math.tan(skew);
6706							t1 = Math.sqrt(1 + t1 * t1);
6707							a12 *= t1;
6708							a22 *= t1;
6709							if (t.skewY) {
6710								a11 *= t1;
6711								a21 *= t1;
6712							}
6713						}
6714						if (isSVG) {
6715							x += t.xOrigin - (t.xOrigin * a11 + t.yOrigin * a12) + t.xOffset;
6716							y += t.yOrigin - (t.xOrigin * a21 + t.yOrigin * a22) + t.yOffset;
6717							if (_useSVGTransformAttr && (t.xPercent || t.yPercent)) { //The SVG spec doesn't support percentage-based translation in the "transform" attribute, so we merge it into the matrix to simulate it.
6718								min = this.t.getBBox();
6719								x += t.xPercent * 0.01 * min.width;
6720								y += t.yPercent * 0.01 * min.height;
6721							}
6722							min = 0.000001;
6723							if (x < min) if (x > -min) {
6724								x = 0;
6725							}
6726							if (y < min) if (y > -min) {
6727								y = 0;
6728							}
6729						}
6730						transform = (((a11 * rnd) | 0) / rnd) + "," + (((a21 * rnd) | 0) / rnd) + "," + (((a12 * rnd) | 0) / rnd) + "," + (((a22 * rnd) | 0) / rnd) + "," + x + "," + y + ")";
6731						if (isSVG && _useSVGTransformAttr) {
6732							this.t.setAttribute("transform", "matrix(" + transform);
6733						} else {
6734							//some browsers have a hard time with very small values like 2.4492935982947064e-16 (notice the "e-" towards the end) and would render the object slightly off. So we round to 5 decimal places.
6735							style[_transformProp] = ((t.xPercent || t.yPercent) ? "translate(" + t.xPercent + "%," + t.yPercent + "%) matrix(" : "matrix(") + transform;
6736						}
6737					} else {
6738						style[_transformProp] = ((t.xPercent || t.yPercent) ? "translate(" + t.xPercent + "%," + t.yPercent + "%) matrix(" : "matrix(") + sx + ",0,0," + sy + "," + x + "," + y + ")";
6739					}
6740					return;
6741
6742				}
6743				if (_isFirefox) { //Firefox has a bug (at least in v25) that causes it to render the transparent part of 32-bit PNG images as black when displayed inside an iframe and the 3D scale is very small and doesn't change sufficiently enough between renders (like if you use a Power4.easeInOut to scale from 0 to 1 where the beginning values only change a tiny amount to begin the tween before accelerating). In this case, we force the scale to be 0.00002 instead which is visually the same but works around the Firefox issue.
6744					min = 0.0001;
6745					if (sx < min && sx > -min) {
6746						sx = sz = 0.00002;
6747					}
6748					if (sy < min && sy > -min) {
6749						sy = sz = 0.00002;
6750					}
6751					if (perspective && !t.z && !t.rotationX && !t.rotationY) { //Firefox has a bug that causes elements to have an odd super-thin, broken/dotted black border on elements that have a perspective set but aren't utilizing 3D space (no rotationX, rotationY, or z).
6752						perspective = 0;
6753					}
6754				}
6755				if (angle || t.skewX) {
6756					angle *= _DEG2RAD;
6757					cos = a11 = Math.cos(angle);
6758					sin = a21 = Math.sin(angle);
6759					if (t.skewX) {
6760						angle -= t.skewX * _DEG2RAD;
6761						cos = Math.cos(angle);
6762						sin = Math.sin(angle);
6763						if (t.skewType === "simple") { //by default, we compensate skewing on the other axis to make it look more natural, but you can set the skewType to "simple" to use the uncompensated skewing that CSS does
6764							t1 = Math.tan(t.skewX * _DEG2RAD);
6765							t1 = Math.sqrt(1 + t1 * t1);
6766							cos *= t1;
6767							sin *= t1;
6768							if (t.skewY) {
6769								a11 *= t1;
6770								a21 *= t1;
6771							}
6772						}
6773					}
6774					a12 = -sin;
6775					a22 = cos;
6776
6777				} else if (!rotationY && !rotationX && sz === 1 && !perspective && !isSVG) { //if we're only translating and/or 2D scaling, this is faster...
6778					style[_transformProp] = ((t.xPercent || t.yPercent) ? "translate(" + t.xPercent + "%," + t.yPercent + "%) translate3d(" : "translate3d(") + x + "px," + y + "px," + z +"px)" + ((sx !== 1 || sy !== 1) ? " scale(" + sx + "," + sy + ")" : "");
6779					return;
6780				} else {
6781					a11 = a22 = 1;
6782					a12 = a21 = 0;
6783				}
6784				// KEY  INDEX   AFFECTS
6785				// a11  0       rotation, rotationY, scaleX
6786				// a21  1       rotation, rotationY, scaleX
6787				// a31  2       rotationY, scaleX
6788				// a41  3       rotationY, scaleX
6789				// a12  4       rotation, skewX, rotationX, scaleY
6790				// a22  5       rotation, skewX, rotationX, scaleY
6791				// a32  6       rotationX, scaleY
6792				// a42  7       rotationX, scaleY
6793				// a13  8       rotationY, rotationX, scaleZ
6794				// a23  9       rotationY, rotationX, scaleZ
6795				// a33  10      rotationY, rotationX, scaleZ
6796				// a43  11      rotationY, rotationX, perspective, scaleZ
6797				// a14  12      x, zOrigin, svgOrigin
6798				// a24  13      y, zOrigin, svgOrigin
6799				// a34  14      z, zOrigin
6800				// a44  15
6801				// rotation: Math.atan2(a21, a11)
6802				// rotationY: Math.atan2(a13, a33) (or Math.atan2(a13, a11))
6803				// rotationX: Math.atan2(a32, a33)
6804				a33 = 1;
6805				a13 = a23 = a31 = a32 = a41 = a42 = 0;
6806				a43 = (perspective) ? -1 / perspective : 0;
6807				zOrigin = t.zOrigin;
6808				min = 0.000001; //threshold below which browsers use scientific notation which won't work.
6809				comma = ",";
6810				zero = "0";
6811				angle = rotationY * _DEG2RAD;
6812				if (angle) {
6813					cos = Math.cos(angle);
6814					sin = Math.sin(angle);
6815					a31 = -sin;
6816					a41 = a43*-sin;
6817					a13 = a11*sin;
6818					a23 = a21*sin;
6819					a33 = cos;
6820					a43 *= cos;
6821					a11 *= cos;
6822					a21 *= cos;
6823				}
6824				angle = rotationX * _DEG2RAD;
6825				if (angle) {
6826					cos = Math.cos(angle);
6827					sin = Math.sin(angle);
6828					t1 = a12*cos+a13*sin;
6829					t2 = a22*cos+a23*sin;
6830					a32 = a33*sin;
6831					a42 = a43*sin;
6832					a13 = a12*-sin+a13*cos;
6833					a23 = a22*-sin+a23*cos;
6834					a33 = a33*cos;
6835					a43 = a43*cos;
6836					a12 = t1;
6837					a22 = t2;
6838				}
6839				if (sz !== 1) {
6840					a13*=sz;
6841					a23*=sz;
6842					a33*=sz;
6843					a43*=sz;
6844				}
6845				if (sy !== 1) {
6846					a12*=sy;
6847					a22*=sy;
6848					a32*=sy;
6849					a42*=sy;
6850				}
6851				if (sx !== 1) {
6852					a11*=sx;
6853					a21*=sx;
6854					a31*=sx;
6855					a41*=sx;
6856				}
6857
6858				if (zOrigin || isSVG) {
6859					if (zOrigin) {
6860						x += a13*-zOrigin;
6861						y += a23*-zOrigin;
6862						z += a33*-zOrigin+zOrigin;
6863					}
6864					if (isSVG) { //due to bugs in some browsers, we need to manage the transform-origin of SVG manually
6865						x += t.xOrigin - (t.xOrigin * a11 + t.yOrigin * a12) + t.xOffset;
6866						y += t.yOrigin - (t.xOrigin * a21 + t.yOrigin * a22) + t.yOffset;
6867					}
6868					if (x < min && x > -min) {
6869						x = zero;
6870					}
6871					if (y < min && y > -min) {
6872						y = zero;
6873					}
6874					if (z < min && z > -min) {
6875						z = 0; //don't use string because we calculate perspective later and need the number.
6876					}
6877				}
6878
6879				//optimized way of concatenating all the values into a string. If we do it all in one shot, it's slower because of the way browsers have to create temp strings and the way it affects memory. If we do it piece-by-piece with +=, it's a bit slower too. We found that doing it in these sized chunks works best overall:
6880				transform = ((t.xPercent || t.yPercent) ? "translate(" + t.xPercent + "%," + t.yPercent + "%) matrix3d(" : "matrix3d(");
6881				transform += ((a11 < min && a11 > -min) ? zero : a11) + comma + ((a21 < min && a21 > -min) ? zero : a21) + comma + ((a31 < min && a31 > -min) ? zero : a31);
6882				transform += comma + ((a41 < min && a41 > -min) ? zero : a41) + comma + ((a12 < min && a12 > -min) ? zero : a12) + comma + ((a22 < min && a22 > -min) ? zero : a22);
6883				if (rotationX || rotationY) { //performance optimization (often there's no rotationX or rotationY, so we can skip these calculations)
6884					transform += comma + ((a32 < min && a32 > -min) ? zero : a32) + comma + ((a42 < min && a42 > -min) ? zero : a42) + comma + ((a13 < min && a13 > -min) ? zero : a13);
6885					transform += comma + ((a23 < min && a23 > -min) ? zero : a23) + comma + ((a33 < min && a33 > -min) ? zero : a33) + comma + ((a43 < min && a43 > -min) ? zero : a43) + comma;
6886				} else {
6887					transform += ",0,0,0,0,1,0,";
6888				}
6889				transform += x + comma + y + comma + z + comma + (perspective ? (1 + (-z / perspective)) : 1) + ")";
6890
6891				style[_transformProp] = transform;
6892			};
6893
6894		p = Transform.prototype;
6895		p.x = p.y = p.z = p.skewX = p.skewY = p.rotation = p.rotationX = p.rotationY = p.zOrigin = p.xPercent = p.yPercent = p.xOffset = p.yOffset = 0;
6896		p.scaleX = p.scaleY = p.scaleZ = 1;
6897
6898		_registerComplexSpecialProp("transform,scale,scaleX,scaleY,scaleZ,x,y,z,rotation,rotationX,rotationY,rotationZ,skewX,skewY,shortRotation,shortRotationX,shortRotationY,shortRotationZ,transformOrigin,svgOrigin,transformPerspective,directionalRotation,parseTransform,force3D,skewType,xPercent,yPercent,smoothOrigin", {parser:function(t, e, p, cssp, pt, plugin, vars) {
6899			if (cssp._lastParsedTransform === vars) { return pt; } //only need to parse the transform once, and only if the browser supports it.
6900			cssp._lastParsedTransform = vars;
6901			var originalGSTransform = t._gsTransform,
6902				style = t.style,
6903				min = 0.000001,
6904				i = _transformProps.length,
6905				v = vars,
6906				endRotations = {},
6907				transformOriginString = "transformOrigin",
6908				m1, m2, skewY, copy, orig, has3D, hasChange, dr, x, y;
6909			if (vars.display) { //if the user is setting display during this tween, it may not be instantiated yet but we must force it here in order to get accurate readings. If display is "none", some browsers refuse to report the transform properties correctly.
6910				copy = _getStyle(t, "display");
6911				style.display = "block";
6912				m1 = _getTransform(t, _cs, true, vars.parseTransform);
6913				style.display = copy;
6914			} else {
6915				m1 = _getTransform(t, _cs, true, vars.parseTransform);
6916			}
6917			cssp._transform = m1;
6918			if (typeof(v.transform) === "string" && _transformProp) { //for values like transform:"rotate(60deg) scale(0.5, 0.8)"
6919				copy = _tempDiv.style; //don't use the original target because it might be SVG in which case some browsers don't report computed style correctly.
6920				copy[_transformProp] = v.transform;
6921				copy.display = "block"; //if display is "none", the browser often refuses to report the transform properties correctly.
6922				copy.position = "absolute";
6923				_doc.body.appendChild(_tempDiv);
6924				m2 = _getTransform(_tempDiv, null, false);
6925				_doc.body.removeChild(_tempDiv);
6926				if (!m2.perspective) {
6927					m2.perspective = m1.perspective; //tweening to no perspective gives very unintuitive results - just keep the same perspective in that case.
6928				}
6929				if (v.xPercent != null) {
6930					m2.xPercent = _parseVal(v.xPercent, m1.xPercent);
6931				}
6932				if (v.yPercent != null) {
6933					m2.yPercent = _parseVal(v.yPercent, m1.yPercent);
6934				}
6935			} else if (typeof(v) === "object") { //for values like scaleX, scaleY, rotation, x, y, skewX, and skewY or transform:{...} (object)
6936				m2 = {scaleX:_parseVal((v.scaleX != null) ? v.scaleX : v.scale, m1.scaleX),
6937					scaleY:_parseVal((v.scaleY != null) ? v.scaleY : v.scale, m1.scaleY),
6938					scaleZ:_parseVal(v.scaleZ, m1.scaleZ),
6939					x:_parseVal(v.x, m1.x),
6940					y:_parseVal(v.y, m1.y),
6941					z:_parseVal(v.z, m1.z),
6942					xPercent:_parseVal(v.xPercent, m1.xPercent),
6943					yPercent:_parseVal(v.yPercent, m1.yPercent),
6944					perspective:_parseVal(v.transformPerspective, m1.perspective)};
6945				dr = v.directionalRotation;
6946				if (dr != null) {
6947					if (typeof(dr) === "object") {
6948						for (copy in dr) {
6949							v[copy] = dr[copy];
6950						}
6951					} else {
6952						v.rotation = dr;
6953					}
6954				}
6955				if (typeof(v.x) === "string" && v.x.indexOf("%") !== -1) {
6956					m2.x = 0;
6957					m2.xPercent = _parseVal(v.x, m1.xPercent);
6958				}
6959				if (typeof(v.y) === "string" && v.y.indexOf("%") !== -1) {
6960					m2.y = 0;
6961					m2.yPercent = _parseVal(v.y, m1.yPercent);
6962				}
6963
6964				m2.rotation = _parseAngle(("rotation" in v) ? v.rotation : ("shortRotation" in v) ? v.shortRotation + "_short" : ("rotationZ" in v) ? v.rotationZ : m1.rotation, m1.rotation, "rotation", endRotations);
6965				if (_supports3D) {
6966					m2.rotationX = _parseAngle(("rotationX" in v) ? v.rotationX : ("shortRotationX" in v) ? v.shortRotationX + "_short" : m1.rotationX || 0, m1.rotationX, "rotationX", endRotations);
6967					m2.rotationY = _parseAngle(("rotationY" in v) ? v.rotationY : ("shortRotationY" in v) ? v.shortRotationY + "_short" : m1.rotationY || 0, m1.rotationY, "rotationY", endRotations);
6968				}
6969				m2.skewX = (v.skewX == null) ? m1.skewX : _parseAngle(v.skewX, m1.skewX);
6970
6971				//note: for performance reasons, we combine all skewing into the skewX and rotation values, ignoring skewY but we must still record it so that we can discern how much of the overall skew is attributed to skewX vs. skewY. Otherwise, if the skewY would always act relative (tween skewY to 10deg, for example, multiple times and if we always combine things into skewX, we can't remember that skewY was 10 from last time). Remember, a skewY of 10 degrees looks the same as a rotation of 10 degrees plus a skewX of -10 degrees.
6972				m2.skewY = (v.skewY == null) ? m1.skewY : _parseAngle(v.skewY, m1.skewY);
6973				if ((skewY = m2.skewY - m1.skewY)) {
6974					m2.skewX += skewY;
6975					m2.rotation += skewY;
6976				}
6977			}
6978			if (_supports3D && v.force3D != null) {
6979				m1.force3D = v.force3D;
6980				hasChange = true;
6981			}
6982
6983			m1.skewType = v.skewType || m1.skewType || CSSPlugin.defaultSkewType;
6984
6985			has3D = (m1.force3D || m1.z || m1.rotationX || m1.rotationY || m2.z || m2.rotationX || m2.rotationY || m2.perspective);
6986			if (!has3D && v.scale != null) {
6987				m2.scaleZ = 1; //no need to tween scaleZ.
6988			}
6989
6990			while (--i > -1) {
6991				p = _transformProps[i];
6992				orig = m2[p] - m1[p];
6993				if (orig > min || orig < -min || v[p] != null || _forcePT[p] != null) {
6994					hasChange = true;
6995					pt = new CSSPropTween(m1, p, m1[p], orig, pt);
6996					if (p in endRotations) {
6997						pt.e = endRotations[p]; //directional rotations typically have compensated values during the tween, but we need to make sure they end at exactly what the user requested
6998					}
6999					pt.xs0 = 0; //ensures the value stays numeric in setRatio()
7000					pt.plugin = plugin;
7001					cssp._overwriteProps.push(pt.n);
7002				}
7003			}
7004
7005			orig = v.transformOrigin;
7006			if (m1.svg && (orig || v.svgOrigin)) {
7007				x = m1.xOffset; //when we change the origin, in order to prevent things from jumping we adjust the x/y so we must record those here so that we can create PropTweens for them and flip them at the same time as the origin
7008				y = m1.yOffset;
7009				_parseSVGOrigin(t, _parsePosition(orig), m2, v.svgOrigin, v.smoothOrigin);
7010				pt = _addNonTweeningNumericPT(m1, "xOrigin", (originalGSTransform ? m1 : m2).xOrigin, m2.xOrigin, pt, transformOriginString); //note: if there wasn't a transformOrigin defined yet, just start with the destination one; it's wasteful otherwise, and it causes problems with fromTo() tweens. For example, TweenLite.to("#wheel", 3, {rotation:180, transformOrigin:"50% 50%", delay:1}); TweenLite.fromTo("#wheel", 3, {scale:0.5, transformOrigin:"50% 50%"}, {scale:1, delay:2}); would cause a jump when the from values revert at the beginning of the 2nd tween.
7011				pt = _addNonTweeningNumericPT(m1, "yOrigin", (originalGSTransform ? m1 : m2).yOrigin, m2.yOrigin, pt, transformOriginString);
7012				if (x !== m1.xOffset || y !== m1.yOffset) {
7013					pt = _addNonTweeningNumericPT(m1, "xOffset", (originalGSTransform ? x : m1.xOffset), m1.xOffset, pt, transformOriginString);
7014					pt = _addNonTweeningNumericPT(m1, "yOffset", (originalGSTransform ? y : m1.yOffset), m1.yOffset, pt, transformOriginString);
7015				}
7016				orig = _useSVGTransformAttr ? null : "0px 0px"; //certain browsers (like firefox) completely botch transform-origin, so we must remove it to prevent it from contaminating transforms. We manage it ourselves with xOrigin and yOrigin
7017			}
7018			if (orig || (_supports3D && has3D && m1.zOrigin)) { //if anything 3D is happening and there's a transformOrigin with a z component that's non-zero, we must ensure that the transformOrigin's z-component is set to 0 so that we can manually do those calculations to get around Safari bugs. Even if the user didn't specifically define a "transformOrigin" in this particular tween (maybe they did it via css directly).
7019				if (_transformProp) {
7020					hasChange = true;
7021					p = _transformOriginProp;
7022					orig = (orig || _getStyle(t, p, _cs, false, "50% 50%")) + ""; //cast as string to avoid errors
7023					pt = new CSSPropTween(style, p, 0, 0, pt, -1, transformOriginString);
7024					pt.b = style[p];
7025					pt.plugin = plugin;
7026					if (_supports3D) {
7027						copy = m1.zOrigin;
7028						orig = orig.split(" ");
7029						m1.zOrigin = ((orig.length > 2 && !(copy !== 0 && orig[2] === "0px")) ? parseFloat(orig[2]) : copy) || 0; //Safari doesn't handle the z part of transformOrigin correctly, so we'll manually handle it in the _set3DTransformRatio() method.
7030						pt.xs0 = pt.e = orig[0] + " " + (orig[1] || "50%") + " 0px"; //we must define a z value of 0px specifically otherwise iOS 5 Safari will stick with the old one (if one was defined)!
7031						pt = new CSSPropTween(m1, "zOrigin", 0, 0, pt, -1, pt.n); //we must create a CSSPropTween for the _gsTransform.zOrigin so that it gets reset properly at the beginning if the tween runs backward (as opposed to just setting m1.zOrigin here)
7032						pt.b = copy;
7033						pt.xs0 = pt.e = m1.zOrigin;
7034					} else {
7035						pt.xs0 = pt.e = orig;
7036					}
7037
7038					//for older versions of IE (6-8), we need to manually calculate things inside the setRatio() function. We record origin x and y (ox and oy) and whether or not the values are percentages (oxp and oyp).
7039				} else {
7040					_parsePosition(orig + "", m1);
7041				}
7042			}
7043			if (hasChange) {
7044				cssp._transformType = (!(m1.svg && _useSVGTransformAttr) && (has3D || this._transformType === 3)) ? 3 : 2; //quicker than calling cssp._enableTransforms();
7045			}
7046			return pt;
7047		}, prefix:true});
7048
7049		_registerComplexSpecialProp("boxShadow", {defaultValue:"0px 0px 0px 0px #999", prefix:true, color:true, multi:true, keyword:"inset"});
7050
7051		_registerComplexSpecialProp("borderRadius", {defaultValue:"0px", parser:function(t, e, p, cssp, pt, plugin) {
7052			e = this.format(e);
7053			var props = ["borderTopLeftRadius","borderTopRightRadius","borderBottomRightRadius","borderBottomLeftRadius"],
7054				style = t.style,
7055				ea1, i, es2, bs2, bs, es, bn, en, w, h, esfx, bsfx, rel, hn, vn, em;
7056			w = parseFloat(t.offsetWidth);
7057			h = parseFloat(t.offsetHeight);
7058			ea1 = e.split(" ");
7059			for (i = 0; i < props.length; i++) { //if we're dealing with percentages, we must convert things separately for the horizontal and vertical axis!
7060				if (this.p.indexOf("border")) { //older browsers used a prefix
7061					props[i] = _checkPropPrefix(props[i]);
7062				}
7063				bs = bs2 = _getStyle(t, props[i], _cs, false, "0px");
7064				if (bs.indexOf(" ") !== -1) {
7065					bs2 = bs.split(" ");
7066					bs = bs2[0];
7067					bs2 = bs2[1];
7068				}
7069				es = es2 = ea1[i];
7070				bn = parseFloat(bs);
7071				bsfx = bs.substr((bn + "").length);
7072				rel = (es.charAt(1) === "=");
7073				if (rel) {
7074					en = parseInt(es.charAt(0)+"1", 10);
7075					es = es.substr(2);
7076					en *= parseFloat(es);
7077					esfx = es.substr((en + "").length - (en < 0 ? 1 : 0)) || "";
7078				} else {
7079					en = parseFloat(es);
7080					esfx = es.substr((en + "").length);
7081				}
7082				if (esfx === "") {
7083					esfx = _suffixMap[p] || bsfx;
7084				}
7085				if (esfx !== bsfx) {
7086					hn = _convertToPixels(t, "borderLeft", bn, bsfx); //horizontal number (we use a bogus "borderLeft" property just because the _convertToPixels() method searches for the keywords "Left", "Right", "Top", and "Bottom" to determine of it's a horizontal or vertical property, and we need "border" in the name so that it knows it should measure relative to the element itself, not its parent.
7087					vn = _convertToPixels(t, "borderTop", bn, bsfx); //vertical number
7088					if (esfx === "%") {
7089						bs = (hn / w * 100) + "%";
7090						bs2 = (vn / h * 100) + "%";
7091					} else if (esfx === "em") {
7092						em = _convertToPixels(t, "borderLeft", 1, "em");
7093						bs = (hn / em) + "em";
7094						bs2 = (vn / em) + "em";
7095					} else {
7096						bs = hn + "px";
7097						bs2 = vn + "px";
7098					}
7099					if (rel) {
7100						es = (parseFloat(bs) + en) + esfx;
7101						es2 = (parseFloat(bs2) + en) + esfx;
7102					}
7103				}
7104				pt = _parseComplex(style, props[i], bs + " " + bs2, es + " " + es2, false, "0px", pt);
7105			}
7106			return pt;
7107		}, prefix:true, formatter:_getFormatter("0px 0px 0px 0px", false, true)});
7108		_registerComplexSpecialProp("backgroundPosition", {defaultValue:"0 0", parser:function(t, e, p, cssp, pt, plugin) {
7109			var bp = "background-position",
7110				cs = (_cs || _getComputedStyle(t, null)),
7111				bs = this.format( ((cs) ? _ieVers ? cs.getPropertyValue(bp + "-x") + " " + cs.getPropertyValue(bp + "-y") : cs.getPropertyValue(bp) : t.currentStyle.backgroundPositionX + " " + t.currentStyle.backgroundPositionY) || "0 0"), //Internet Explorer doesn't report background-position correctly - we must query background-position-x and background-position-y and combine them (even in IE10). Before IE9, we must do the same with the currentStyle object and use camelCase
7112				es = this.format(e),
7113				ba, ea, i, pct, overlap, src;
7114			if ((bs.indexOf("%") !== -1) !== (es.indexOf("%") !== -1)) {
7115				src = _getStyle(t, "backgroundImage").replace(_urlExp, "");
7116				if (src && src !== "none") {
7117					ba = bs.split(" ");
7118					ea = es.split(" ");
7119					_tempImg.setAttribute("src", src); //set the temp IMG's src to the background-image so that we can measure its width/height
7120					i = 2;
7121					while (--i > -1) {
7122						bs = ba[i];
7123						pct = (bs.indexOf("%") !== -1);
7124						if (pct !== (ea[i].indexOf("%") !== -1)) {
7125							overlap = (i === 0) ? t.offsetWidth - _tempImg.width : t.offsetHeight - _tempImg.height;
7126							ba[i] = pct ? (parseFloat(bs) / 100 * overlap) + "px" : (parseFloat(bs) / overlap * 100) + "%";
7127						}
7128					}
7129					bs = ba.join(" ");
7130				}
7131			}
7132			return this.parseComplex(t.style, bs, es, pt, plugin);
7133		}, formatter:_parsePosition});
7134		_registerComplexSpecialProp("backgroundSize", {defaultValue:"0 0", formatter:_parsePosition});
7135		_registerComplexSpecialProp("perspective", {defaultValue:"0px", prefix:true});
7136		_registerComplexSpecialProp("perspectiveOrigin", {defaultValue:"50% 50%", prefix:true});
7137		_registerComplexSpecialProp("transformStyle", {prefix:true});
7138		_registerComplexSpecialProp("backfaceVisibility", {prefix:true});
7139		_registerComplexSpecialProp("userSelect", {prefix:true});
7140		_registerComplexSpecialProp("margin", {parser:_getEdgeParser("marginTop,marginRight,marginBottom,marginLeft")});
7141		_registerComplexSpecialProp("padding", {parser:_getEdgeParser("paddingTop,paddingRight,paddingBottom,paddingLeft")});
7142		_registerComplexSpecialProp("clip", {defaultValue:"rect(0px,0px,0px,0px)", parser:function(t, e, p, cssp, pt, plugin){
7143			var b, cs, delim;
7144			if (_ieVers < 9) { //IE8 and earlier don't report a "clip" value in the currentStyle - instead, the values are split apart into clipTop, clipRight, clipBottom, and clipLeft. Also, in IE7 and earlier, the values inside rect() are space-delimited, not comma-delimited.
7145				cs = t.currentStyle;
7146				delim = _ieVers < 8 ? " " : ",";
7147				b = "rect(" + cs.clipTop + delim + cs.clipRight + delim + cs.clipBottom + delim + cs.clipLeft + ")";
7148				e = this.format(e).split(",").join(delim);
7149			} else {
7150				b = this.format(_getStyle(t, this.p, _cs, false, this.dflt));
7151				e = this.format(e);
7152			}
7153			return this.parseComplex(t.style, b, e, pt, plugin);
7154		}});
7155		_registerComplexSpecialProp("textShadow", {defaultValue:"0px 0px 0px #999", color:true, multi:true});
7156		_registerComplexSpecialProp("autoRound,strictUnits", {parser:function(t, e, p, cssp, pt) {return pt;}}); //just so that we can ignore these properties (not tween them)
7157		_registerComplexSpecialProp("border", {defaultValue:"0px solid #000", parser:function(t, e, p, cssp, pt, plugin) {
7158				return this.parseComplex(t.style, this.format(_getStyle(t, "borderTopWidth", _cs, false, "0px") + " " + _getStyle(t, "borderTopStyle", _cs, false, "solid") + " " + _getStyle(t, "borderTopColor", _cs, false, "#000")), this.format(e), pt, plugin);
7159			}, color:true, formatter:function(v) {
7160				var a = v.split(" ");
7161				return a[0] + " " + (a[1] || "solid") + " " + (v.match(_colorExp) || ["#000"])[0];
7162			}});
7163		_registerComplexSpecialProp("borderWidth", {parser:_getEdgeParser("borderTopWidth,borderRightWidth,borderBottomWidth,borderLeftWidth")}); //Firefox doesn't pick up on borderWidth set in style sheets (only inline).
7164		_registerComplexSpecialProp("float,cssFloat,styleFloat", {parser:function(t, e, p, cssp, pt, plugin) {
7165			var s = t.style,
7166				prop = ("cssFloat" in s) ? "cssFloat" : "styleFloat";
7167			return new CSSPropTween(s, prop, 0, 0, pt, -1, p, false, 0, s[prop], e);
7168		}});
7169
7170		//opacity-related
7171		var _setIEOpacityRatio = function(v) {
7172				var t = this.t, //refers to the element's style property
7173					filters = t.filter || _getStyle(this.data, "filter") || "",
7174					val = (this.s + this.c * v) | 0,
7175					skip;
7176				if (val === 100) { //for older versions of IE that need to use a filter to apply opacity, we should remove the filter if opacity hits 1 in order to improve performance, but make sure there isn't a transform (matrix) or gradient in the filters.
7177					if (filters.indexOf("atrix(") === -1 && filters.indexOf("radient(") === -1 && filters.indexOf("oader(") === -1) {
7178						t.removeAttribute("filter");
7179						skip = (!_getStyle(this.data, "filter")); //if a class is applied that has an alpha filter, it will take effect (we don't want that), so re-apply our alpha filter in that case. We must first remove it and then check.
7180					} else {
7181						t.filter = filters.replace(_alphaFilterExp, "");
7182						skip = true;
7183					}
7184				}
7185				if (!skip) {
7186					if (this.xn1) {
7187						t.filter = filters = filters || ("alpha(opacity=" + val + ")"); //works around bug in IE7/8 that prevents changes to "visibility" from being applied properly if the filter is changed to a different alpha on the same frame.
7188					}
7189					if (filters.indexOf("pacity") === -1) { //only used if browser doesn't support the standard opacity style property (IE 7 and 8). We omit the "O" to avoid case-sensitivity issues
7190						if (val !== 0 || !this.xn1) { //bugs in IE7/8 won't render the filter properly if opacity is ADDED on the same frame/render as "visibility" changes (this.xn1 is 1 if this tween is an "autoAlpha" tween)
7191							t.filter = filters + " alpha(opacity=" + val + ")"; //we round the value because otherwise, bugs in IE7/8 can prevent "visibility" changes from being applied properly.
7192						}
7193					} else {
7194						t.filter = filters.replace(_opacityExp, "opacity=" + val);
7195					}
7196				}
7197			};
7198		_registerComplexSpecialProp("opacity,alpha,autoAlpha", {defaultValue:"1", parser:function(t, e, p, cssp, pt, plugin) {
7199			var b = parseFloat(_getStyle(t, "opacity", _cs, false, "1")),
7200				style = t.style,
7201				isAutoAlpha = (p === "autoAlpha");
7202			if (typeof(e) === "string" && e.charAt(1) === "=") {
7203				e = ((e.charAt(0) === "-") ? -1 : 1) * parseFloat(e.substr(2)) + b;
7204			}
7205			if (isAutoAlpha && b === 1 && _getStyle(t, "visibility", _cs) === "hidden" && e !== 0) { //if visibility is initially set to "hidden", we should interpret that as intent to make opacity 0 (a convenience)
7206				b = 0;
7207			}
7208			if (_supportsOpacity) {
7209				pt = new CSSPropTween(style, "opacity", b, e - b, pt);
7210			} else {
7211				pt = new CSSPropTween(style, "opacity", b * 100, (e - b) * 100, pt);
7212				pt.xn1 = isAutoAlpha ? 1 : 0; //we need to record whether or not this is an autoAlpha so that in the setRatio(), we know to duplicate the setting of the alpha in order to work around a bug in IE7 and IE8 that prevents changes to "visibility" from taking effect if the filter is changed to a different alpha(opacity) at the same time. Setting it to the SAME value first, then the new value works around the IE7/8 bug.
7213				style.zoom = 1; //helps correct an IE issue.
7214				pt.type = 2;
7215				pt.b = "alpha(opacity=" + pt.s + ")";
7216				pt.e = "alpha(opacity=" + (pt.s + pt.c) + ")";
7217				pt.data = t;
7218				pt.plugin = plugin;
7219				pt.setRatio = _setIEOpacityRatio;
7220			}
7221			if (isAutoAlpha) { //we have to create the "visibility" PropTween after the opacity one in the linked list so that they run in the order that works properly in IE8 and earlier
7222				pt = new CSSPropTween(style, "visibility", 0, 0, pt, -1, null, false, 0, ((b !== 0) ? "inherit" : "hidden"), ((e === 0) ? "hidden" : "inherit"));
7223				pt.xs0 = "inherit";
7224				cssp._overwriteProps.push(pt.n);
7225				cssp._overwriteProps.push(p);
7226			}
7227			return pt;
7228		}});
7229
7230
7231		var _removeProp = function(s, p) {
7232				if (p) {
7233					if (s.removeProperty) {
7234						if (p.substr(0,2) === "ms" || p.substr(0,6) === "webkit") { //Microsoft and some Webkit browsers don't conform to the standard of capitalizing the first prefix character, so we adjust so that when we prefix the caps with a dash, it's correct (otherwise it'd be "ms-transform" instead of "-ms-transform" for IE9, for example)
7235							p = "-" + p;
7236						}
7237						s.removeProperty(p.replace(_capsExp, "-$1").toLowerCase());
7238					} else { //note: old versions of IE use "removeAttribute()" instead of "removeProperty()"
7239						s.removeAttribute(p);
7240					}
7241				}
7242			},
7243			_setClassNameRatio = function(v) {
7244				this.t._gsClassPT = this;
7245				if (v === 1 || v === 0) {
7246					this.t.setAttribute("class", (v === 0) ? this.b : this.e);
7247					var mpt = this.data, //first MiniPropTween
7248						s = this.t.style;
7249					while (mpt) {
7250						if (!mpt.v) {
7251							_removeProp(s, mpt.p);
7252						} else {
7253							s[mpt.p] = mpt.v;
7254						}
7255						mpt = mpt._next;
7256					}
7257					if (v === 1 && this.t._gsClassPT === this) {
7258						this.t._gsClassPT = null;
7259					}
7260				} else if (this.t.getAttribute("class") !== this.e) {
7261					this.t.setAttribute("class", this.e);
7262				}
7263			};
7264		_registerComplexSpecialProp("className", {parser:function(t, e, p, cssp, pt, plugin, vars) {
7265			var b = t.getAttribute("class") || "", //don't use t.className because it doesn't work consistently on SVG elements; getAttribute("class") and setAttribute("class", value") is more reliable.
7266				cssText = t.style.cssText,
7267				difData, bs, cnpt, cnptLookup, mpt;
7268			pt = cssp._classNamePT = new CSSPropTween(t, p, 0, 0, pt, 2);
7269			pt.setRatio = _setClassNameRatio;
7270			pt.pr = -11;
7271			_hasPriority = true;
7272			pt.b = b;
7273			bs = _getAllStyles(t, _cs);
7274			//if there's a className tween already operating on the target, force it to its end so that the necessary inline styles are removed and the class name is applied before we determine the end state (we don't want inline styles interfer
7274ing that were there just for class-specific values)
7275			cnpt = t._gsClassPT;
7276			if (cnpt) {
7277				cnptLookup = {};
7278				mpt = cnpt.data; //first MiniPropTween which stores the inline styles - we need to force these so that the inline styles don't contaminate things. Otherwise, there's a small chance that a tween could start and the inline values match the destination values and they never get cleaned.
7279				while (mpt) {
7280					cnptLookup[mpt.p] = 1;
7281					mpt = mpt._next;
7282				}
7283				cnpt.setRatio(1);
7284			}
7285			t._gsClassPT = pt;
7286			pt.e = (e.charAt(1) !== "=") ? e : b.replace(new RegExp("\\s*\\b" + e.substr(2) + "\\b"), "") + ((e.charAt(0) === "+") ? " " + e.substr(2) : "");
7287			t.setAttribute("class", pt.e);
7288			difData = _cssDif(t, bs, _getAllStyles(t), vars, cnptLookup);
7289			t.setAttribute("class", b);
7290			pt.data = difData.firstMPT;
7291			t.style.cssText = cssText; //we recorded cssText before we swapped classes and ran _getAllStyles() because in cases when a className tween is overwritten, we remove all the related tweening properties from that class change (otherwise class-specific stuff can't override properties we've directly set on the target's style object due to specificity).
7292			pt = pt.xfirst = cssp.parse(t, difData.difs, pt, plugin); //we record the CSSPropTween as the xfirst so that we can handle overwriting propertly (if "className" gets overwritten, we must kill all the properties associated with the className part of the tween, so we can loop through from xfirst to the pt itself)
7293			return pt;
7294		}});
7295
7296
7297		var _setClearPropsRatio = function(v) {
7298			if (v === 1 || v === 0) if (this.data._totalTime === this.data._totalDuration && this.data.data !== "isFromStart") { //this.data refers to the tween. Only clear at the END of the tween (remember, from() tweens make the ratio go from 1 to 0, so we can't just check that and if the tween is the zero-duration one that's created internally to render the starting values in a from() tween, ignore that because otherwise, for example, from(...{height:100, clearProps:"height", delay:1}) would wipe the height at the beginning of the tween and after 1 second, it'd kick back in).
7299				var s = this.t.style,
7300					transformParse = _specialProps.transform.parse,
7301					a, p, i, clearTransform, transform;
7302				if (this.e === "all") {
7303					s.cssText = "";
7304					clearTransform = true;
7305				} else {
7306					a = this.e.split(" ").join("").split(",");
7307					i = a.length;
7308					while (--i > -1) {
7309						p = a[i];
7310						if (_specialProps[p]) {
7311							if (_specialProps[p].parse === transformParse) {
7312								clearTransform = true;
7313							} else {
7314								p = (p === "transformOrigin") ? _transformOriginProp : _specialProps[p].p; //ensures that special properties use the proper browser-specific property name, like "scaleX" might be "-webkit-transform" or "boxShadow" might be "-moz-box-shadow"
7315							}
7316						}
7317						_removeProp(s, p);
7318					}
7319				}
7320				if (clearTransform) {
7321					_removeProp(s, _transformProp);
7322					transform = this.t._gsTransform;
7323					if (transform) {
7324						if (transform.svg) {
7325							this.t.removeAttribute("data-svg-origin");
7326						}
7327						delete this.t._gsTransform;
7328					}
7329				}
7330
7331			}
7332		};
7333		_registerComplexSpecialProp("clearProps", {parser:function(t, e, p, cssp, pt) {
7334			pt = new CSSPropTween(t, p, 0, 0, pt, 2);
7335			pt.setRatio = _setClearPropsRatio;
7336			pt.e = e;
7337			pt.pr = -10;
7338			pt.data = cssp._tween;
7339			_hasPriority = true;
7340			return pt;
7341		}});
7342
7343		p = "bezier,throwProps,physicsProps,physics2D".split(",");
7344		i = p.length;
7345		while (i--) {
7346			_registerPluginProp(p[i]);
7347		}
7348
7349
7350
7351
7352
7353
7354
7355
7356		p = CSSPlugin.prototype;
7357		p._firstPT = p._lastParsedTransform = p._transform = null;
7358
7359		//gets called when the tween renders for the first time. This kicks everything off, recording start/end values, etc.
7360		p._onInitTween = function(target, vars, tween) {
7361			if (!target.nodeType) { //css is only for dom elements
7362				return false;
7363			}
7364			this._target = target;
7365			this._tween = tween;
7366			this._vars = vars;
7367			_autoRound = vars.autoRound;
7368			_hasPriority = false;
7369			_suffixMap = vars.suffixMap || CSSPlugin.suffixMap;
7370			_cs = _getComputedStyle(target, "");
7371			_overwriteProps = this._overwriteProps;
7372			var style = target.style,
7373				v, pt, pt2, first, last, next, zIndex, tpt, threeD;
7374			if (_reqSafariFix) if (style.zIndex === "") {
7375				v = _getStyle(target, "zIndex", _cs);
7376				if (v === "auto" || v === "") {
7377					//corrects a bug in [non-Android] Safari that prevents it from repainting elements in their new positions if they don't have a zIndex set. We also can't just apply this inside _parseTransform() because anything that's moved in any way (like using "left" or "top" instead of transforms like "x" and "y") can be affected, so it is best to ensure that anything that's tweening has a z-index. Setting "WebkitPerspective" to a non-zero value worked too except that on iOS Safari things would flicker randomly. Plus zIndex is less memory-intensive.
7378					this._addLazySet(style, "zIndex", 0);
7379				}
7380			}
7381
7382			if (typeof(vars) === "string") {
7383				first = style.cssText;
7384				v = _getAllStyles(target, _cs);
7385				style.cssText = first + ";" + vars;
7386				v = _cssDif(target, v, _getAllStyles(target)).difs;
7387				if (!_supportsOpacity && _opacityValExp.test(vars)) {
7388					v.opacity = parseFloat( RegExp.$1 );
7389				}
7390				vars = v;
7391				style.cssText = first;
7392			}
7393
7394			if (vars.className) { //className tweens will combine any differences they find in the css with the vars that are passed in, so {className:"myClass", scale:0.5, left:20} would work.
7395				this._firstPT = pt = _specialProps.className.parse(target, vars.className, "className", this, null, null, vars);
7396			} else {
7397				this._firstPT = pt = this.parse(target, vars, null);
7398			}
7399
7400			if (this._transformType) {
7401				threeD = (this._transformType === 3);
7402				if (!_transformProp) {
7403					style.zoom = 1; //helps correct an IE issue.
7404				} else if (_isSafari) {
7405					_reqSafariFix = true;
7406					//if zIndex isn't set, iOS Safari doesn't repaint things correctly sometimes (seemingly at random).
7407					if (style.zIndex === "") {
7408						zIndex = _getStyle(target, "zIndex", _cs);
7409						if (zIndex === "auto" || zIndex === "") {
7410							this._addLazySet(style, "zIndex", 0);
7411						}
7412					}
7413					//Setting WebkitBackfaceVisibility corrects 3 bugs:
7414					// 1) [non-Android] Safari skips rendering changes to "top" and "left" that are made on the same frame/render as a transform update.
7415					// 2) iOS Safari sometimes neglects to repaint elements in their new positions. Setting "WebkitPerspective" to a non-zero value worked too except that on iOS Safari things would flicker randomly.
7416					// 3) Safari sometimes displayed odd artifacts when tweening the transform (or WebkitTransform) property, like ghosts of the edges of the element remained. Definitely a browser bug.
7417					//Note: we allow the user to override the auto-setting by defining WebkitBackfaceVisibility in the vars of the tween.
7418					if (_isSafariLT6) {
7419						this._addLazySet(style, "WebkitBackfaceVisibility", this._vars.WebkitBackfaceVisibility || (threeD ? "visible" : "hidden"));
7420					}
7421				}
7422				pt2 = pt;
7423				while (pt2 && pt2._next) {
7424					pt2 = pt2._next;
7425				}
7426				tpt = new CSSPropTween(target, "transform", 0, 0, null, 2);
7427				this._linkCSSP(tpt, null, pt2);
7428				tpt.setRatio = _transformProp ? _setTransformRatio : _setIETransformRatio;
7429				tpt.data = this._transform || _getTransform(target, _cs, true);
7430				tpt.tween = tween;
7431				tpt.pr = -1; //ensures that the transforms get applied after the components are updated.
7432				_overwriteProps.pop(); //we don't want to force the overwrite of all "transform" tweens of the target - we only care about individual transform properties like scaleX, rotation, etc. The CSSPropTween constructor automatically adds the property to _overwriteProps which is why we need to pop() here.
7433			}
7434
7435			if (_hasPriority) {
7436				//reorders the linked list in order of pr (priority)
7437				while (pt) {
7438					next = pt._next;
7439					pt2 = first;
7440					while (pt2 && pt2.pr > pt.pr) {
7441						pt2 = pt2._next;
7442					}
7443					if ((pt._prev = pt2 ? pt2._prev : last)) {
7444						pt._prev._next = pt;
7445					} else {
7446						first = pt;
7447					}
7448					if ((pt._next = pt2)) {
7449						pt2._prev = pt;
7450					} else {
7451						last = pt;
7452					}
7453					pt = next;
7454				}
7455				this._firstPT = first;
7456			}
7457			return true;
7458		};
7459
7460
7461		p.parse = function(target, vars, pt, plugin) {
7462			var style = target.style,
7463				p, sp, bn, en, bs, es, bsfx, esfx, isStr, rel;
7464			for (p in vars) {
7465				es = vars[p]; //ending value string
7466				sp = _specialProps[p]; //SpecialProp lookup.
7467				if (sp) {
7468					pt = sp.parse(target, es, p, this, pt, plugin, vars);
7469
7470				} else {
7471					bs = _getStyle(target, p, _cs) + "";
7472					isStr = (typeof(es) === "string");
7473					if (p === "color" || p === "fill" || p === "stroke" || p.indexOf("Color") !== -1 || (isStr && _rgbhslExp.test(es))) { //Opera uses background: to define color sometimes in addition to backgroundColor:
7474						if (!isStr) {
7475							es = _parseColor(es);
7476							es = ((es.length > 3) ? "rgba(" : "rgb(") + es.join(",") + ")";
7477						}
7478						pt = _parseComplex(style, p, bs, es, true, "transparent", pt, 0, plugin);
7479
7480					} else if (isStr && (es.indexOf(" ") !== -1 || es.indexOf(",") !== -1)) {
7481						pt = _parseComplex(style, p, bs, es, true, null, pt, 0, plugin);
7482
7483					} else {
7484						bn = parseFloat(bs);
7485						bsfx = (bn || bn === 0) ? bs.substr((bn + "").length) : ""; //remember, bs could be non-numeric like "normal" for fontWeight, so we should default to a blank suffix in that case.
7486
7487						if (bs === "" || bs === "auto") {
7488							if (p === "width" || p === "height") {
7489								bn = _getDimension(target, p, _cs);
7490								bsfx = "px";
7491							} else if (p === "left" || p === "top") {
7492								bn = _calculateOffset(target, p, _cs);
7493								bsfx = "px";
7494							} else {
7495								bn = (p !== "opacity") ? 0 : 1;
7496								bsfx = "";
7497							}
7498						}
7499
7500						rel = (isStr && es.charAt(1) === "=");
7501						if (rel) {
7502							en = parseInt(es.charAt(0) + "1", 10);
7503							es = es.substr(2);
7504							en *= parseFloat(es);
7505							esfx = es.replace(_suffixExp, "");
7506						} else {
7507							en = parseFloat(es);
7508							esfx = isStr ? es.replace(_suffixExp, "") : "";
7509						}
7510
7511						if (esfx === "") {
7512							esfx = (p in _suffixMap) ? _suffixMap[p] : bsfx; //populate the end suffix, prioritizing the map, then if none is found, use the beginning suffix.
7513						}
7514
7515						es = (en || en === 0) ? (rel ? en + bn : en) + esfx : vars[p]; //ensures that any += or -= prefixes are taken care of. Record the end value before normalizing the suffix because we always want to end the tween on exactly what they intended even if it doesn't match the beginning value's suffix.
7516
7517						//if the beginning/ending suffixes don't match, normalize them...
7518						if (bsfx !== esfx) if (esfx !== "") if (en || en === 0) if (bn) { //note: if the beginning value (bn) is 0, we don't need to convert units!
7519							bn = _convertToPixels(target, p, bn, bsfx);
7520							if (esfx === "%") {
7521								bn /= _convertToPixels(target, p, 100, "%") / 100;
7522								if (vars.strictUnits !== true) { //some browsers report only "px" values instead of allowing "%" with getComputedStyle(), so we assume that if we're tweening to a %, we should start there too unless strictUnits:true is defined. This approach is particularly useful for responsive designs that use from() tweens.
7523									bs = bn + "%";
7524								}
7525
7526							} else if (esfx === "em" || esfx === "rem") {
7527								bn /= _convertToPixels(target, p, 1, esfx);
7528
7529							//otherwise convert to pixels.
7530							} else if (esfx !== "px") {
7531								en = _convertToPixels(target, p, en, esfx);
7532								esfx = "px"; //we don't use bsfx after this, so we don't need to set it to px too.
7533							}
7534							if (rel) if (en || en === 0) {
7535								es = (en + bn) + esfx; //the changes we made affect relative calculations, so adjust the end value here.
7536							}
7537						}
7538
7539						if (rel) {
7540							en += bn;
7541						}
7542
7543						if ((bn || bn === 0) && (en || en === 0)) { //faster than isNaN(). Also, previously we required en !== bn but that doesn't really gain much performance and it prevents _parseToProxy() from working properly if beginning and ending values match but need to get tweened by an external plugin anyway. For example, a bezier tween where the target starts at left:0 and has these points: [{left:50},{left:0}] wouldn't work properly because when parsing the last point, it'd match the first (current) one and a non-tweening CSSPropTween would be recorded when we actually need a normal tween (type:0) so that things get updated during the tween properly.
7544							pt = new CSSPropTween(style, p, bn, en - bn, pt, 0, p, (_autoRound !== false && (esfx === "px" || p === "zIndex")), 0, bs, es);
7545							pt.xs0 = esfx;
7546							//DEBUG: _log("tween "+p+" from "+pt.b+" ("+bn+esfx+") to "+pt.e+" with suffix: "+pt.xs0);
7547						} else if (style[p] === undefined || !es && (es + "" === "NaN" || es == null)) {
7548							_log("invalid " + p + " tween value: " + vars[p]);
7549						} else {
7550							pt = new CSSPropTween(style, p, en || bn || 0, 0, pt, -1, p, false, 0, bs, es);
7551							pt.xs0 = (es === "none" && (p === "display" || p.indexOf("Style") !== -1)) ? bs : es; //intermediate value should typically be set immediately (end value) except for "display" or things like borderTopStyle, borderBottomStyle, etc. which should use the beginning value during the tween.
7552							//DEBUG: _log("non-tweening value "+p+": "+pt.xs0);
7553						}
7554					}
7555				}
7556				if (plugin) if (pt && !pt.plugin) {
7557					pt.plugin = plugin;
7558				}
7559			}
7560			return pt;
7561		};
7562
7563
7564		//gets called every time the tween updates, passing the new ratio (typically a value between 0 and 1, but not always (for example, if an Elastic.easeOut is used, the value can jump above 1 mid-tween). It will always start and 0 and end at 1.
7565		p.setRatio = function(v) {
7566			var pt = this._firstPT,
7567				min = 0.000001,
7568				val, str, i;
7569			//at the end of the tween, we set the values to exactly what we received in order to make sure non-tweening values (like "position" or "float" or whatever) are set and so that if the beginning/ending suffixes (units) didn't match and we normalized to px, the value that the user passed in is used here. We check to see if the tween is at its beginning in case it's a from() tween in which case the ratio will actually go from 1 to 0 over the course of the tween (backwards).
7570			if (v === 1 && (this._tween._time === this._tween._duration || this._tween._time === 0)) {
7571				while (pt) {
7572					if (pt.type !== 2) {
7573						if (pt.r && pt.type !== -1) {
7574							val = Math.round(pt.s + pt.c);
7575							if (!pt.type) {
7576								pt.t[pt.p] = val + pt.xs0;
7577							} else if (pt.type === 1) { //complex value (one that typically has multiple numbers inside a string, like "rect(5px,10px,20px,25px)"
7578								i = pt.l;
7579								str = pt.xs0 + val + pt.xs1;
7580								for (i = 1; i < pt.l; i++) {
7581									str += pt["xn"+i] + pt["xs"+(i+1)];
7582								}
7583								pt.t[pt.p] = str;
7584							}
7585						} else {
7586							pt.t[pt.p] = pt.e;
7587						}
7588					} else {
7589						pt.setRatio(v);
7590					}
7591					pt = pt._next;
7592				}
7593
7594			} else if (v || !(this._tween._time === this._tween._duration || this._tween._time === 0) || this._tween._rawPrevTime === -0.000001) {
7595				while (pt) {
7596					val = pt.c * v + pt.s;
7597					if (pt.r) {
7598						val = Math.round(val);
7599					} else if (val < min) if (val > -min) {
7600						val = 0;
7601					}
7602					if (!pt.type) {
7603						pt.t[pt.p] = val + pt.xs0;
7604					} else if (pt.type === 1) { //complex value (one that typically has multiple numbers inside a string, like "rect(5px,10px,20px,25px)"
7605						i = pt.l;
7606						if (i === 2) {
7607							pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2;
7608						} else if (i === 3) {
7609							pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2 + pt.xn2 + pt.xs3;
7610						} else if (i === 4) {
7611							pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2 + pt.xn2 + pt.xs3 + pt.xn3 + pt.xs4;
7612						} else if (i === 5) {
7613							pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2 + pt.xn2 + pt.xs3 + pt.xn3 + pt.xs4 + pt.xn4 + pt.xs5;
7614						} else {
7615							str = pt.xs0 + val + pt.xs1;
7616							for (i = 1; i < pt.l; i++) {
7617								str += pt["xn"+i] + pt["xs"+(i+1)];
7618							}
7619							pt.t[pt.p] = str;
7620						}
7621
7622					} else if (pt.type === -1) { //non-tweening value
7623						pt.t[pt.p] = pt.xs0;
7624
7625					} else if (pt.setRatio) { //custom setRatio() for things like SpecialProps, external plugins, etc.
7626						pt.setRatio(v);
7627					}
7628					pt = pt._next;
7629				}
7630
7631			//if the tween is reversed all the way back to the beginning, we need to restore the original values which may have different units (like % instead of px or em or whatever).
7632			} else {
7633				while (pt) {
7634					if (pt.type !== 2) {
7635						pt.t[pt.p] = pt.b;
7636					} else {
7637						pt.setRatio(v);
7638					}
7639					pt = pt._next;
7640				}
7641			}
7642		};
7643
7644		/**
7645		 * @private
7646		 * Forces rendering of the target's transforms (rotation, scale, etc.) whenever the CSSPlugin's setRatio() is called.
7647		 * Basically, this tells the CSSPlugin to create a CSSPropTween (type 2) after instantiation that runs last in the linked
7648		 * list and calls the appropriate (3D or 2D) rendering function. We separate this into its own method so that we can call
7649		 * it from other plugins like BezierPlugin if, for example, it needs to apply an autoRotation and this CSSPlugin
7650		 * doesn't have any transform-related properties of its own. You can call this method as many times as you
7651		 * want and it won't create duplicate CSSPropTweens.
7652		 *
7653		 * @param {boolean} threeD if true, it should apply 3D tweens (otherwise, just 2D ones are fine and typically faster)
7654		 */
7655		p._enableTransforms = function(threeD) {
7656			this._transform = this._transform || _getTransform(this._target, _cs, true); //ensures that the element has a _gsTransform property with the appropriate values.
7657			this._transformType = (!(this._transform.svg && _useSVGTransformAttr) && (threeD || this._transformType === 3)) ? 3 : 2;
7658		};
7659
7660		var lazySet = function(v) {
7661			this.t[this.p] = this.e;
7662			this.data._linkCSSP(this, this._next, null, true); //we purposefully keep this._next even though it'd make sense to null it, but this is a performance optimization, as this happens during the while (pt) {} loop in setRatio() at the bottom of which it sets pt = pt._next, so if we null it, the linked list will be broken in that loop.
7663		};
7664		/** @private Gives us a way to set a value on the first render (and only the first render). **/
7665		p._addLazySet = function(t, p, v) {
7666			var pt = this._firstPT = new CSSPropTween(t, p, 0, 0, this._firstPT, 2);
7667			pt.e = v;
7668			pt.setRatio = lazySet;
7669			pt.data = this;
7670		};
7671
7672		/** @private **/
7673		p._linkCSSP = function(pt, next, prev, remove) {
7674			if (pt) {
7675				if (next) {
7676					next._prev = pt;
7677				}
7678				if (pt._next) {
7679					pt._next._prev = pt._prev;
7680				}
7681				if (pt._prev) {
7682					pt._prev._next = pt._next;
7683				} else if (this._firstPT === pt) {
7684					this._firstPT = pt._next;
7685					remove = true; //just to prevent resetting this._firstPT 5 lines down in case pt._next is null. (optimized for speed)
7686				}
7687				if (prev) {
7688					prev._next = pt;
7689				} else if (!remove && this._firstPT === null) {
7690					this._firstPT = pt;
7691				}
7692				pt._next = next;
7693				pt._prev = prev;
7694			}
7695			return pt;
7696		};
7697
7698		//we need to make sure that if alpha or autoAlpha is killed, opacity is too. And autoAlpha affects the "visibility" property.
7699		p._kill = function(lookup) {
7700			var copy = lookup,
7701				pt, p, xfirst;
7702			if (lookup.autoAlpha || lookup.alpha) {
7703				copy = {};
7704				for (p in lookup) { //copy the lookup so that we're not changing the original which may be passed elsewhere.
7705					copy[p] = lookup[p];
7706				}
7707				copy.opacity = 1;
7708				if (copy.autoAlpha) {
7709					copy.visibility = 1;
7710				}
7711			}
7712			if (lookup.className && (pt = this._classNamePT)) { //for className tweens, we need to kill any associated CSSPropTweens too; a linked list starts at the className's "xfirst".
7713				xfirst = pt.xfirst;
7714				if (xfirst && xfirst._prev) {
7715					this._linkCSSP(xfirst._prev, pt._next, xfirst._prev._prev); //break off the prev
7716				} else if (xfirst === this._firstPT) {
7717					this._firstPT = pt._next;
7718				}
7719				if (pt._next) {
7720					this._linkCSSP(pt._next, pt._next._next, xfirst._prev);
7721				}
7722				this._classNamePT = null;
7723			}
7724			return TweenPlugin.prototype._kill.call(this, copy);
7725		};
7726
7727
7728
7729		//used by cascadeTo() for gathering all the style properties of each child element into an array for c
7729omparison.
7730		var _getChildStyles = function(e, props, targets) {
7731				var children, i, child, type;
7732				if (e.slice) {
7733					i = e.length;
7734					while (--i > -1) {
7735						_getChildStyles(e[i], props, targets);
7736					}
7737					return;
7738				}
7739				children = e.childNodes;
7740				i = children.length;
7741				while (--i > -1) {
7742					child = children[i];
7743					type = child.type;
7744					if (child.style) {
7745						props.push(_getAllStyles(child));
7746						if (targets) {
7747							targets.push(child);
7748						}
7749					}
7750					if ((type === 1 || type === 9 || type === 11) && child.childNodes.length) {
7751						_getChildStyles(child, props, targets);
7752					}
7753				}
7754			};
7755
7756		/**
7757		 * Typically only useful for className tweens that may affect child elements, this method creates a TweenLite
7758		 * and then compares the style properties of all the target's child elements at the tween's start and end, and
7759		 * if any are different, it also creates tweens for those and returns an array containing ALL of the resulting
7760		 * tweens (so that you can easily add() them to a TimelineLite, for example). The reason this functionality is
7761		 * wrapped into a separate static method of CSSPlugin instead of being integrated into all regular className tweens
7762		 * is because it creates entirely new tweens that may have completely different targets than the original tween,
7763		 * so if they were all lumped into the original tween instance, it would be inconsistent with the rest of the API
7764		 * and it would create other problems. For example:
7765		 *  - If I create a tween of elementA, that tween instance may suddenly change its target to include 50 other elements (unintuitive if I specifically defined the target I wanted)
7766		 *  - We can't just create new independent tweens because otherwise, what happens if the original/parent tween is reversed or pause or dropped into a TimelineLite for tight control? You'd expect that tween's behavior to affect all the others.
7767		 *  - Analyzing every style property of every child before and after the tween is an expensive operation when there are many children, so this behavior shouldn't be imposed on all className tweens by default, especially since it's probably rare that this extra functionality is needed.
7768		 *
7769		 * @param {Object} target object to be tweened
7770		 * @param {number} Duration in seconds (or frames for frames-based tweens)
7771		 * @param {Object} Object containing the end values, like {className:"newClass", ease:Linear.easeNone}
7772		 * @return {Array} An array of TweenLite instances
7773		 */
7774		CSSPlugin.cascadeTo = function(target, duration, vars) {
7775			var tween = TweenLite.to(target, duration, vars),
7776				results = [tween],
7777				b = [],
7778				e = [],
7779				targets = [],
7780				_reservedProps = TweenLite._internals.reservedProps,
7781				i, difs, p, from;
7782			target = tween._targets || tween.target;
7783			_getChildStyles(target, b, targets);
7784			tween.render(duration, true, true);
7785			_getChildStyles(target, e);
7786			tween.render(0, true, true);
7787			tween._enabled(true);
7788			i = targets.length;
7789			while (--i > -1) {
7790				difs = _cssDif(targets[i], b[i], e[i]);
7791				if (difs.firstMPT) {
7792					difs = difs.difs;
7793					for (p in vars) {
7794						if (_reservedProps[p]) {
7795							difs[p] = vars[p];
7796						}
7797					}
7798					from = {};
7799					for (p in difs) {
7800						from[p] = b[i][p];
7801					}
7802					results.push(TweenLite.fromTo(targets[i], duration, from, difs));
7803				}
7804			}
7805			return results;
7806		};
7807
7808		TweenPlugin.activate([CSSPlugin]);
7809		return CSSPlugin;
7810
7811	}, true);
7812	
7813}); if (_gsScope._gsDefine) { _gsScope._gsQueue.pop()(); }
7814
7815//export to AMD/RequireJS and CommonJS/Node (precursor to full modular build system coming at a later date)
7816(function(name) {
7817	"use strict";
7818	var getGlobal = function() {
7819		return (_gsScope.GreenSockGlobals || _gsScope)[name];
7820	};
7821	if (typeof(define) === "function" && define.amd) { //AMD
7822		define(["TweenLite"], getGlobal);
7823	} else if (typeof(module) !== "undefined" && module.exports) { //node
7824		require("../TweenLite.js");
7825		module.exports = getGlobal();
7826	}
7827}("CSSPlugin"));
7828
7829
7830
7831/*!
7832 * VERSION: beta 0.3.4
7833 * DATE: 2015-08-15
7834 * UPDATES AND DOCS AT: http://greensock.com
7835 *
7836 * @license Copyright (c) 2008-2015, GreenSock. All rights reserved.
7837 * SplitText is a Club GreenSock membership benefit; You must have a valid membership to use
7838 * this code without violating the terms of use. Visit http://www.greensock.com/club/ to sign up or get more details.
7839 * This work is subject to the software agreement that was issued with your membership.
7840 * 
7841 * @author: Jack Doyle, [email protected]
7842 */
7843var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(global) !== "undefined") ? global : this || window; //helps ensure compatibility with AMD/RequireJS and CommonJS/Node
7844(function(window) {
7845	
7846	"use strict";
7847	var _globals = window.GreenSockGlobals || window,
7848		_namespace = function(ns) {
7849			var a = ns.split("."),
7850				p = _globals, i;
7851			for (i = 0; i < a.length; i++) {
7852				p[a[i]] = p = p[a[i]] || {};
7853			}
7854			return p;
7855		},
7856		pkg = _namespace("com.greensock.utils"),
7857		_getText = function(e) {
7858			var type = e.nodeType,
7859				result = "";
7860			if (type === 1 || type === 9 || type === 11) {
7861				if (typeof(e.textContent) === "string") {
7862					return e.textContent;
7863				} else {
7864					for ( e = e.firstChild; e; e = e.nextSibling ) {
7865						result += _getText(e);
7866					}
7867				}
7868			} else if (type === 3 || type === 4) {
7869				return e.nodeValue;
7870			}
7871			return result;
7872		},
7873		_doc = document,
7874		_getComputedStyle = _doc.defaultView ? _doc.defaultView.getComputedStyle : function() {},
7875		_capsExp = /([A-Z])/g,
7876		_getStyle = function(t, p, cs, str) {
7877			var result;
7878			if ((cs = cs || _getComputedStyle(t, null))) {
7879				t = cs.getPropertyValue(p.replace(_capsExp, "-$1").toLowerCase());
7880				result = (t || cs.length) ? t : cs[p]; //Opera behaves VERY strangely - length is usually 0 and cs[p] is the only way to get accurate results EXCEPT when checking for -o-transform which only works with cs.getPropertyValue()!
7881			} else if (t.currentStyle) {
7882				cs = t.currentStyle;
7883				result = cs[p];
7884			}
7885			return str ? result : parseInt(result, 10) || 0;
7886		},
7887		_isArrayLike = function(e) {
7888			return (e.length && e[0] && ((e[0].nodeType && e[0].style && !e.nodeType) || (e[0].length && e[0][0]))) ? true : false; //could be an array of jQuery objects too, so accommodate that.
7889		},
7890		_flattenArray = function(a) {
7891			var result = [],
7892				l = a.length,
7893				i, e, j;
7894			for (i = 0; i < l; i++) {
7895				e = a[i];
7896				if (_isArrayLike(e)) {
7897					j = e.length;
7898					for (j = 0; j < e.length; j++) {
7899						result.push(e[j]);
7900					}
7901				} else {
7902					result.push(e);
7903				}
7904			}
7905			return result;
7906		},
7907		_brSwap = ")eefec303079ad17405c",
7908		_brExp = /(?:<br>|<br\/>|<br \/>)/gi,
7909		_isOldIE = (_doc.all && !_doc.addEventListener),
7910		_divStart = "<div style='position:relative;display:inline-block;" + (_isOldIE ? "*display:inline;*zoom:1;'" : "'"), //note: we must use both display:inline-block and *display:inline for IE8 and earlier, otherwise it won't flow correctly (and if we only use display:inline, IE won't render most of the property tweens - very odd).
7911		_cssClassFunc = function(cssClass) {
7912			cssClass = cssClass || "";
7913			var iterate = (cssClass.indexOf("++") !== -1),
7914				num = 1;
7915			if (iterate) {
7916				cssClass = cssClass.split("++").join("");
7917			}
7918			return function() {
7919				return _divStart + (cssClass ? " class='" + cssClass + (iterate ? num++ : "") + "'>" : ">");
7920			};
7921		},
7922		SplitText = pkg.SplitText = _globals.SplitText = function(element, vars) {
7923			if (typeof(element) === "string") {
7924				element = SplitText.selector(element);
7925			}
7926			if (!element) {
7927				throw("cannot split a null element.");
7928			}
7929			this.elements = _isArrayLike(element) ? _flattenArray(element) : [element];
7930			this.chars = [];
7931			this.words = [];
7932			this.lines = [];
7933			this._originals = [];
7934			this.vars = vars || {};
7935			this.split(vars);
7936		},
7937		_swapText = function(element, oldText, newText) {
7938			var type = element.nodeType;
7939			if (type === 1 || type === 9 || type === 11) {
7940				for ( element = element.firstChild; element; element = element.nextSibling ) {
7941					_swapText(element, oldText, newText);
7942				}
7943			} else if (type === 3 || type === 4) {
7944				element.nodeValue = element.nodeValue.split(oldText).join(newText);
7945			}
7946		},
7947		_pushReversed = function(a, merge) {
7948			var i = merge.length;
7949			while (--i > -1) {
7950				a.push(merge[i]);
7951			}
7952		},
7953		_split = function(element, vars, allChars, allWords, allLines) {
7954			if (_brExp.test(element.innerHTML)) {
7955				element.innerHTML = element.innerHTML.replace(_brExp, _brSwap); //swap in a unique string for <br/> tags so that we can identify it when we loop through later, and replace it appropriately
7956			}
7957			var text = _getText(element),
7958				types = vars.type || vars.split || "chars,words,lines",
7959				lines = (types.indexOf("lines") !== -1) ? [] : null,
7960				words = (types.indexOf("words") !== -1),
7961				chars = (types.indexOf("chars") !== -1),
7962				absolute = (vars.position === "absolute" || vars.absolute === true),
7963				space = absolute ? "&#173; " : " ",
7964				lineOffsetY = -999,
7965				cs = _getComputedStyle(element),
7966				paddingLeft = _getStyle(element, "paddingLeft", cs),
7967				borderTopAndBottom = _getStyle(element, "borderBottomWidth", cs) + _get
7967Style(element, "borderTopWidth", cs),
7968				borderLeftAndRight = _getStyle(element, "borderLeftWidth", cs) + _getStyle(element, "borderRightWidth", cs),
7969				padTopAndBottom = _getStyle(element, "paddingTop", cs) + _getStyle(element, "paddingBottom", cs),
7970				padLeftAndRight = _getStyle(element, "paddingLeft", cs) + _getStyle(element, "paddingRight", cs),
7971				textAlign = _getStyle(element, "textAlign", cs, true),
7972				origHeight = element.clientHeight,
7973				origWidth = element.clientWidth,
7974				wordEnd = "</div>",
7975				wordStart = _cssClassFunc(vars.wordsClass),
7976				charStart = _cssClassFunc(vars.charsClass),
7977				iterateLine = ((vars.linesClass || "").indexOf("++") !== -1),
7978				linesClass = vars.linesClass,
7979				hasTagStart = text.indexOf("<") !== -1,
7980				wordIsOpen = true,
7981				charArray = [],
7982				wordArray = [],
7983				lineArray = [],
7984				l, curLine, isChild, splitText, i, j, character, nodes, node, offset, lineNode, style, lineWidth, addWordSpaces;
7985
7986			if (iterateLine) {
7987				linesClass = linesClass.split("++").join("");
7988			}
7989			if (hasTagStart) {
7990				text = text.split("<").join("{{LT}}"); //we can't leave "<" in the string, or when we set the innerHTML, it can be interpreted as
7991			}
7992			l = text.length;
7993
7994			splitText = wordStart();
7995			for (i = 0; i < l; i++) {
7996				character = text.charAt(i);
7997				if (character === ")" && text.substr(i, 20) === _brSwap) {
7998					splitText += (wordIsOpen ? wordEnd : "") + "<BR/>";
7999					wordIsOpen = false;
8000					if (i !== l - 20 && text.substr(i+20, 20) !== _brSwap) {
8001						splitText += " " + wordStart();
8002						wordIsOpen = true;
8003					}
8004					i += 19;
8005
8006				} else if (character === " " && text.charAt(i-1) !== " " && i !== l-1 && text.substr(i-20, 20) !== _brSwap) {
8007					splitText += wordIsOpen ? wordEnd : "";
8008					wordIsOpen = false;
8009					while (text.charAt(i + 1) === " ") { //skip over empty spaces (to avoid making them words)
8010						splitText += space;
8011						i++;
8012					}
8013					if (text.charAt(i + 1) !== ")" || text.substr(i + 1, 20) !== _brSwap) {
8014						splitText += space + wordStart();
8015						wordIsOpen = true;
8016					}
8017
8018				} else if (character === "{" && text.substr(i, 6) === "{{LT}}") {
8019					splitText +=  chars ? charStart() + "{{LT}}" + "</div>" : "{{LT}}";
8020					i += 5;
8021				} else {
8022					splitText += (chars && character !== " ") ? charStart() + character + "</div>" : character;
8023				}
8024			}
8025			element.innerHTML = splitText + (wordIsOpen ? wordEnd : "");
8026
8027			if (hasTagStart) {
8028				_swapText(element, "{{LT}}", "<");
8029			}
8030			//copy all the descendant nodes into an array (we can't use a regular nodeList because it's live and we may need to renest things)
8031			j = element.getElementsByTagName("*");
8032			l = j.length;
8033			nodes = [];
8034			for (i = 0; i < l; i++) {
8035				nodes[i] = j[i];
8036			}
8037
8038			//for absolute positioning, we need to record the x/y offsets and width/height for every <div>. And even if we're not positioning things absolutely, in order to accommodate lines, we must figure out where the y offset changes so that we can sense where the lines break, and we populate the lines array.
8039			if (lines || absolute) {
8040				for (i = 0; i < l; i++) {
8041					node = nodes[i];
8042					isChild = (node.parentNode === element);
8043					if (isChild || absolute || (chars && !words)) {
8044					 	offset = node.offsetTop;
8045						if (lines && isChild && offset !== lineOffsetY && node.nodeName !== "BR") {
8046							curLine = [];
8047							lines.push(curLine);
8048							lineOffsetY = offset;
8049						}
8050						if (absolute) { //record offset x and y, as well as width and height so that we can access them later for positioning. Grabbing them at once ensures we don't trigger a browser paint & we maximize performance.
8051							node._x = node.offsetLeft;
8052							node._y = offset;
8053							node._w = node.offsetWidth;
8054							node._h = node.offsetHeight;
8055						}
8056						if (lines) {
8057							if (words === isChild || !chars) {
8058								curLine.push(node);
8059								node._x -= paddingLeft;
8060							}
8061							if (isChild && i) {
8062								nodes[i-1]._wordEnd = true;
8063							}
8064							if (node.nodeName === "BR" && node.nextSibling && node.nextSibling.nodeName === "BR") { //two consecutive <br> tags signify a new [empty] line.
8065								lines.push([]);
8066							}
8067						}
8068					}
8069				}
8070			}
8071
8072			for (i = 0; i < l; i++) {
8073				node = nodes[i];
8074				isChild = (node.parentNode === element);
8075				if (node.nodeName === "BR") {
8076					if (lines || absolute) {
8077						element.removeChild(node);
8078						nodes.splice(i--, 1);
8079						l--;
8080					} else if (!words) {
8081						element.appendChild(node);
8082					}
8083					continue;
8084				}
8085
8086				if (absolute) {
8087					style = node.style;
8088					if (!words && !isChild) {
8089						node._x += node.parentNode._x;
8090						node._y += node.parentNode._y;
8091					}
8092					style.left = node._x + "px";
8093					style.top = node._y + "px";
8094					style.position = "absolute";
8095					style.display = "block";
8096					//if we don't set the width/height, things collapse in older versions of IE and the origin for transforms is thrown off in all browsers.
8097					style.width = (node._w + 1) + "px"; //IE is 1px short sometimes. Avoid wrapping
8098					style.height = node._h + "px";
8099				}
8100
8101				if (!words) {
8102					//we always start out wrapping words in their own <div> so that line breaks happen correctly, but here we'll remove those <div> tags if necessary and renest the characters directly into the element rather than inside the word <div>
8103					if (isChild) {
8104						element.removeChild(node);
8105						nodes.splice(i--, 1);
8106						l--;
8107					} else if (!isChild && chars) {
8108						offset = (!lines && !absolute && node.nextSibling); //if this is the last letter in the word (and we're not breaking by lines and not positioning things absolutely), we need to add a space afterwards so that the characters don't just mash together
8109						element.appendChild(node);
8110						if (!offset) {
8111							element.appendChild(_doc.createTextNode(" "));
8112						}
8113						charArray.push(node); //TODO: push()
8114					}
8115				} else if (isChild && node.innerHTML !== "") {
8116					wordArray.push(node);  //TODO: push()
8117				} else if (chars) {
8118					charArray.push(node);  //TODO: push()
8119				}
8120			}
8121
8122			if (lines) {
8123				//the next 7 lines just give us the line width in the most reliable way and figure out the left offset (if position isn't relative or absolute). We must set the width along with text-align to ensure everything works properly for various alignments.
8124				if (absolute) {
8125					lineNode = _doc.createElement("div");
8126					element.appendChild(lineNode);
8127					lineWidth = lineNode.offsetWidth + "px";
8128					offset = (lineNode.offsetParent === element) ? 0 : element.offsetLeft;
8129					element.removeChild(lineNode);
8130				}
8131				style = element.style.cssText;
8132				element.style.cssText = "display:none;"; //to improve performance, set display:none on the element so that the browser doesn't have to worry about reflowing or rendering while we're renesting things. We'll revert the cssText later.
8133				//we can't use element.innerHTML = "" because that causes IE to literally delete all the nodes and their content even though we've stored them in an array! So we must loop through the children and remove them.
8134				while (element.firstChild) {
8135					element.removeChild(element.firstChild);
8136				}
8137				addWordSpaces = (!absolute || (!words && !chars));
8138				for (i = 0; i < lines.length; i++) {
8139					curLine = lines[i];
8140					lineNode = _doc.createElement("div");
8141					lineNode.style.cssText = "display:block;text-align:" + textAlign + ";position:" + (absolute ? "absolute;" : "relative;");
8142					if (linesClass) {
8143						lineNode.className = linesClass + (iterateLine ? i+1 : "");
8144					}
8145					lineArray.push(lineNode);  //TODO: push()
8146					l = curLine.length;
8147					for (j = 0; j < l; j++) {
8148						if (curLine[j].nodeName !== "BR") {
8149							node = curLine[j];
8150							lineNode.appendChild(node);
8151							if (addWordSpaces && (node._wordEnd || words)) {
8152								lineNode.appendChild(_doc.createTextNode(" "));
8153							}
8154							if (absolute) {
8155								if (j === 0) {
8156									lineNode.style.top = node._y + "px";
8157									lineNode.style.left = (paddingLeft + offset) + "px";
8158								}
8159								node.style.top = "0px";
8160								if (offset) {
8161									node.style.left = (node._x - offset) + "px";
8162								}
8163							}
8164						}
8165					}
8166					if (l === 0) { //if there are no nodes in the line (typically meaning there were tw
8166o consecutive <br> tags, just add a non-breaking space so that things display properly.
8167						lineNode.innerHTML = "&nbsp;";
8168					}
8169					if (!words && !chars) {
8170						lineNode.innerHTML = _getText(lineNode).split(String.fromCharCode(160)).join(" ");
8171					}
8172					if (absolute) {
8173						lineNode.style.width = lineWidth;
8174						lineNode.style.height = node._h + "px";
8175					}
8176					element.appendChild(lineNode);
8177				}
8178				element.style.cssText = style;
8179			}
8180
8181			//if everything shifts to being position:absolute, the container can collapse in terms of height or width, so fix that here.
8182			if (absolute) {
8183				if (origHeight > element.clientHeight) {
8184					element.style.height = (origHeight - padTopAndBottom) + "px";
8185					if (element.clientHeight < origHeight) { //IE8 and earlier use a different box model - we must include padding and borders
8186						element.style.height = (origHeight + borderTopAndBottom)+ "px";
8187					}
8188				}
8189				if (origWidth > element.clientWidth) {
8190					element.style.width = (origWidth - padLeftAndRight) + "px";
8191					if (element.clientWidth < origWidth) { //IE8 and earlier use a different box model - we must include padding and borders
8192						element.style.width = (origWidth + borderLeftAndRight)+ "px";
8193					}
8194				}
8195			}
8196			_pushReversed(allChars, charArray);
8197			_pushReversed(allWords, wordArray);
8198			_pushReversed(allLines, lineArray);
8199		},
8200		p = SplitText.prototype;
8201
8202	p.split = function(vars) {
8203		if (this.isSplit) {
8204			this.revert();
8205		}
8206		this.vars = vars || this.vars;
8207		this._originals.length = this.chars.length = this.words.length = this.lines.length = 0;
8208		var i = this.elements.length;
8209		//we split in reversed order so that if/when we position:absolute elements, they don't affect the position of the ones after them in the document flow (shifting them up as they're taken out of the document flow).
8210		while (--i > -1) {
8211			this._originals[i] = this.elements[i].innerHTML;
8212			_split(this.elements[i], this.vars, this.chars, this.words, this.lines);
8213		}
8214		this.chars.reverse();
8215		this.words.reverse();
8216		this.lines.reverse();
8217		this.isSplit = true;
8218		return this;
8219	};
8220
8221	p.revert = function() {
8222		if (!this._originals) {
8223			throw("revert() call wasn't scoped properly.");
8224		}
8225		var i = this._originals.length;
8226		while (--i > -1) {
8227			this.elements[i].innerHTML = this._originals[i];
8228		}
8229		this.chars = [];
8230		this.words = [];
8231		this.lines = [];
8232		this.isSplit = false;
8233		return this;
8234	};
8235
8236	SplitText.selector = window.$ || window.jQuery || function(e) {
8237		var selector = window.$ || window.jQuery;
8238		if (selector) {
8239			SplitText.selector = selector;
8240			return selector(e);
8241		}
8242		return (typeof(document) === "undefined") ? e : (document.querySelectorAll ? document.querySelectorAll(e) : document.getElementById((e.charAt(0) === "#") ? e.substr(1) : e));
8243	};
8244	SplitText.version = "0.3.4";
8245	
8246})(_gsScope);
8247
8248//export to AMD/RequireJS and CommonJS/Node (precursor to full modular build system coming at a later date)
8249(function(name) {
8250	"use strict";
8251	var getGlobal = function() {
8252		return (_gsScope.GreenSockGlobals || _gsScope)[name];
8253	};
8254	if (typeof(define) === "function" && define.amd) { //AMD
8255		define(["TweenLite"], getGlobal);
8256	} else if (typeof(module) !== "undefined" && module.exports) { //node
8257		module.exports = getGlobal();
8258	}
8259}("SplitText"));
8260
8261
8262// Sandboxing Greensock
8263try{
8264	window.GreenSockGlobals = null;
8265	window._gsQueue = null;
8266	window._gsDefine = null;
8267
8268	delete(window.GreenSockGlobals);
8269	delete(window._gsQueue);
8270	delete(window._gsDefine);	
8271   } catch(e) {}
8272
8273try{
8274	window.GreenSockGlobals = oldgs;
8275	window._gsQueue = oldgs_queue;
8276	} catch(e) {}
8277
8278if (window.tplogs==true)
8279	try {
8280		console.groupEnd();
8281	} catch(e) {}
8282
8283
8284;(function (factory) {
8285    if (typeof define === 'function' && define.amd) {
8286        // AMD. Register as an anonymous module.
8287        define(['jquery'], factory);
8288    } else if (typeof exports === 'object') {
8289        // CommonJS / nodejs module
8290        module.exports = factory(require('jquery'));
8291    } else {
8292        // Browser globals
8293        factory(jQuery);
8294    }
8295}(function ($) {
8296    // Namespace all events.
8297    var eventNamespace = 'waitForImages';
8298
8299    // CSS properties which contain references to images.
8300    $.waitForImages = {
8301        hasImageProperties: [
8302            'backgroundImage',
8303            'listStyleImage',
8304            'borderImage',
8305            'borderCornerImage',
8306            'cursor'
8307        ],
8308        hasImageAttributes: ['srcset']
8309    };
8310
8311    // Custom selector to find all `img` elements with a valid `src` attribute.
8312    //theme
8313    // $.expr[':']['has-src'] = function (obj) {
8314    //     // Ensure we are dealing with an `img` element with a valid
8315    //     // `src` attribute.
8316    //     return $(obj).is('img[src][src!=""]');
8317    // };
8318
8319    // Custom selector to find images which are not already cached by the
8320    // browser.
8321    //theme
8322    // $.expr[':'].uncached = function (obj) {
8323    //     // Ensure we are dealing with an `img` element with a valid
8324    //     // `src` attribute.
8325    //     if (!$(obj).is(':has-src')) {
8326    //         return false;
8327    //     }
8328
8329    //     return !obj.complete;
8330    // };
8331
8332    $.fn.waitForImages = function () {
8333
8334        var allImgsLength = 0;
8335        var allImgsLoaded = 0;
8336        var deferred = $.Deferred();
8337
8338        var finishedCallback;
8339        var eachCallback;
8340        var waitForAll;
8341
8342        // Handle options object (if passed).
8343        if ($.isPlainObject(arguments[0])) {
8344
8345            waitForAll = arguments[0].waitForAll;
8346            eachCallback = arguments[0].each;
8347            finishedCallback = arguments[0].finished;
8348
8349        } else {
8350
8351            // Handle if using deferred object and only one param was passed in.
8352            if (arguments.length === 1 && $.type(arguments[0]) === 'boolean') {
8353                waitForAll = arguments[0];
8354            } else {
8355                finishedCallback = arguments[0];
8356                eachCallback = arguments[1];
8357                waitForAll = arguments[2];
8358            }
8359
8360        }
8361
8362        // Handle missing callbacks.
8363        finishedCallback = finishedCallback || $.noop;
8364        eachCallback = eachCallback || $.noop;
8365
8366        // Convert waitForAll to Boolean
8367        waitForAll = !! waitForAll;
8368
8369        // Ensure callbacks are functions.
8370        if (!$.isFunction(finishedCallback) || !$.isFunction(eachCallback)) {
8371            throw new TypeError('An invalid callback was supplied.');
8372        }
8373
8374        this.each(function () {
8375            // Build a list of all imgs, dependent on what images will
8376            // be considered.
8377            var obj = $(this);
8378            var allImgs = [];
8379            // CSS properties which may contain an image.
8380            var hasImgProperties = $.waitForImages.hasImageProperties || [];
8381            // Element attributes which may contain an image.
8382            var hasImageAttributes = $.waitForImages.hasImageAttributes || [];
8383            // To match `url()` references.
8384            // Spec: http://www.w3.org/TR/CSS2/syndata.html#value-def-uri
8385            var matchUrl = /url\(\s*(['"]?)(.*?)\1\s*\)/g;
8386
8387            if (waitForAll) {
8388
8389                // Get all elements (including the original), as any one of
8390                // them could have a background image.
8391                obj.find('*').addBack().each(function () {
8392                    var element = $(this);
8393
8394                    // If an `img` element, add it. But keep iterating in
8395                    // case it has a background image too.
8396                    if (element.is('img:has-src')) {
8397                        allImgs.push({
8398                            src: element.attr('src'),
8399                            element: element[0]
8400                        });
8401                    }
8402
8403                    $.each(hasImgProperties, function (i, property) {
8404                        var propertyValue = element.css(property);
8405                        var match;
8406
8407                        // If it doesn't contain this property, skip.
8408                        if (!propertyValue) {
8409                            return true;
8410                        }
8411
8412                        // Get all url() of this element.
8413                        while (match = matchUrl.exec(propertyValue)) {
8414                            allImgs.push({
8415                                src: match[2],
8416                                element: element[0]
8417                            });
8418                        }
8419                    });
8420
8421                    $.each(hasImageAttributes, function (i, attribute) {
8422                        var attributeValue = element.attr(attribute);
8423                        var attributeValues;
8424
8425                        // If it doesn't contain this property, skip.
8426                        if (!attributeValue) {
8427                            return true;
8428                        }
8429
8430                        // Check for multiple comma separated images
8431                        attributeValues = attributeValue.split(',');
8432
8433                        $.each(attributeValues, function(i, value) {
8434                            // Trim value and get string before first
8435                            // whitespace (for use with srcset).
8436                            value = $.trim(value).split(' ')[0];
8437                            allImgs.push({
8438                                src: value,
8439                                element: element[0]
8440                            });
8441                        });
8442                    });
8443                });
8444            } else {
8445                // For images only, the task is simpler.
8446                obj.find('img:has-src')
8447                    .each(function () {
8448                    allImgs.push({
8449                        src: this.src,
8450                        element: this
8451                    });
8452                });
8453            }
8454
8455            allImgsLength = allImgs.length;
8456            allImgsLoaded = 0;
8457
8458            // If no images found, don't bother.
8459            if (allImgsLength === 0) {
8460                finishedCallback.call(obj[0]);
8461                deferred.resolveWith(obj[0]);
8462            }
8463
8464            $.each(allImgs, function (i, img) {
8465
8466                var image = new Image();
8467                var events =
8468                  'load.' + eventNamespace + ' error.' + eventNamespace;
8469
8470                // Handle the image loading and error with the same callback.
8471                $(image).one(events, function me (event) {
8472                    // If an error occurred with loading the image, set the
8473                    // third argument accordingly.
8474                    var eachArguments = [
8475                        allImgsLoaded,
8476                        allImgsLength,
8477                        event.type == 'load'
8478                    ];
8479                    allImgsLoaded++;
8480
8481                    eachCallback.apply(img.element, eachArguments);
8482                    deferred.notifyWith(img.element, eachArguments);
8483
8484                    // Unbind the event listeners. I use this in addition to
8485                    // `one` as one of those events won't be called (either
8486                    // 'load' or 'error' will be called).
8487                    $(this).off(events, me);
8488
8489                    if (allImgsLoaded == allImgsLength) {
8490                        finishedCallback.call(obj[0]);
8491                        deferred.resolveWith(obj[0]);
8492                        return false;
8493                    }
8494
8495                });
8496
8497                image.src = img.src;
8498            });
8499        });
8500
8501        return deferred.promise();
8502
8503    };
8504}));
8505

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.