define( [

	"./core",

	"./core/camelCase",

	"./var/document",

	"./var/isFunction",

	"./var/rcssNum",

	"./var/rnothtmlwhite",

	"./css/var/cssExpand",

	"./css/var/isHiddenWithinTree",

	"./css/var/swap",

	"./css/adjustCSS",

	"./data/var/dataPriv",

	"./css/showHide",



	"./core/init",

	"./queue",

	"./deferred",

	"./traversing",

	"./manipulation",

	"./css",

	"./effects/Tween"

], function( jQuery, camelCase, document, isFunction, rcssNum, rnothtmlwhite, cssExpand,

	isHiddenWithinTree, swap, adjustCSS, dataPriv, showHide ) {



"use strict";



var

	fxNow, inProgress,

	rfxtypes = /^(?:toggle|show|hide)$/,

	rrun = /queueHooks$/;



function schedule() {

	if ( inProgress ) {

		if ( document.hidden === false && window.requestAnimationFrame ) {

			window.requestAnimationFrame( schedule );

		} else {

			window.setTimeout( schedule, jQuery.fx.interval );

		}



		jQuery.fx.tick();

	}

}



// Animations created synchronously will run synchronously

function createFxNow() {

	window.setTimeout( function() {

		fxNow = undefined;

	} );

	return ( fxNow = Date.now() );

}



// Generate parameters to create a standard animation

function genFx( type, includeWidth ) {

	var which,

		i = 0,

		attrs = { height: type };



	// If we include width, step value is 1 to do all cssExpand values,

	// otherwise step value is 2 to skip over Left and Right

	includeWidth = includeWidth ? 1 : 0;

	for ( ; i < 4; i += 2 - includeWidth ) {

		which = cssExpand[ i ];

		attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;

	}



	if ( includeWidth ) {

		attrs.opacity = attrs.width = type;

	}



	return attrs;

}



function createTween( value, prop, animation ) {

	var tween,

		collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ),

		index = 0,

		length = collection.length;

	for ( ; index < length; index++ ) {

		if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) {



			// We're done with this property

			return tween;

		}

	}

}



function defaultPrefilter( elem, props, opts ) {

	var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display,

		isBox = "width" in props || "height" in props,

		anim = this,

		orig = {},

		style = elem.style,

		hidden = elem.nodeType && isHiddenWithinTree( elem ),

		dataShow = dataPriv.get( elem, "fxshow" );



	// Queue-skipping animations hijack the fx hooks

	if ( !opts.queue ) {

		hooks = jQuery._queueHooks( elem, "fx" );

		if ( hooks.unqueued == null ) {

			hooks.unqueued = 0;

			oldfire = hooks.empty.fire;

			hooks.empty.fire = function() {

				if ( !hooks.unqueued ) {

					oldfire();

				}

			};

		}

		hooks.unqueued++;



		anim.always( function() {



			// Ensure the complete handler is called before this completes

			anim.always( function() {

				hooks.unqueued--;

				if ( !jQuery.queue( elem, "fx" ).length ) {

					hooks.empty.fire();

				}

			} );

		} );

	}



	// Detect show/hide animations

	for ( prop in props ) {

		value = props[ prop ];

		if ( rfxtypes.test( value ) ) {

			delete props[ prop ];

			toggle = toggle || value === "toggle";

			if ( value === ( hidden ? "hide" : "show" ) ) {



				// Pretend to be hidden if this is a "show" and

				// there is still data from a stopped show/hide

				if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {

					hidden = true;



				// Ignore all other no-op show/hide data

				} else {

					continue;

				}

			}

			orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );

		}

	}



	// Bail out if this is a no-op like .hide().hide()

	propTween = !jQuery.isEmptyObject( props );

	if ( !propTween && jQuery.isEmptyObject( orig ) ) {

		return;

	}



	// Restrict "overflow" and "display" styles during box animations

	if ( isBox && elem.nodeType === 1 ) {



		// Support: IE <=9 - 11, Edge 12 - 15

		// Record all 3 overflow attributes because IE does not infer the shorthand

		// from identically-valued overflowX and overflowY and Edge just mirrors

		// the overflowX value there.

		opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];



		// Identify a display type, preferring old show/hide data over the CSS cascade

		restoreDisplay = dataShow && dataShow.display;

		if ( restoreDisplay == null ) {

			restoreDisplay = dataPriv.get( elem, "display" );

		}

		display = jQuery.css( elem, "display" );

		if ( display === "none" ) {

			if ( restoreDisplay ) {

				display = restoreDisplay;

			} else {



				// Get nonempty value(s) by temporarily forcing visibility

				showHide( [ elem ], true );

				restoreDisplay = elem.style.display || restoreDisplay;

				display = jQuery.css( elem, "display" );

				showHide( [ elem ] );

			}

		}



		// Animate inline elements as inline-block

		if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) {

			if ( jQuery.css( elem, "float" ) === "none" ) {



				// Restore the original display value at the end of pure show/hide animations

				if ( !propTween ) {

					anim.done( function() {

						style.display = restoreDisplay;

					} );

					if ( restoreDisplay == null ) {

						display = style.display;

						restoreDisplay = display === "none" ? "" : display;

					}

				}

				style.display = "inline-block";

			}

		}

	}



	if ( opts.overflow ) {

		style.overflow = "hidden";

		anim.always( function() {

			style.overflow = opts.overflow[ 0 ];

			style.overflowX = opts.overflow[ 1 ];

			style.overflowY = opts.overflow[ 2 ];

		} );

	}



	// Implement show/hide animations

	propTween = false;

	for ( prop in orig ) {



		// General show/hide setup for this element animation

		if ( !propTween ) {

			if ( dataShow ) {

				if ( "hidden" in dataShow ) {

					hidden = dataShow.hidden;

				}

			} else {

				dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } );

			}



			// Store hidden/visible for toggle so `.stop().toggle()` "reverses"

			if ( toggle ) {

				dataShow.hidden = !hidden;

			}



			// Show elements before animating them

			if ( hidden ) {

				showHide( [ elem ], true );

			}



			/* eslint-disable no-loop-func */



			anim.done( function() {



			/* eslint-enable no-loop-func */



				// The final step of a "hide" animation is actually hiding the element

				if ( !hidden ) {

					showHide( [ elem ] );

				}

				dataPriv.remove( elem, "fxshow" );

				for ( prop in orig ) {

					jQuery.style( elem, prop, orig[ prop ] );

				}

			} );

		}



		// Per-property setup

		propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );

		if ( !( prop in dataShow ) ) {

			dataShow[ prop ] = propTween.start;

			if ( hidden ) {

				propTween.end = propTween.start;

				propTween.start = 0;

			}

		}

	}

}



