 			// remove the callback if it was previously added
 			removeCallback(callback);
 			
-			var entry:CallbackEntry = new CallbackEntry();
-			_callbackEntries.push(entry);
-			entry.context = relevantContext;
-			entry.callback = callback;
-			entry.recursionLimit = 0;
+			var entry:CallbackEntry = new CallbackEntry(relevantContext, callback);
 			if (alwaysCallLast)
 				entry.schedule = 1;
-			
-			if (debug)
-				entry.addCallback_stackTrace = new Error(STACK_TRACE_ADD).getStackTrace();
+			_callbackEntries.push(entry);
 
 			// run callback now if requested
 			if (runCallbackNow)

		 */
		private var _triggerCounter:uint = DEFAULT_TRIGGER_COUNT;
		
		private static const STACK_TRACE_TRIGGER:String = "This is the stack trace from when the callbacks were last triggered.";
		private static const STACK_TRACE_ADD:String = "This is the stack trace from when the callback was added.";
		private static const STACK_TRACE_REMOVE:String = "This is the stack trace from when the callback was removed.";
		
		/**
		 * @inheritDoc
		 */

	 */
	public var removeCallback_stackTrace:String = null;
}

/**
 * @private
 */
internal class GroupedCallbackEntry extends CallbackEntry
{
	public static function addGroupedCallback(callbackCollection:ICallbackCollection, relevantContext:Object, groupedCallback:Function, triggerCallbackNow:Boolean):void
	{
		// get (or create) the shared entry for the groupedCallback
		var entry:GroupedCallbackEntry = _entryLookup[groupedCallback] as GroupedCallbackEntry;
		if (!entry)
			_entryLookup[groupedCallback] = entry = new GroupedCallbackEntry(groupedCallback);
		
		// context shouldn't be null because we use it to determine when to clean up the GroupedCallbackEntry.
		if (relevantContext == null)
			relevantContext = callbackCollection;
		
		// add this context to the list of relevant contexts
		(entry.context as Array).push(relevantContext);
		
		// make sure the actual function is not already added as a callback.
		callbackCollection.removeCallback(groupedCallback);
		
		// add the trigger function as a callback
		callbackCollection.addImmediateCallback(relevantContext, entry.trigger, triggerCallbackNow);
	}
	
	public static function removeGroupedCallback(callbackCollection:ICallbackCollection, groupedCallback:Function):void
	{
		// remove the trigger function as a callback
		var entry:GroupedCallbackEntry = _entryLookup[groupedCallback] as GroupedCallbackEntry;
		if (entry)
			callbackCollection.removeCallback(entry.trigger);
	}
	
	/**
	 * This function gets called once per frame and allows grouped callbacks to run.
	 */
	public static function _handleGroupedCallbacks():void
	{
		// handle grouped callbacks in the order they were triggered
		while (_triggeredEntries.length)
			(_triggeredEntries.shift() as GroupedCallbackEntry).handleGroupedCallback();
	}
	
	/**
	 * This gets set to true when the static _handleGroupedCallbacks() callback has been added as a frame listener.
	 */
	private static var _initialized:Boolean = false;
	
	/**
	 * This maps a groupedCallback function to its corresponding GroupedCallbackEntry.
	 */
	private static const _entryLookup:Dictionary = new Dictionary();
	
	/**
	 * This is a list of GroupedCallbackEntry objects in the order they were triggered.
	 */		
	private static const _triggeredEntries:Array = [];
	
	/**
	 * Constructor
	 */
	public function GroupedCallbackEntry(groupedCallback:Function)
	{
		// context will be an array of contexts
		super([], groupedCallback);
		
		if (!_initialized)
		{
			WeaveAPI.StageUtils.addEventCallback(Event.ENTER_FRAME, null, _handleGroupedCallbacks);
			_initialized = true;
		}
	}
	
	/**
	 * If true, the callback was triggered this frame.
	 */
	public var triggered:Boolean = false;
	
	/**
	 * Marks the entry to be handled later (unless already triggered this frame).
	 * This also takes care of preventing recursion.
	 */
	public function trigger():void
	{
		if (!triggered)
		{
			_triggeredEntries.push(this);
			triggered = true;
		}
	}
	
	/**
	 * Checks the context(s) before calling groupedCallback
	 */
	public function handleGroupedCallback():void
	{
		// first, make sure there is at least one relevant context for this callback.
		var allContexts:Array = context as Array;
		// remove the contexts that have been disposed of.
		for (var i:int = 0; i < allContexts.length; i++)
			if (WeaveAPI.SessionManager.objectWasDisposed(allContexts[i]))
				allContexts.splice(i--, 1);
		// if there are no more relevant contexts for this callback, don't run it.
		if (allContexts.length == 0)
		{
			if (CallbackCollection.debug)
				removeCallback_stackTrace = new Error(STACK_TRACE_REMOVE).getStackTrace();
			// clean up and remove this entry
			callback = null; // help the garbage-collector a bit
			delete _entryLookup[callback];
			return;
		}
		
		callback();
		
		// to avoid recursion, reset triggered state as the very last step
		triggered = false;
	}
}
