 		/**
 		 * This maps a ChangeWatcher object to a function that was added as a callback to the corresponding ILinkableVariable.
 		 */
-		private const _watcherToSynchronizeFunctionMap:Dictionary = new Dictionary(); // use weak links to be GC-friendly
-		
-		
-		
-		
-		
-		/*******************
-		 * Computing diffs
-		 *******************/
-		
-		
-		internal static const DIFF_DELETE:String = 'delete';
-		
-		/**
-		 * This function computes the diff of two session states.
-		 * @param oldState The source session state.
-		 * @param newState The destination session state.
-		 * @return A patch that generates the destination session state when applied to the source session state, or undefined if the two states are equivalent.
-		 */
-		public function computeDiff(oldState:Object, newState:Object):*
-		{
-			var type:String = typeof(oldState); // the type of null is 'object'
-			var diffValue:*;
-
-			// special case if types differ
-			if (typeof(newState) != type)
-				return newState;
-			
-			if (type == 'xml')
-			{
-				throw new Error("XML is not supported as a primitive session state type.");
-			}
-			else if (type == 'number')
-			{
-				if (isNaN(oldState as Number) && isNaN(newState as Number))
-					return undefined; // no diff
-				
-				if (oldState != newState)
-					return newState;
-				
-				return undefined; // no diff
-			}
-			else if (oldState === null || newState === null || type != 'object') // other primitive value
-			{
-				if (oldState !== newState) // no type-casting
-					return newState;
-				
-				return undefined; // no diff
-			}
-			else if (oldState is Array && newState is Array)
-			{
-				// create an array of new DynamicState objects for all new names followed by missing old names
-				var i:int;
-				var typedState:Object;
-				var changeDetected:Boolean = false;
-				
-				// create oldLookup
-				var oldLookup:Object = {};
-				var objectName:String;
-				var className:String;
-				var sessionState:Object;
-				for (i = 0; i < oldState.length; i++)
-				{
-					typedState = oldState[i];
-					
-					// if we see a string, assume both are String Arrays.
-					if (typedState is String || typedState is Array)
-					{
-						if (StandardLib.arrayCompare(oldState as Array, newState as Array) == 0)
-							return undefined; // no diff
-						return newState;
-					}
-					
-					//note: there is no error checking here for typedState
-					objectName = typedState[DynamicState.OBJECT_NAME];
-					// use '' instead of null to avoid "null"
-					oldLookup[objectName || ''] = typedState;
-				}
-				if (oldState.length != newState.length)
-					changeDetected = true;
-				
-				// create new Array with new DynamicState objects
-				var result:Array = [];
-				for (i = 0; i < newState.length; i++)
-				{
-					typedState = newState[i];
-					
-					// if we see a string, assume both are String Arrays.
-					if (typedState is String || typedState is Array)
-					{
-						if (StandardLib.arrayCompare(oldState as Array, newState as Array) == 0)
-							return undefined; // no diff
-						return newState; // TODO: same object pointer.. potential problem?
-					}
-					
-					//note: there is no error checking here for typedState
-					objectName = typedState[DynamicState.OBJECT_NAME];
-					className = typedState[DynamicState.CLASS_NAME];
-					sessionState = typedState[DynamicState.SESSION_STATE];
-					var oldTypedState:Object = oldLookup[objectName || ''];
-					delete oldLookup[objectName || '']; // remove it from the lookup because it's already been handled
-					
-					// If the object specified in newState does not exist in oldState, we don't need to do anything further.
-					// If the class is the same as before, then we can save a diff instead of the entire session state.
-					// If the class changed, we can't save only a diff -- we need to keep the entire session state.
-					// Replace the sessionState in the new DynamicState object with the diff.
-					if (oldTypedState != null && oldTypedState[DynamicState.CLASS_NAME] == className)
-					{
-						className = null; // no change
-						diffValue = computeDiff(oldTypedState[DynamicState.SESSION_STATE], sessionState);
-						if (diffValue === undefined)
-						{
-							// Since the class name is the same and the session state is the same,
-							// we only need to specify that this name is still present.
-							result.push(objectName);
-							
-							if (!changeDetected && oldState[i][DynamicState.OBJECT_NAME] != objectName)
-								changeDetected = true;
-							
-							continue;
-						}
-						sessionState = diffValue;
-					}
-					
-					// save in new array and remove from lookup
-					result.push(new DynamicState(objectName, className, sessionState));
-					changeDetected = true;
-				}
-				
-				// Anything remaining in the lookup does not appear in newState.
-				// Add DynamicState entries with an invalid className ("delete") to convey that each of these objects should be removed.
-				for (objectName in oldLookup)
-				{
-					result.push(new DynamicState(objectName, DIFF_DELETE));
-					changeDetected = true;
-				}
-				
-				if (changeDetected)
-					return result;
-				
-				return undefined; // no diff
-			}
-			else // nested object
-			{
-				var diff:* = undefined; // start with no diff
-				
-				// find old properties that changed value
-				for (var oldName:String in oldState)
-				{
-					diffValue = computeDiff(oldState[oldName], newState[oldName]);
-					if (diffValue !== undefined)
-					{
-						if (!diff)
-							diff = {};
-						diff[oldName] = diffValue;
-					}
-				}
-
-				// find new properties
-				for (var newName:String in newState)
-				{
-					if (oldState[newName] === undefined)
-					{
-						if (!diff)
-							diff = {};
-						diff[newName] = newState[newName]; // TODO: same object pointer.. potential problem?
-					}
-				}
-
-				return diff;
-			}
-		}
-		
-		/**
-		 * This modifies an existing diff to include an additional diff.
-		 * @param baseDiff The base diff which will be modified to include an additional diff.
-		 * @param diffToAdd The diff to add to the base diff.  This diff will not be modified.
-		 * @return The modified baseDiff, or a new diff object if baseDiff is a primitive value.
-		 */
-		public function combineDiff(baseDiff:Object, diffToAdd:Object):Object
-		{
-			// special case for no change
-			if (diffToAdd === null)
-				return baseDiff;
-			
-			var baseType:String = typeof(baseDiff); // the type of null is 'object'
-			var diffType:String = typeof(diffToAdd);
-
-			// special cases
-			if (baseDiff == null || baseType != diffType || baseType != 'object')
-			{
-				if (diffType == 'object') // not a primitive, so make a copy
-					baseDiff = ObjectUtil.copy(diffToAdd);
-				else
-					baseDiff = diffToAdd;
-			}
-			else if (baseDiff is Array && diffToAdd is Array)
-			{
-				var typedState:Object;
-				var i:int;
-				
-				// If a non-String, non-Array is found, treat both as Arrays of DynamicState objects
-				var isTyped:Boolean = false;
-				checkArrays: for each (var array:Array in arguments) // [baseDiff, diffToAdd]
-				{
-					for each (typedState in array)
-					{
-						if (!(typedState is String || typedState is Array))
-						{
-							isTyped = true;
-							break checkArrays;
-						}
-					}
-				}
-				if (isTyped)
-				{
-					var objectName:String;
-
-					// create lookup: objectName -> old diff entry
-					// temporarily turn baseDiff into an Array of object names
-					var baseLookup:Object = {};
-					for (i = 0; i < baseDiff.length; i++)
-					{
-						typedState = baseDiff[i];
-						// note: no error checking for typedState
-						if (typedState is String || typedState == null)
-							objectName = typedState as String;
-						else
-							objectName = typedState[DynamicState.OBJECT_NAME] as String;
-						baseLookup[objectName] = typedState;
-						// temporarily turn baseDiff into an Array of object names
-						baseDiff[i] = objectName;
-					}
-					// apply each typedState diff appearing in diffToAdd
-					for (i = 0; i < diffToAdd.length; i++)
-					{
-						typedState = diffToAdd[i];
-						// note: no error checking for typedState
-						if (typedState is String || typedState == null)
-							objectName = typedState as String;
-						else
-							objectName = typedState[DynamicState.OBJECT_NAME] as String;
-						
-						// adjust names list so this name appears at the end
-						if (baseLookup.hasOwnProperty(objectName))
-						{
-							for (var j:int = (baseDiff as Array).indexOf(objectName); j < baseDiff.length - 1; j++)
-								baseDiff[j] = baseDiff[j + 1];
-							baseDiff[baseDiff.length - 1] = objectName;
-						}
-						else
-						{
-							baseDiff.push(objectName);
-						}
-						
-						// apply diff
-						var oldTypedState:Object = baseLookup[objectName];
-						if (oldTypedState is String || oldTypedState == null)
-						{
-							if (typedState is String || typedState == null)
-								baseLookup[objectName] = typedState; // avoid unnecessary function call overhead
-							else
-								baseLookup[objectName] = ObjectUtil.copy(typedState);
-						}
-						else if (!(typedState is String || typedState == null)) // update dynamic state
-						{
-							var className:String = typedState[DynamicState.CLASS_NAME];
-							// if new className is different and not null, start with a fresh typedState diff
-							if (className && className != oldTypedState[DynamicState.CLASS_NAME])
-							{
-								baseLookup[objectName] = ObjectUtil.copy(typedState);
-							}
-							else // className hasn't changed, so combine the diffs
-							{
-								oldTypedState[DynamicState.SESSION_STATE] = combineDiff(oldTypedState[DynamicState.SESSION_STATE], typedState[DynamicState.SESSION_STATE]);
-							}
-						}
-					}
-					// change baseDiff back from names to typed states
-					for (i = 0; i < baseDiff.length; i++)
-						baseDiff[i] = baseLookup[baseDiff[i]];
-				}
-				else // not typed session state
-				{
-					// overwrite old Array with new Array's values
-					baseDiff.length = diffToAdd.length;
-					for (i = diffToAdd.length - 1; i >= 0; i--)
-					{
-						var value:Object = diffToAdd[i];
-						if (value is String)
-							baseDiff[i] = value; // avoid function call overhead
-						else
-							baseDiff[i] = combineDiff(baseDiff[i], value);
-					}
-				}
-			}
-			else // nested object
-			{
-				for (var newName:String in diffToAdd)
-					baseDiff[newName] = combineDiff(baseDiff[newName], diffToAdd[newName]);
-			}
-			
-			return baseDiff;
+		private const _watcherToSynchronizeFunctionMap:Dictionary = new Dictionary(); // use weak links to be GC-friendly
+		
+		
+		
+		
+		
+		/*******************
+		 * Computing diffs
+		 *******************/
+		
+		
+		internal static const DIFF_DELETE:String = 'delete';
+		
+		/**
+		 * This function computes the diff of two session states.
+		 * @param oldState The source session state.
+		 * @param newState The destination session state.
+		 * @return A patch that generates the destination session state when applied to the source session state, or undefined if the two states are equivalent.
+		 */
+		public function computeDiff(oldState:Object, newState:Object):*
+		{
+			var type:String = typeof(oldState); // the type of null is 'object'
+			var diffValue:*;
+
+			// special case if types differ
+			if (typeof(newState) != type)
+				return newState;
+			
+			if (type == 'xml')
+			{
+				throw new Error("XML is not supported as a primitive session state type.");
+			}
+			else if (type == 'number')
+			{
+				if (isNaN(oldState as Number) && isNaN(newState as Number))
+					return undefined; // no diff
+				
+				if (oldState != newState)
+					return newState;
+				
+				return undefined; // no diff
+			}
+			else if (oldState === null || newState === null || type != 'object') // other primitive value
+			{
+				if (oldState !== newState) // no type-casting
+					return newState;
+				
+				return undefined; // no diff
+			}
+			else if (oldState is Array && newState is Array)
+			{
+				// create an array of new DynamicState objects for all new names followed by missing old names
+				var i:int;
+				var typedState:Object;
+				var changeDetected:Boolean = false;
+				
+				// create oldLookup
+				var oldLookup:Object = {};
+				var objectName:String;
+				var className:String;
+				var sessionState:Object;
+				for (i = 0; i < oldState.length; i++)
+				{
+					typedState = oldState[i];
+					
+					// if we see a string in oldState, assume both oldState and newState are String Arrays.
+					if (typedState is String || typedState is Array)
+					{
+						if (StandardLib.arrayCompare(oldState as Array, newState as Array) == 0)
+							return undefined; // no diff
+						return newState;
+					}
+					
+					//note: there is no error checking here for typedState
+					objectName = typedState[DynamicState.OBJECT_NAME];
+					// use '' instead of null to avoid "null"
+					oldLookup[objectName || ''] = typedState;
+				}
+				if (oldState.length != newState.length)
+					changeDetected = true;
+				
+				// create new Array with new DynamicState objects
+				var result:Array = [];
+				for (i = 0; i < newState.length; i++)
+				{
+					typedState = newState[i];
+					
+					// if we see a string, assume both are String Arrays.
+					if (typedState is String || typedState is Array)
+					{
+						if (StandardLib.arrayCompare(oldState as Array, newState as Array) == 0)
+							return undefined; // no diff
+						return newState; // TODO: same object pointer.. potential problem?
+					}
+					
+					// assume everthing is typed session state
+					//note: there is no error checking here for typedState
+					objectName = typedState[DynamicState.OBJECT_NAME];
+					className = typedState[DynamicState.CLASS_NAME];
+					sessionState = typedState[DynamicState.SESSION_STATE];
+					var oldTypedState:Object = oldLookup[objectName || ''];
+					delete oldLookup[objectName || '']; // remove it from the lookup because it's already been handled
+					
+					// If the object specified in newState does not exist in oldState, we don't need to do anything further.
+					// If the class is the same as before, then we can save a diff instead of the entire session state.
+					// If the class changed, we can't save only a diff -- we need to keep the entire session state.
+					// Replace the sessionState in the new DynamicState object with the diff.
+					if (oldTypedState != null && oldTypedState[DynamicState.CLASS_NAME] == className)
+					{
+						className = null; // no change
+						diffValue = computeDiff(oldTypedState[DynamicState.SESSION_STATE], sessionState);
+						if (diffValue === undefined)
+						{
+							// Since the class name is the same and the session state is the same,
+							// we only need to specify that this name is still present.
+							result.push(objectName);
+							
+							if (!changeDetected && oldState[i][DynamicState.OBJECT_NAME] != objectName)
+								changeDetected = true;
+							
+							continue;
+						}
+						sessionState = diffValue;
+					}
+					
+					// save in new array and remove from lookup
+					result.push(new DynamicState(objectName, className, sessionState));
+					changeDetected = true;
+				}
+				
+				// Anything remaining in the lookup does not appear in newState.
+				// Add DynamicState entries with an invalid className ("delete") to convey that each of these objects should be removed.
+				for (objectName in oldLookup)
+				{
+					result.push(new DynamicState(objectName, DIFF_DELETE));
+					changeDetected = true;
+				}
+				
+				if (changeDetected)
+					return result;
+				
+				return undefined; // no diff
+			}
+			else // nested object
+			{
+				var diff:* = undefined; // start with no diff
+				
+				// find old properties that changed value
+				for (var oldName:String in oldState)
+				{
+					diffValue = computeDiff(oldState[oldName], newState[oldName]);
+					if (diffValue !== undefined)
+					{
+						if (!diff)
+							diff = {};
+						diff[oldName] = diffValue;
+					}
+				}
+
+				// find new properties
+				for (var newName:String in newState)
+				{
+					if (oldState[newName] === undefined)
+					{
+						if (!diff)
+							diff = {};
+						diff[newName] = newState[newName]; // TODO: same object pointer.. potential problem?
+					}
+				}
+
+				return diff;
+			}
+		}
+		
+		/**
+		 * This modifies an existing diff to include an additional diff.
+		 * @param baseDiff The base diff which will be modified to include an additional diff.
+		 * @param diffToAdd The diff to add to the base diff.  This diff will not be modified.
+		 * @return The modified baseDiff, or a new diff object if baseDiff is a primitive value.
+		 */
+		public function combineDiff(baseDiff:Object, diffToAdd:Object):Object
+		{
+			var baseType:String = typeof(baseDiff); // the type of null is 'object'
+			var diffType:String = typeof(diffToAdd);
+
+			// special cases
+			if (baseDiff == null || diffToAdd == null || baseType != diffType || baseType != 'object')
+			{
+				if (diffType == 'object') // not a primitive, so make a copy
+					baseDiff = ObjectUtil.copy(diffToAdd);
+				else
+					baseDiff = diffToAdd;
+			}
+			else if (baseDiff is Array && diffToAdd is Array)
+			{
+				var typedState:Object;
+				var i:int;
+				
+				// If a non-String, non-Array is found, treat both as Arrays of DynamicState objects
+				var isTyped:Boolean = false;
+				checkArrays: for each (var array:Array in arguments) // [baseDiff, diffToAdd]
+				{
+					for each (typedState in array)
+					{
+						if (!(typedState is String || typedState is Array))
+						{
+							isTyped = true;
+							break checkArrays;
+						}
+					}
+				}
+				if (isTyped)
+				{
+					var objectName:String;
+
+					// create lookup: objectName -> old diff entry
+					// temporarily turn baseDiff into an Array of object names
+					var baseLookup:Object = {};
+					for (i = 0; i < baseDiff.length; i++)
+					{
+						typedState = baseDiff[i];
+						// note: no error checking for typedState
+						if (typedState is String || typedState == null)
+							objectName = typedState as String;
+						else
+							objectName = typedState[DynamicState.OBJECT_NAME] as String;
+						baseLookup[objectName] = typedState;
+						// temporarily turn baseDiff into an Array of object names
+						baseDiff[i] = objectName;
+					}
+					// apply each typedState diff appearing in diffToAdd
+					for (i = 0; i < diffToAdd.length; i++)
+					{
+						typedState = diffToAdd[i];
+						// note: no error checking for typedState
+						if (typedState is String || typedState == null)
+							objectName = typedState as String;
+						else
+							objectName = typedState[DynamicState.OBJECT_NAME] as String;
+						
+						// adjust names list so this name appears at the end
+						if (baseLookup.hasOwnProperty(objectName))
+						{
+							for (var j:int = (baseDiff as Array).indexOf(objectName); j < baseDiff.length - 1; j++)
+								baseDiff[j] = baseDiff[j + 1];
+							baseDiff[baseDiff.length - 1] = objectName;
+						}
+						else
+						{
+							baseDiff.push(objectName);
+						}
+						
+						// apply diff
+						var oldTypedState:Object = baseLookup[objectName];
+						if (oldTypedState is String || oldTypedState == null)
+						{
+							if (typedState is String || typedState == null)
+								baseLookup[objectName] = typedState; // avoid unnecessary function call overhead
+							else
+								baseLookup[objectName] = ObjectUtil.copy(typedState);
+						}
+						else if (!(typedState is String || typedState == null)) // update dynamic state
+						{
+							var className:String = typedState[DynamicState.CLASS_NAME];
+							// if new className is different and not null, start with a fresh typedState diff
+							if (className && className != oldTypedState[DynamicState.CLASS_NAME])
+							{
+								baseLookup[objectName] = ObjectUtil.copy(typedState);
+							}
+							else // className hasn't changed, so combine the diffs
+							{
+								oldTypedState[DynamicState.SESSION_STATE] = combineDiff(oldTypedState[DynamicState.SESSION_STATE], typedState[DynamicState.SESSION_STATE]);
+							}
+						}
+					}
+					// change baseDiff back from names to typed states
+					for (i = 0; i < baseDiff.length; i++)
+						baseDiff[i] = baseLookup[baseDiff[i]];
+				}
+				else // not typed session state
+				{
+					// overwrite old Array with new Array's values
+					baseDiff.length = diffToAdd.length;
+					for (i = diffToAdd.length - 1; i >= 0; i--)
+					{
+						var value:Object = diffToAdd[i];
+						if (value is String)
+							baseDiff[i] = value; // avoid function call overhead
+						else
+							baseDiff[i] = combineDiff(baseDiff[i], value);
+					}
+				}
+			}
+			else // nested object
+			{
+				for (var newName:String in diffToAdd)
+					baseDiff[newName] = combineDiff(baseDiff[newName], diffToAdd[newName]);
+			}
+			
+			return baseDiff;
+		}
+		
+		public function testDiff():void
+		{
+			var states:Array = [
+				[
+					{objectName: 'a', className: 'aClass', sessionState: 'aVal'},
+					{objectName: 'b', className: 'bClass', sessionState: 'bVal1'}
+				],
+				[
+					{objectName: 'b', className: 'bClass', sessionState: 'bVal2'},
+					{objectName: 'a', className: 'aClass', sessionState: 'aVal'}
+				],
+				[
+					{objectName: 'a', className: 'aNewClass', sessionState: 'aVal'},
+					{objectName: 'b', className: 'bClass', sessionState: null}
+				],
+				[
+					{objectName: 'b', className: 'bClass', sessionState: null}
+				]
+			];
+			var diffs:Array = [];
+			var combined:Array = [];
+			var baseDiff:* = null;
+			for (var i:int = 1; i < states.length; i++)
+			{
+				var diff:* = computeDiff(states[i - 1], states[i]);
+				diffs.push(diff);
+				baseDiff = combineDiff(baseDiff, diff);
+				combined.push(ObjectUtil.copy(baseDiff));
+			}
+			trace('diffs',ObjectUtil.toString(diffs));
+			trace('combined',ObjectUtil.toString(combined));
 		}
 	}
 }

		 */
		public function disposeObjects(object:Object, ...moreObjects):void
		{
			if (object != null && !_disposedObjectsMap[object])
			{
				_disposedObjectsMap[object] = true;
				
				try
				{

			var objectCC:ICallbackCollection = getCallbackCollection(linkableObject);
			objectCC.delayCallbacks();

			// set session state
			var name:String;
			for each (name in getLinkablePropertyNames(linkableObject))
			{
				if (!newState.hasOwnProperty(name))