function propFilter( props, specialEasing ) {

	var index, name, easing, value, hooks;



	// camelCase, specialEasing and expand cssHook pass

	for ( index in props ) {

		name = camelCase( index );

		easing = specialEasing[ name ];

		value = props[ index ];

		if ( Array.isArray( value ) ) {

			easing = value[ 1 ];

			value = props[ index ] = value[ 0 ];

		}



		if ( index !== name ) {

			props[ name ] = value;

			delete props[ index ];

		}



		hooks = jQuery.cssHooks[ name ];

		if ( hooks && "expand" in hooks ) {

			value = hooks.expand( value );

			delete props[ name ];



			// Not quite $.extend, this won't overwrite existing keys.

			// Reusing 'index' because we have the correct "name"

			for ( index in value ) {

				if ( !( index in props ) ) {

					props[ index ] = value[ index ];

					specialEasing[ index ] = easing;

				}

			}

		} else {

			specialEasing[ name ] = easing;

		}

	}

}



function Animation( elem, properties, options ) {

	var result,

		stopped,

		index = 0,

		length = Animation.prefilters.length,

		deferred = jQuery.Deferred().always( function() {



			// Don't match elem in the :animated selector

			delete tick.elem;

		} ),

		tick = function() {

			if ( stopped ) {

				return false;

			}

			var currentTime = fxNow || createFxNow(),

				remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),



				// Support: Android 2.3 only

				// Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)

				temp = remaining / animation.duration || 0,

				percent = 1 - temp,

				index = 0,

				length = animation.tweens.length;



			for ( ; index < length; index++ ) {

				animation.tweens[ index ].run( percent );

			}



			deferred.notifyWith( elem, [ animation, percent, remaining ] );



			// If there's more to do, yield

			if ( percent < 1 && length ) {

				return remaining;

			}



			// If this was an empty animation, synthesize a final progress notification

			if ( !length ) {

				deferred.notifyWith( elem, [ animation, 1, 0 ] );

			}



			// Resolve the animation and report its conclusion

			deferred.resolveWith( elem, [ animation ] );

			return false;

		},

		animation = deferred.promise( {

			elem: elem,

			props: jQuery.extend( {}, properties ),

			opts: jQuery.extend( true, {

				specialEasing: {},

				easing: jQuery.easing._default

			}, options ),

			originalProperties: properties,

			originalOptions: options,

			startTime: fxNow || createFxNow(),

			duration: options.duration,

			tweens: [],

			createTween: function( prop, end ) {

				var tween = jQuery.Tween( elem, animation.opts, prop, end,

						animation.opts.specialEasing[ prop ] || animation.opts.easing );

				animation.tweens.push( tween );

				return tween;

			},

			stop: function( gotoEnd ) {

				var index = 0,



					// If we are going to the end, we want to run all the tweens

					// otherwise we skip this part

					length = gotoEnd ? animation.tweens.length : 0;

				if ( stopped ) {

					return this;

				}

				stopped = true;

				for ( ; index < length; index++ ) {

					animation.tweens[ index ].run( 1 );

				}



				// Resolve when we played the last frame; otherwise, reject

				if ( gotoEnd ) {

					deferred.notifyWith( elem, [ animation, 1, 0 ] );

					deferred.resolveWith( elem, [ animation, gotoEnd ] );

				} else {

					deferred.rejectWith( elem, [ animation, gotoEnd ] );

				}

				return this;

			}

		} ),

		props = animation.props;



	propFilter( props, animation.opts.specialEasing );



	for ( ; index < length; index++ ) {

		result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );

		if ( result ) {

			if ( isFunction( result.stop ) ) {

				jQuery._queueHooks( animation.elem, animation.opts.queue ).stop =

					result.stop.bind( result );

			}

			return result;

		}

	}



	jQuery.map( props, createTween, animation );



	if ( isFunction( animation.opts.start ) ) {

		animation.opts.start.call( elem, animation );

	}



	// Attach callbacks from options

	animation

		.progress( animation.opts.progress )

		.done( animation.opts.done, animation.opts.complete )

		.fail( animation.opts.fail )

		.always( animation.opts.always );



	jQuery.fx.timer(

		jQuery.extend( tick, {

			elem: elem,

			anim: animation,

			queue: animation.opts.queue

		} )

	);



	return animation;

}



