define( [

"./core",
"./var/document",
"./var/rcssNum",
"./css/var/cssExpand",
"./var/rnotwhite",
"./css/var/isHidden",
"./css/adjustCSS",
"./css/defaultDisplay",
"./data/var/dataPriv",

"./core/init",
"./effects/Tween",
"./queue",
"./css",
"./deferred",
"./traversing"

], function( jQuery, document, rcssNum, cssExpand, rnotwhite,

isHidden, adjustCSS, defaultDisplay, dataPriv ) {

var

fxNow, timerId,
rfxtypes = /^(?:toggle|show|hide)$/,
rrun = /queueHooks$/;

// Animations created synchronously will run synchronously function createFxNow() {

window.setTimeout( function() {
        fxNow = undefined;
} );
return ( fxNow = jQuery.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 ) {

/* jshint validthis: true */
var prop, value, toggle, tween, hooks, oldfire, display, checkDisplay,
        anim = this,
        orig = {},
        style = elem.style,
        hidden = elem.nodeType && isHidden( elem ),
        dataShow = dataPriv.get( elem, "fxshow" );

// Handle queue: false promises
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();
                        }
                } );
        } );
}

// Height/width overflow pass
if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {

        // Make sure that nothing sneaks out
        // Record all 3 overflow attributes because IE9-10 do not
        // change the overflow attribute when overflowX and
        // overflowY are set to the same value
        opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];

        // Set display property to inline-block for height/width
        // animations on inline elements that are having width/height animated
        display = jQuery.css( elem, "display" );

        // Test default display if display is currently "none"
        checkDisplay = display === "none" ?
                dataPriv.get( elem, "olddisplay" ) || defaultDisplay( elem.nodeName ) : display;

        if ( checkDisplay === "inline" && jQuery.css( elem, "float" ) === "none" ) {
                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 ];
        } );
}

// show/hide pass
for ( prop in props ) {
        value = props[ prop ];
        if ( rfxtypes.exec( value ) ) {
                delete props[ prop ];
                toggle = toggle || value === "toggle";
                if ( value === ( hidden ? "hide" : "show" ) ) {

                        // If there is dataShow left over from a stopped hide or show
                        // and we are going to proceed with show, we should pretend to be hidden
                        if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
                                hidden = true;
                        } else {
                                continue;
                        }
                }
                orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );

        // Any non-fx value stops us from restoring the original display value
        } else {
                display = undefined;
        }
}

if ( !jQuery.isEmptyObject( orig ) ) {
        if ( dataShow ) {
                if ( "hidden" in dataShow ) {
                        hidden = dataShow.hidden;
                }
        } else {
                dataShow = dataPriv.access( elem, "fxshow", {} );
        }

        // Store state if its toggle - enables .stop().toggle() to "reverse"
        if ( toggle ) {
                dataShow.hidden = !hidden;
        }
        if ( hidden ) {
                jQuery( elem ).show();
        } else {
                anim.done( function() {
                        jQuery( elem ).hide();
                } );
        }
        anim.done( function() {
                var prop;

                dataPriv.remove( elem, "fxshow" );
                for ( prop in orig ) {
                        jQuery.style( elem, prop, orig[ prop ] );
                }
        } );
        for ( prop in orig ) {
                tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );

                if ( !( prop in dataShow ) ) {
                        dataShow[ prop ] = tween.start;
                        if ( hidden ) {
                                tween.end = tween.start;
                                tween.start = prop === "width" || prop === "height" ? 1 : 0;
                        }
                }
        }

// If this is a noop like .hide().hide(), restore an overwritten display value
} else if ( ( display === "none" ? defaultDisplay( elem.nodeName ) : display ) === "inline" ) {
        style.display = display;
}

}

function propFilter( props, specialEasing ) {

var index, name, easing, value, hooks;

// camelCase, specialEasing and expand cssHook pass
for ( index in props ) {
        name = jQuery.camelCase( index );
        easing = specialEasing[ name ];
        value = props[ index ];
        if ( jQuery.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
                        // 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 ( percent < 1 && length ) {
                        return remaining;
                } else {
                        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 ( jQuery.isFunction( result.stop ) ) {
                        jQuery._queueHooks( animation.elem, animation.opts.queue ).stop =
                                jQuery.proxy( result.stop, result );
                }
                return result;
        }
}

jQuery.map( props, createTween, animation );

if ( jQuery.isFunction( animation.opts.start ) ) {
        animation.opts.start.call( elem, animation );
}

jQuery.fx.timer(
        jQuery.extend( tick, {
                elem: elem,
                anim: animation,
                queue: animation.opts.queue
        } )
);

// attach callbacks from options
return animation.progress( animation.opts.progress )
        .done( animation.opts.done, animation.opts.complete )
        .fail( animation.opts.fail )
        .always( animation.opts.always );

}

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 ( jQuery.isFunction( props ) ) {
                callback = props;
                props = [ "*" ];
        } else {
                props = props.match( rnotwhite );
        }

        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 ||
                jQuery.isFunction( speed ) && speed,
        duration: speed,
        easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
};

opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ?
        opt.duration : opt.duration in jQuery.fx.speeds ?
                jQuery.fx.speeds[ 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 ( jQuery.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( isHidden ).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 = jQuery.now();

for ( ; i < timers.length; i++ ) {
        timer = timers[ i ];

        // Checks the timer has not already been removed
        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 );
if ( timer() ) {
        jQuery.fx.start();
} else {
        jQuery.timers.pop();
}

};

jQuery.fx.interval = 13; jQuery.fx.start = function() {

if ( !timerId ) {
        timerId = window.setInterval( jQuery.fx.tick, jQuery.fx.interval );
}

};

jQuery.fx.stop = function() {

window.clearInterval( timerId );

timerId = null;

};

jQuery.fx.speeds = {

slow: 600,
fast: 200,

// Default speed
_default: 400

};

return jQuery; } );