 		myWindow.nativeWindow.addEventListener("close", cleanup);
 	}
 }
-}+}
+
+import flash.display.DisplayObject;
+import flash.events.IEventDispatcher;
+
+/**
+ * A form that exists in a SystemManager in another sandbox or compiled with
+ * a different version of Flex.
+ * 
+ * An instance of a RemotePopUp is put into the forms array of the top-level 
+ * System Manager so the top-level System Manager can manage the form's 
+ * activation/deactivation along with any other forms that are displayed.
+ */
+class RemotePopUp extends Object
+{
+	/**
+	 * Create new RemotePopUp. There are two kinds of remote pop ups. One for trusted
+	 * popups and one for untrusted popups. Trusted pop ups pass may pass display objects
+	 * and the bridge handle of the form. Untrusted pop ups may only pass a string id and
+	 * the bridge handle of the direct child.
+	 * 
+	 * @param window String if the form is a placeholder for an untrusted pop up. A display
+	 * object (SystemManagerProxy) if the form is trusted.
+	 * 
+	 * @param bridge If the form is trusted, the bridge handle of the source of the form.
+	 * If the form is untrusted, the bridge of the direct child of this application that parents
+	 * the source of the form. 
+	 */
+	public function RemotePopUp(window:Object, bridge:Object)
+	{
+		this.window = window;
+  		this.bridge = bridge;
+	}
+	
+	public var window:Object;		// SystemManagerProxy or String id of remote form
+	public var bridge:Object;		// bridge of remote form
+}
+
+import flash.events.EventDispatcher;
+import flash.events.IEventDispatcher;
+import flash.events.Event;
+import flash.events.MouseEvent;
+import mx.events.MarshalMouseEvent;
+import mx.utils.EventUtil;
+import mx.managers.WindowedSystemManager;
+
+/**
+ * An object that marshals events to other sandboxes
+ */
+class EventProxy extends EventDispatcher
+{
+	private var systemManager:WindowedSystemManager;
+
+	public function EventProxy(systemManager:WindowedSystemManager)
+	{
+		this.systemManager = systemManager;
+	}
+
+	public function marshalListener(event:Event):void
+	{
+		if (event is MouseEvent)
+		{
+			var me:MouseEvent = event as MouseEvent;;
+			var mme:MarshalMouseEvent = new MarshalMouseEvent(EventUtil.mouseEventMap[event.type],
+				false, false, me.ctrlKey, me.altKey, me.shiftKey, me.buttonDown);
+			// trace(">>marshalListener", systemManager, mme.type);
+			systemManager.dispatchEventToSandboxes(mme, null, true);
+			// trace("<<marshalListener", systemManager);
+		}
+	}
+
+}
+
+import flash.display.Stage;
+import flash.events.MouseEvent;
+
+/**
+ * An object that filters stage
+ */
+class StageEventProxy
+{
+	private var listener:Function;
+
+	public function StageEventProxy(listener:Function)
+	{
+		this.listener = listener;
+	}
+
+	public function stageListener(event:Event):void
+	{
+		if (event.target is Stage)
+			listener(event);
+	}
+
+}
+
+/**
+ * Simple class to track placeholders for RemotePopups.
+ */
+class PlaceholderData extends Object
+{
+	public function PlaceholderData(id:String, bridge:IEventDispatcher, data:Object)
+	{
+		this.id = id;
+		this.bridge = bridge;
+		this.data = data;
+	}
+	
+	public var id:String;				// id of string at this node in the display list
+	public var bridge:IEventDispatcher; // bridge to next child application
+	public var data:Object;				// either a popup or a bridge to the next application 
+}

		return super.contains(child);
	}

	// fake out mouseX/mouseY
	mx_internal var _mouseX:*;
	mx_internal var _mouseY:*;

        return bounds;
    }
 
	/**
	 * @private
	 * 
	 * Notify parent that a new window has been activated.
	 * 
	 * @param window window that was activated.
	 */
	mx_internal function fireActivatedWindowEvent(window:DisplayObject):void
	{
		var bridge:IEventDispatcher = sandboxBridgeGroup ? sandboxBridgeGroup.parentBridge : null;
		if (bridge)
		{
			var sbRoot:DisplayObject = getSandboxRoot();
			var sendToSbRoot:Boolean = sbRoot != this;
			var bridgeEvent:SandboxBridgeEvent = new SandboxBridgeEvent(SandboxBridgeEvent.ACTIVATE_WINDOW,
																	    false, false,
	       																bridge, 
	       																sendToSbRoot ? window :
	       																NameUtil.displayObjectToString(window));
	        if (sendToSbRoot)
	        	sbRoot.dispatchEvent(bridgeEvent);
			else
				bridge.dispatchEvent(bridgeEvent);
		}
		
	}

	/**
	 * @private
	 * 
	 * Notify parent that a window has been deactivated.
	 * 
	 * @param id window display object or id string that was activated. Ids are used if
	 * 		  the message is going outside the security domain.
	 */
	private function fireDeactivatedWindowEvent(window:DisplayObject):void
	{
		var bridge:IEventDispatcher = sandboxBridgeGroup ? sandboxBridgeGroup.parentBridge : null;
		if (bridge)
		{
			var sbRoot:DisplayObject = getSandboxRoot();
			var sendToSbRoot:Boolean = sbRoot != this;
			var bridgeEvent:SandboxBridgeEvent = new SandboxBridgeEvent(SandboxBridgeEvent.DEACTIVATE_WINDOW,
																	    false, 
																	    false,
	       																bridge, 
	       																sendToSbRoot ? window :
	       																NameUtil.displayObjectToString(window));
	        if (sendToSbRoot)
	        	sbRoot.dispatchEvent(bridgeEvent);
			else
				bridge.dispatchEvent(bridgeEvent);
		}
		
	}
	
	
	/**
	 * @private
	 * 
	 * Notify parent that an application has been activated.
	 */
	private function fireActivatedApplicationEvent():void
	{
		// click on this system manager or one of its sub system managers
		// If in a sandbox tell the top-level system manager we are active.
		var bridge:IEventDispatcher = sandboxBridgeGroup ? sandboxBridgeGroup.parentBridge : null;
		if (bridge)
		{
			var bridgeEvent:SandboxBridgeEvent = new SandboxBridgeEvent(SandboxBridgeEvent.ACTIVATE_APPLICATION,
																		false, false,
																		bridge);
			bridge.dispatchEvent(bridgeEvent);
		}
	}

	/**
	 * Adjust the forms array so it is sorted by last active. 
	 * The last active form will be at the end of the forms array.
	 * 
	 * This method assumes the form variable has been set before calling
	 * this function.
	 */
	private function updateLastActiveForm():void
	{
		// find "form" in the forms array and move that entry to 
		// the end of the array.
		var n:int = forms.length;
		if (n < 2)
			return;	// zero or one forms, no need to update
			
		var index:int = -1;
		for (var i:int = 0; i < n; i++)
		{
			if (areFormsEqual(form, forms[i]))
			{
				index = i;
				break;
			}
		}
		
		if (index >= 0)
		{
			forms.splice(index, 1);
			forms.push(form);
		}
		else
			throw new Error();	// should never get here
		
	}

	/**
	 * @private
	 * 
	 * Add placeholder information to this instance's list of placeholder data.
	 */ 	
	private function addPlaceholderId(id:String, previousId:String, bridge:IEventDispatcher, 
									  placeholder:Object):void
	{
		if (!bridge)
			throw new Error();	// bridge is required.
			
		if (!idToPlaceholder)
			idToPlaceholder = [];
			
		idToPlaceholder[id] = new PlaceholderData(previousId, bridge, placeholder);	
	}
	
	private function removePlaceholderId(id:String):void
	{
		delete idToPlaceholder[id];
	}

	private var currentSandboxEvent:Event;

	/**
	 * dispatch the event to all sandboxes except the specified one
	 */
	public function dispatchEventToSandboxes(event:Event, skip:IEventDispatcher = null, trackClones:Boolean = false):void
	{
		var clone:Event;
		// trace(">>dispatchEventToSandboxes", this, event.type);
		clone = event.clone();
		if (trackClones)
			currentSandboxEvent = clone;
		var parentBridge:IEventDispatcher = sandboxBridgeGroup.parentBridge;
		if (parentBridge && parentBridge != skip)
		{
			parentBridge.dispatchEvent(clone);
		}
		
		var children:Array = sandboxBridgeGroup.getChildBridges();
		for (var i:int = 0; i < children.length; i++)
		{
			if (children[i] != skip)
			{
				// trace("send to child", i, event.type);
				clone = event.clone();
				if (trackClones)
					currentSandboxEvent = clone;
				IEventDispatcher(children[i]).dispatchEvent(clone);
			}
		}
		currentSandboxEvent = null;

		// trace("<<dispatchEventToSandboxes", this, event.type);
	}

	/**
	 * request the parent to add an event listener.
	 */
	private function addEventListenerToSandboxes(type:String, listener:Function, useCapture:Boolean = false, 
				priority:int=0, useWeakReference:Boolean=false, skip:IEventDispatcher = null):void
	{
		// trace(">>addEventListenerToSandboxes", this, type);

		var request:EventListenerRequest = new EventListenerRequest(EventListenerRequest.ADD,
													type, 
													useCapture, 
													priority,
													useWeakReference);
		
		var parentBridge:IEventDispatcher = sandboxBridgeGroup.parentBridge;
		if (parentBridge)
		{
			parentBridge.addEventListener(type, listener, false, priority, useWeakReference);			
		}
		
		var children:Array = sandboxBridgeGroup.getChildBridges();
		for (var i:int; i < children.length; i++)
		{
		 	var childBridge:IEventDispatcher = IEventDispatcher(children[i]);
			childBridge.addEventListener(type, listener, false, priority, useWeakReference);			
		}
		
		dispatchEventToSandboxes(request, skip);
		// trace("<<addEventListenerToSandboxes", this, type);
	}

	/**
	 * request the parent to remove an event listener.
	 */	
	private function removeEventListenerFromSandboxes(type:String, listener:Function, 
	                                                  useCapture:Boolean = false,
	                                                  skip:IEventDispatcher = null):void 
	{
		// trace(">>removeEventListenerToSandboxes", this, type);
		var request:EventListenerRequest = new EventListenerRequest(EventListenerRequest.REMOVE,
																				type, 
																				useCapture);
		var parentBridge:IEventDispatcher = sandboxBridgeGroup.parentBridge;
		if (parentBridge)
			parentBridge.removeEventListener(type, listener, useCapture);
		
		var children:Array = sandboxBridgeGroup.getChildBridges();
		for (var i:int; i < children.length; i++)
		{
			IEventDispatcher(children[i]).removeEventListener(type, listener, useCapture);			
		}
		
		dispatchEventToSandboxes(request, skip);
		// trace("<<removeEventListenerToSandboxes", this, type);
	}

    /**
     *   @private
     * 
     *   @return true if the message should be processed, false if 
     *   no other action is required.
     */ 
    private function preProcessModalWindowRequest(request:ModalWindowRequest, 
                                                  sm:ISystemManager2,
                                                  sbRoot:DisplayObject):Boolean
    {
        // should we process this message?
        if (request.skip)
        {
            // skipping this sandbox, 
            // but don't skip the next one.
            request.skip = false;
           
            if (sm.useBridge())
            {
                var bridge:IEventDispatcher = sm.sandboxBridgeGroup.parentBridge;
                request.requestor = bridge;
                bridge.dispatchEvent(request);
            }
            return false;
        }
        
        // if we are not the sandbox root, dispatch the message to the sandbox root.
        if (sm != sbRoot)
        {
            var forwardRequest:Boolean = false;

            // convert exclude component into a rectangle and forward to parent bridge.
            if (request.type == ModalWindowRequest.CREATE ||
                request.type == ModalWindowRequest.SHOW)
            {
                var exclude:IApplicationLoader = sm.sandboxBridgeGroup.getChildBridgeOwner(request.requestor) 
                                                 as IApplicationLoader;
                var excludeRect:Rectangle = IApplicationLoader(exclude).getVisibleApplicationRect();
                request.data = excludeRect;
                forwardRequest = true;
            }
            else if (request.type == ModalWindowRequest.HIDE)
                forwardRequest = true;
                
            if (forwardRequest)
            {
                bridge = sm.sandboxBridgeGroup.parentBridge;
                request.requestor = bridge;
         
                // The HIDE request does not need to be processed by each
                // application, so dispatch it directly to the sandbox root.       
                if (request.type == ModalWindowRequest.HIDE)
                    sbRoot.dispatchEvent(request);
                else 
                    bridge.dispatchEvent(request);
                return false;
            }
        }

        // skip aftering sending the message over a bridge.
        request.skip = false;
                
        return true;
    }    
    

	private function sandboxMouseListener(event:Event):void
	{
		// trace("sandboxMouseListener", this);
		if (event is MarshalMouseEvent)
			return;

		var marshaledEvent:Event = MarshalMouseEvent.marshal(event);
		dispatchEventToSandboxes(marshaledEvent, event.target as IEventDispatcher);

		// ask the sandbox root if it was the original dispatcher of this event
		// if it was then don't dispatch to ourselves because we could have
		// got this event by listening to sandboxRoot ourselves.
		var me:MarshalEvent = new MarshalEvent(MarshalEvent.SYSTEM_MANAGER);
		me.name = "sameSandbox";
		me.value = event;
		getSandboxRoot().dispatchEvent(me);

		if (!me.value)
			dispatchEvent(marshaledEvent);
	}

	private function eventListenerRequestHandler(event:Event):void
	{
		if (event is EventListenerRequest)
			return;

        var actualType:String;
		var eventObj:Object = event;
		if (event.type == EventListenerRequest.ADD)
		{
			if (!eventProxy)
				eventProxy = new EventProxy(this);
			
			// trace(">>eventListenerRequestHandler ADD ", this, eventObj.userType);

			actualType = EventUtil.marshalMouseEventMap[eventObj.userType];
			if (actualType)
			{
				addEventListenerToSandboxes(eventObj.userType, sandboxMouseListener,
							eventObj.useCapture, eventObj.priority, eventObj.useWeakReference, event.target as IEventDispatcher);
				if (getSandboxRoot() == this)
					super.addEventListener(actualType, eventProxy.marshalListener,
							eventObj.useCapture, eventObj.priority, eventObj.useWeakReference);
			}
			// trace("<<eventListenerRequestHandler ADD ", this, eventObj.userType);
		}
		else if (event.type == EventListenerRequest.REMOVE)
        {
            // trace(">>eventListenerRequestHandler REMOVE ", this, eventObj.userType);
            actualType = EventUtil.marshalMouseEventMap[eventObj.userType];
            if (actualType)
            {
                removeEventListenerFromSandboxes(eventObj.userType, sandboxMouseListener,
                            eventObj.useCapture, event.target as IEventDispatcher);
                if (getSandboxRoot() == this)
                    super.removeEventListener(actualType, eventProxy.marshalListener,
                            eventObj.useCapture);
            }
            // trace("<<eventListenerRequestHandler REMOVE ", this, eventObj.userType);
        }		
	}
 
	
	/**
	 *  Returns <code>true</code> if the given DisplayObject is the 