jQuery.Animation = jQuery.extend( Animation, {



	tweeners: {

		"*": [ function( prop, value ) {

			var tween = this.createTween( prop, value );

			adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );

			return tween;

		} ]

	},



	tweener: function( props, callback ) {

		if ( isFunction( props ) ) {

			callback = props;

			props = [ "*" ];

		} else {

			props = props.match( rnothtmlwhite );

		}



		var prop,

			index = 0,

			length = props.length;



		for ( ; index < length; index++ ) {

			prop = props[ index ];

			Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];

			Animation.tweeners[ prop ].unshift( callback );

		}

	},



	prefilters: [ defaultPrefilter ],



	prefilter: function( callback, prepend ) {

		if ( prepend ) {

			Animation.prefilters.unshift( callback );

		} else {

			Animation.prefilters.push( callback );

		}

	}

} );



jQuery.speed = function( speed, easing, fn ) {

	var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {

		complete: fn || !fn && easing ||

			isFunction( speed ) && speed,

		duration: speed,

		easing: fn && easing || easing && !isFunction( easing ) && easing

	};



	// Go to the end state if fx are off

	if ( jQuery.fx.off ) {

		opt.duration = 0;



	} else {

		if ( typeof opt.duration !== "number" ) {

			if ( opt.duration in jQuery.fx.speeds ) {

				opt.duration = jQuery.fx.speeds[ opt.duration ];



			} else {

				opt.duration = jQuery.fx.speeds._default;

			}

		}

	}



	// Normalize opt.queue - true/undefined/null -> "fx"

	if ( opt.queue == null || opt.queue === true ) {

		opt.queue = "fx";

	}



	// Queueing

	opt.old = opt.complete;



	opt.complete = function() {

		if ( isFunction( opt.old ) ) {

			opt.old.call( this );

		}



		if ( opt.queue ) {

			jQuery.dequeue( this, opt.queue );

		}

	};



	return opt;

};



