define( [

	"./core",

	"./core/toType",

	"./var/isFunction",

	"./var/rnothtmlwhite"

], function( jQuery, toType, isFunction, rnothtmlwhite ) {



"use strict";



// Convert String-formatted options into Object-formatted ones

function createOptions( options ) {

	var object = {};

	jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) {

		object[ flag ] = true;

	} );

	return object;

}



/*

 * Create a callback list using the following parameters:

 *

 *	options: an optional list of space-separated options that will change how

 *			the callback list behaves or a more traditional option object

 *

 * By default a callback list will act like an event callback list and can be

 * "fired" multiple times.

 *

 * Possible options:

 *

 *	once:			will ensure the callback list can only be fired once (like a Deferred)

 *

 *	memory:			will keep track of previous values and will call any callback added

 *					after the list has been fired right away with the latest "memorized"

 *					values (like a Deferred)

 *

 *	unique:			will ensure a callback can only be added once (no duplicate in the list)

 *

 *	stopOnFalse:	interrupt callings when a callback returns false

 *

 */

jQuery.Callbacks = function( options ) {



	// Convert options from String-formatted to Object-formatted if needed

	// (we check in cache first)

	options = typeof options === "string" ?

		createOptions( options ) :

		jQuery.extend( {}, options );



	var // Flag to know if list is currently firing

		firing,



		// Last fire value for non-forgettable lists

		memory,



		// Flag to know if list was already fired

		fired,



		// Flag to prevent firing

		locked,



		// Actual callback list

		list = [],



		// Queue of execution data for repeatable lists

		queue = [],



		// Index of currently firing callback (modified by add/remove as needed)

		firingIndex = -1,



		// Fire callbacks

		fire = function() {



			// Enforce single-firing

			locked = locked || options.once;



			// Execute callbacks for all pending executions,

			// respecting firingIndex overrides and runtime changes

			fired = firing = true;

			for ( ; queue.length; firingIndex = -1 ) {

				memory = queue.shift();

				while ( ++firingIndex < list.length ) {



					// Run callback and check for early termination

					if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&

						options.stopOnFalse ) {



						// Jump to end and forget the data so .add doesn't re-fire

						firingIndex = list.length;

						memory = false;

					}

				}

			}



			// Forget the data if we're done with it

			if ( !options.memory ) {

				memory = false;

			}



			firing = false;



			// Clean up if we're done firing for good

			if ( locked ) {



				// Keep an empty list if we have data for future add calls

				if ( memory ) {

					list = [];



				// Otherwise, this object is spent

				} else {

					list = "";

				}

			}

		},



		// Actual Callbacks object

		self = {



			// Add a callback or a collection of callbacks to the list

			add: function() {

				if ( list ) {



					// If we have memory from a past run, we should fire after adding

					if ( memory && !firing ) {

						firingIndex = list.length - 1;

						queue.push( memory );

					}



					( function add( args ) {

						jQuery.each( args, function( _, arg ) {

							if ( isFunction( arg ) ) {

								if ( !options.unique || !self.has( arg ) ) {

									list.push( arg );

								}

							} else if ( arg && arg.length && toType( arg ) !== "string" ) {



								// Inspect recursively

								add( arg );

							}

						} );

					} )( arguments );



					if ( memory && !firing ) {

						fire();

					}

				}

				return this;

			},



			// Remove a callback from the list

			remove: function() {

				jQuery.each( arguments, function( _, arg ) {

					var index;

					while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {

						list.splice( index, 1 );



						// Handle firing indexes

						if ( index <= firingIndex ) {

							firingIndex--;

						}

					}

				} );

				return this;

			},



			// Check if a given callback is in the list.

			// If no argument is given, return whether or not list has callbacks attached.

			has: function( fn ) {

				return fn ?

					jQuery.inArray( fn, list ) > -1 :

					list.length > 0;

			},



			// Remove all callbacks from the list

			empty: function() {

				if ( list ) {

					list = [];

				}

				return this;

			},



			// Disable .fire and .add

			// Abort any current/pending executions

			// Clear all callbacks and values

			disable: function() {

				locked = queue = [];

				list = memory = "";

				return this;

			},

			disabled: function() {

				return !list;

			},



			// Disable .fire

			// Also disable .add unless we have memory (since it would have no effect)

			// Abort any pending executions

			lock: function() {

				locked = queue = [];

				if ( !memory && !firing ) {

					list = memory = "";

				}

				return this;

			},

			locked: function() {

				return !!locked;

			},



			// Call all callbacks with the given context and arguments

			fireWith: function( context, args ) {

				if ( !locked ) {

					args = args || [];

					args = [ context, args.slice ? args.slice() : args ];

					queue.push( args );

					if ( !firing ) {

						fire();

					}

				}

				return this;

			},



			// Call all the callbacks with the given arguments

			fire: function() {

				self.fireWith( this, arguments );

				return this;

			},



			// To know if the callbacks have already been called at least once

			fired: function() {

				return !!fired;

			}

		};



	return self;

};



return jQuery;

} );