jQuery.fn.extend( {

	fadeTo: function( speed, to, easing, callback ) {



		// Show any hidden elements after setting opacity to 0

		return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show()



			// Animate to the value specified

			.end().animate( { opacity: to }, speed, easing, callback );

	},

	animate: function( prop, speed, easing, callback ) {

		var empty = jQuery.isEmptyObject( prop ),

			optall = jQuery.speed( speed, easing, callback ),

			doAnimation = function() {



				// Operate on a copy of prop so per-property easing won't be lost

				var anim = Animation( this, jQuery.extend( {}, prop ), optall );



				// Empty animations, or finishing resolves immediately

				if ( empty || dataPriv.get( this, "finish" ) ) {

					anim.stop( true );

				}

			};

			doAnimation.finish = doAnimation;



		return empty || optall.queue === false ?

			this.each( doAnimation ) :

			this.queue( optall.queue, doAnimation );

	},

	stop: function( type, clearQueue, gotoEnd ) {

		var stopQueue = function( hooks ) {

			var stop = hooks.stop;

			delete hooks.stop;

			stop( gotoEnd );

		};



		if ( typeof type !== "string" ) {

			gotoEnd = clearQueue;

			clearQueue = type;

			type = undefined;

		}

		if ( clearQueue && type !== false ) {

			this.queue( type || "fx", [] );

		}



		return this.each( function() {

			var dequeue = true,

				index = type != null && type + "queueHooks",

				timers = jQuery.timers,

				data = dataPriv.get( this );



			if ( index ) {

				if ( data[ index ] && data[ index ].stop ) {

					stopQueue( data[ index ] );

				}

			} else {

				for ( index in data ) {

					if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {

						stopQueue( data[ index ] );

					}

				}

			}



			for ( index = timers.length; index--; ) {

				if ( timers[ index ].elem === this &&

					( type == null || timers[ index ].queue === type ) ) {



					timers[ index ].anim.stop( gotoEnd );

					dequeue = false;

					timers.splice( index, 1 );

				}

			}



			// Start the next in the queue if the last step wasn't forced.

			// Timers currently will call their complete callbacks, which

			// will dequeue but only if they were gotoEnd.

			if ( dequeue || !gotoEnd ) {

				jQuery.dequeue( this, type );

			}

		} );

	},

	finish: function( type ) {

		if ( type !== false ) {

			type = type || "fx";

		}

		return this.each( function() {

			var index,

				data = dataPriv.get( this ),

				queue = data[ type + "queue" ],

				hooks = data[ type + "queueHooks" ],

				timers = jQuery.timers,

				length = queue ? queue.length : 0;



			// Enable finishing flag on private data

			data.finish = true;



			// Empty the queue first

			jQuery.queue( this, type, [] );



			if ( hooks && hooks.stop ) {

				hooks.stop.call( this, true );

			}



			// Look for any active animations, and finish them

			for ( index = timers.length; index--; ) {

				if ( timers[ index ].elem === this && timers[ index ].queue === type ) {

					timers[ index ].anim.stop( true );

					timers.splice( index, 1 );

				}

			}



			// Look for any animations in the old queue and finish them

			for ( index = 0; index < length; index++ ) {

				if ( queue[ index ] && queue[ index ].finish ) {

					queue[ index ].finish.call( this );

				}

			}



			// Turn off finishing flag

			delete data.finish;

		} );

	}

} );



jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) {

	var cssFn = jQuery.fn[ name ];

	jQuery.fn[ name ] = function( speed, easing, callback ) {

		return speed == null || typeof speed === "boolean" ?

			cssFn.apply( this, arguments ) :

			this.animate( genFx( name, true ), speed, easing, callback );

	};

} );



// Generate shortcuts for custom animations

jQuery.each( {

	slideDown: genFx( "show" ),

	slideUp: genFx( "hide" ),

	slideToggle: genFx( "toggle" ),

	fadeIn: { opacity: "show" },

	fadeOut: { opacity: "hide" },

	fadeToggle: { opacity: "toggle" }

}, function( name, props ) {

	jQuery.fn[ name ] = function( speed, easing, callback ) {

		return this.animate( props, speed, easing, callback );

	};

} );



jQuery.timers = [];

jQuery.fx.tick = function() {

	var timer,

		i = 0,

		timers = jQuery.timers;



	fxNow = Date.now();



	for ( ; i < timers.length; i++ ) {

		timer = timers[ i ];



		// Run the timer and safely remove it when done (allowing for external removal)

		if ( !timer() && timers[ i ] === timer ) {

			timers.splice( i--, 1 );

		}

	}



	if ( !timers.length ) {

		jQuery.fx.stop();

	}

	fxNow = undefined;

};



jQuery.fx.timer = function( timer ) {

	jQuery.timers.push( timer );

	jQuery.fx.start();

};



jQuery.fx.interval = 13;

jQuery.fx.start = function() {

	if ( inProgress ) {

		return;

	}



	inProgress = true;

	schedule();

};



jQuery.fx.stop = function() {

	inProgress = null;

};



jQuery.fx.speeds = {

	slow: 600,

	fast: 200,



	// Default speed

	_default: 400

};



return jQuery;

} );

