You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by cf...@apache.org on 2012/06/18 20:10:25 UTC

svn commit: r1351437 [4/12] - in /incubator/flex/trunk/frameworks/projects: automation_agent/ automation_agent/bundles/ automation_agent/bundles/da_DK/ automation_agent/bundles/de_DE/ automation_agent/bundles/en_US/ automation_agent/bundles/es_ES/ auto...

Added: incubator/flex/trunk/frameworks/projects/automation_agent/src/mx/automation/AutomationManager.as
URL: http://svn.apache.org/viewvc/incubator/flex/trunk/frameworks/projects/automation_agent/src/mx/automation/AutomationManager.as?rev=1351437&view=auto
==============================================================================
--- incubator/flex/trunk/frameworks/projects/automation_agent/src/mx/automation/AutomationManager.as (added)
+++ incubator/flex/trunk/frameworks/projects/automation_agent/src/mx/automation/AutomationManager.as Mon Jun 18 18:10:20 2012
@@ -0,0 +1,5119 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.automation
+{
+	import flash.display.DisplayObject;
+	import flash.display.DisplayObjectContainer;
+	import flash.display.Stage;
+	import flash.events.Event;
+	import flash.events.EventDispatcher;
+	import flash.events.FocusEvent;
+	import flash.events.IEventDispatcher;
+	import flash.events.KeyboardEvent;
+	import flash.events.MouseEvent;
+	import flash.geom.Point;
+	import flash.system.ApplicationDomain;
+	import flash.utils.Dictionary;
+	import flash.utils.clearTimeout;
+	import flash.utils.getDefinitionByName;
+	import flash.utils.getQualifiedClassName;
+	import flash.utils.getQualifiedSuperclassName;
+	import flash.utils.setTimeout;
+	
+	import mx.automation.delegates.DragManagerAutomationImpl;
+	import mx.automation.events.AutomationAirEvent;
+	import mx.automation.events.AutomationEvent;
+	import mx.automation.events.AutomationRecordEvent;
+	import mx.automation.events.AutomationReplayEvent;
+	import mx.automation.events.EventDetails;
+	import mx.automation.events.MarshalledAutomationEvent;
+	import mx.controls.Alert;
+	import mx.core.Application;
+	import mx.core.Container;
+	import mx.core.EventPriority;
+	import mx.core.IChildList;
+	import mx.core.IDeferredInstantiationUIComponent;
+	import mx.core.IFlexModuleFactory;
+	import mx.core.IRawChildrenContainer;
+	import mx.core.ISWFBridgeProvider;
+	import mx.core.IUIComponent;
+	import mx.core.UIComponent;
+	import mx.core.mx_internal;
+	import mx.events.DragEvent;
+	import mx.events.FlexChangeEvent;
+	import mx.events.FlexEvent;
+	import mx.events.InterManagerRequest;
+	import mx.events.SandboxMouseEvent;
+	import mx.managers.IMarshalSystemManager;
+	import mx.managers.ISystemManager;
+	import mx.managers.SystemManager;
+	import mx.managers.SystemManagerProxy;
+	import mx.modules.ModuleManager;
+	import mx.resources.IResourceManager;
+	import mx.resources.ResourceManager;
+	import mx.styles.IStyleClient;
+
+	use namespace mx_internal;
+	[Mixin]
+ 
+[ResourceBundle("automation_agent")]
+			
+/**
+ *  Provides the interface for manipulating the automation hierarchy,
+ *  and for recording and replaying events.
+ *  
+ *  @langversion 3.0
+ *  @playerversion Flash 9
+ *  @playerversion AIR 1.1
+ *  @productversion Flex 3
+ */         
+public class AutomationManager extends EventDispatcher
+	   implements IAutomationManager2, IAutomationObjectHelper, 
+	   IAutomationMouseSimulator, IAutomationDebugTracer
+{
+    include "../core/Version.as";
+ 
+
+
+	//--------------------------------------------------------------------------
+	//
+	//  Class constants
+	//
+	//--------------------------------------------------------------------------
+
+    /**
+     *  @private
+     */
+	private static const MOUSE_CLICK_TYPES:Array = [ MouseEvent.MOUSE_OVER,
+                                                     MouseEvent.MOUSE_DOWN,
+                                                     MouseEvent.MOUSE_UP,
+                                                     MouseEvent.CLICK ];
+
+    /**
+     *  @private
+     */
+	private static const KEY_CLICK_TYPES:Array = [ KeyboardEvent.KEY_DOWN,
+                                                   KeyboardEvent.KEY_UP ];
+
+	//--------------------------------------------------------------------------
+	//
+	//  Class variables
+	//
+	//--------------------------------------------------------------------------
+
+    /**
+     *  @private
+     *  Dictionary of all app domains/systemManagers
+     */
+	private static var allSystemManagers:Dictionary = new Dictionary(true);
+	
+	/**
+	 *  @private
+	 *  The highest place we can listen for events in our DOM
+	 */
+	private static var _mainListenerObj:IEventDispatcher; 
+	
+	
+	/**
+	 *  @private
+	 *  The uniqueAppID of this applicaiton as decided by the 
+	 *  root AutomationManager
+	 *  This field will be the applicaiton.id for the root appliction
+	 */
+	private static var _uniqueApplicationId:String; 
+	
+	/**
+	 *  @private
+	 *  The start point of this application in screen coordinates
+	 */
+	private static var _appStartPoint:Point; 
+	
+	/**
+	 *  @private
+	 *  the system manager of the current applicaiton domain
+	 */
+	 
+	private static var sm1:ISystemManager;
+	private static var _sm1MSm:IMarshalSystemManager;
+	
+	
+	/**
+	 *  @private
+	 *  The popup's of the current appliation domain
+	 */
+	 
+	private static var popUpObjects:Array;
+	
+	/**
+	 *  @private
+	 *  The daragProxy from the sub application
+	 */
+	 
+	private static var currentDragProxyHolder:Array;
+	
+	
+	private static var allAirWindowsToIdDictionary:Dictionary = new Dictionary(true);
+	private static var allAirIdToWindowsDictionary:Dictionary = new Dictionary(true);
+	private static var allAirWindowList:Array = new Array();
+	private static var lastRegisteredWindowCount:int = 0;
+	private static const airWindowIdFixedString:String = "_AIRWindow_";
+	public static const airWindowIndicatorPropertyName:String = "isAIRWindow";
+	//--------------------------------------------------------------------------
+	//
+	//  Class methods
+	//
+	//--------------------------------------------------------------------------
+
+	private static function get mainListenerObj():IEventDispatcher
+	{
+		if(!_mainListenerObj)
+			initMainListeners();
+		
+		return _mainListenerObj;
+		
+	}
+	
+	
+	private static function get sm1MSm():IMarshalSystemManager
+	{
+		if(!_sm1MSm)
+			initMainListeners();
+		
+		return _sm1MSm;
+		
+	}
+    /**
+     *  @private
+     *  Function invoked by the SystemManager. Creates AutomationManager singleton.
+     */
+	public static function init(root:DisplayObject):void
+	{ 
+		if(!Automation.initialized)
+		{
+				
+			sm1 = root as ISystemManager;
+			var sysMgr:SystemManager = root as SystemManager;
+			var tempOj:Object = sysMgr.topLevelSystemManager.getImplementation("mx.managers::IMarshalSystemManager");
+			_sm1MSm = IMarshalSystemManager(sysMgr.topLevelSystemManager.getImplementation("mx.managers::IMarshalSystemManager") );
+			//sm1MSm = root as IMarshalSystemManager;
+			// add event listener for the new sand_box_bridge event.
+			// whenver we get the new bridge
+			//mainListenerObj = getMainListenerObject(sm1);
+				
+			Automation.automationManager = new AutomationManager;
+			AutomationHelper.registerSystemManager(sm1);
+					
+		}
+	}
+	
+    /**
+     *  @private
+     */
+    private static function isChild(parent:DisplayObject,
+									child:DisplayObject):Boolean
+    {
+        while (child != null)
+        {
+            if (parent == child)
+                return true;
+            
+			child = child.parent;
+        }
+
+        return false;
+    }
+
+    /**
+     *  @private
+     */
+    private static function comparePropertyValues(lhs:Object, rhs:Object):Boolean
+    {
+        //we should probably be use the DefaultPropertyCodec to transcoding help here
+        //parts coming in from the testing tool should be properly typed, but they aren't
+        //so pretty much lhs will always be a String or RegExp
+        if (lhs == null && rhs == null)
+            return true;
+
+	   if ((lhs is String || lhs is Array) && 
+            lhs.length == 0 && rhs == null)
+            return true;
+	   
+	   /* Commenting the trimming part below because XMLList is now retruning non-trimmed strings*/
+	   //For strings we are trimming because otherwise, it returns false when compared with XML.toString()
+	   //because it returns trimmed strings 
+	   /*if(rhs is String)
+	   		rhs = trim(rhs as String);
+	   if(lhs is String)
+		   lhs = trim(lhs as String);*/
+	   
+		if ((lhs is XML ) && 
+			(lhs as XML).toXMLString.length == 0 && rhs == null)
+			return true;
+
+		if(rhs == null)
+		{
+			if ((lhs is XMLList ) && 
+				((lhs as XMLList).length() == 1))
+			{
+				var currentVar:XML = lhs[0];
+				if(currentVar.toXMLString().length == 0)
+					return true;
+			}
+		}
+		
+        if (rhs == null)
+            return false;
+
+		if(rhs is Boolean)
+			return (rhs == Boolean(Number(lhs)));
+				
+        if (lhs is Array)
+        {
+            if (!(rhs is Array))
+                return false;
+
+            if (lhs.length != rhs.length)
+                return false;
+
+            for (var no:int = 0; no < lhs.length; ++no)
+            {
+                if (!comparePropertyValues(lhs[no], rhs[no]))
+                    return false;
+            }
+            
+            return true;
+        }
+        else if (lhs is RegExp)
+            return lhs.test(rhs.toString());
+        else if (lhs is String)
+            return lhs == rhs.toString();
+        else
+            return lhs == rhs;
+    }
+
+    /**
+     * Applies [f] to each item in [list] by calling f(list[i])
+     * for i=0..[list].length.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    private static function map(f:Function, list:Array):void
+    {
+    	for (var i:int = 0; i < list.length; i++)
+        {
+    		f(list[i]);
+        }
+    }
+	
+	private static function isWhitespace( ch:String ):Boolean {
+		return ch == '\r' || 
+			ch == '\n' ||
+			ch == '\f' || 
+			ch == '\t' ||
+			ch == ' '; 
+	}
+	
+	private static function trim(string:String):String 
+	{
+		var n:int = string.length;
+		var i:int;
+		while(n>0)
+		{
+			if(isWhitespace(string.charAt(0)))
+			{
+				string = string.substring(1,n);
+				n--;
+			}
+			else
+				break;
+		}
+		n = string.length;
+		while(n>0)
+		{
+			if(isWhitespace(string.charAt(n-1)))
+			{
+				string = string.substring(0,n-1);
+				n--;
+			}
+			else
+				break;
+		}
+		return string;
+	}
+    
+	/**
+	 *  @private
+	 */
+	private  function childAddedHandler(event:Event):void
+	{
+		if (!Automation.delegateDictionary)
+			return;
+
+		var object:DisplayObject = event.target as DisplayObject;
+		
+		if (object && object.root && object.root is DisplayObject && !allSystemManagers[object.root])
+			allSystemManagers[object.root] = object.root;
+
+		
+		var delegateCreated:Boolean = createDelegate(event.target as DisplayObject);
+		addDelegates(event.target as DisplayObject);
+		
+		if(delegateCreated == false)
+		{
+			var component:IAutomationObject = event.target as IAutomationObject;
+			if(!component) // the obejct is not an IAutomationObject of the main applicaiton 
+			{
+				
+				if(object.parent )
+				{
+					// try to get the parents classname.
+					var className:String = getQualifiedClassName(object.parent);
+					
+					// when we get Alerts which are part of the another application
+					// we cannot create the delegate here. Here we should send the details
+					// to the other application and let them handle the same.
+					if((className == "mx.managers::SystemManagerProxy")||
+					 ((object.hasOwnProperty("className")&&	(object["className"] == "DragProxy")))||
+						(className =="mx.managers.dragClasses::DragProxy"))
+					
+					//if(className == "mx.managers::SystemManagerProxy")
+					{
+						
+						var tempEventObj:MarshalledAutomationEvent = new MarshalledAutomationEvent(
+								MarshalledAutomationEvent.POPUP_HANDLER_REQUEST);
+						var tempArr:Array = new Array();
+						tempArr.push(object);
+						tempEventObj.interAppDataToSubApp = tempArr;
+						dispatchMarshalledEventToSubApplications(tempEventObj);
+					}
+				}
+			}
+	
+		}
+	}
+	
+		
+	/**
+	 *  @private
+     *  Given a object returns the SystemManager object which contains
+     *  the applicationDomain containing the object class.
+	 */
+	private static function getSWFRoot(object:DisplayObject):DisplayObject
+	{
+		var className:String = getQualifiedClassName(object);
+
+		var domain:ApplicationDomain;
+		var compClass:Class;
+		for (var p:* in allSystemManagers)
+		{
+			domain = p.loaderInfo.applicationDomain;
+			try
+			{
+				compClass = Class(domain.getDefinition(className));
+				if (object is compClass)
+					return p as DisplayObject;
+			}
+			catch(e:Error)
+			{
+                 //exception means that the application domain 
+                 //doesn't contain the object class.
+			}
+		}
+		
+        //we have failed to find the application domain in the dictionary.
+        //try the nearest systemManager instance.
+		var sm:DisplayObject = object;
+		while(sm && !(sm is ISystemManager))
+		{
+			sm = sm.parent;
+		}
+		if(sm)
+		{
+			
+			domain = sm.loaderInfo.applicationDomain;
+			try	
+			{
+				compClass = Class(domain.getDefinition(className));
+				if (object is compClass)
+					return sm;
+			}
+			catch(e:Error)
+			{
+				// we didnt get the current object in any of the system manager's domain 
+				// and we got this exception. It is quite possible that the class 
+				// is an internal class. so let us rerutn the last parent's system manager.
+				// FLEXENT-1088, 1090, we should not return the parent's sm as this will prevent
+				// the module's app domain getting tried out.
+				//return sm;
+			}
+		}
+		
+		return null;
+	}
+	
+	/**
+	 *  @private
+	 */	 
+	private static function createDelegate(obj:DisplayObject):Boolean
+	{
+		var component:IAutomationObject = obj as IAutomationObject;
+		//if(!(obj is IAutomationObject || component == null || component.automationDelegate))
+		// the above looks to be wrong as we were adding the delegate for the same object more than once
+		// so change as follows
+		if((component == null)||(component.automationDelegate))
+		{
+			return false;
+		}
+		
+		var retValue:Boolean = false;
+		var appDomain:ApplicationDomain;
+		var className:String = getQualifiedClassName(obj);
+		var message:String;
+		if(!className)
+		{
+			message = "class name for the object could not be obtained " + obj.toString();
+			Automation.automationDebugTracer.traceMessage("AutomationManager","createDelegate()",message);
+			return false;
+		}
+			
+		var sm:DisplayObject = getSWFRoot(obj);
+		
+		if(!sm)
+		{
+	        var factory:IFlexModuleFactory = ModuleManager.getAssociatedFactory(obj);
+	        if (factory != null)
+    	    {
+        	    appDomain = ApplicationDomain(factory.info()["currentDomain"]);
+	        }
+	        else
+	        {
+	        	message = "Factory module failure";
+				Automation.automationDebugTracer.traceMessage("AutomationManager","createDelegate()",message);
+	        }
+		}
+		else
+		{
+			appDomain = (sm.loaderInfo) ? sm.loaderInfo.applicationDomain :
+											ApplicationDomain.currentDomain;
+		}
+		
+		var delegateClass:Class = null;
+		var compClass:Class = null;
+		var mainComponentClass:Class = null;
+		try
+		{
+			if(appDomain)
+			{
+				compClass = appDomain.getDefinition(className) as Class;
+				mainComponentClass = compClass;
+				delegateClass = Automation.delegateDictionary[compClass] as Class;
+			}
+			else
+			{
+				message = "Failed in getting the definition or the class or getting the delegate. " + 
+					"Automation will not work for this component. " + className;
+				Automation.automationDebugTracer.traceMessage("AutomationManager","createDelegate()",message);
+			}
+		}
+		catch(e:Error)
+		{
+			message = "Failed in getting the definition or the class or getting the delegate. " + 
+					"Automation will not work for this component. " + className;
+			Automation.automationDebugTracer.traceMessage("AutomationManager","createDelegate()",message);
+			Automation.automationDebugTracer.traceMessage("AutomationManager","createDelegate()",e.message);
+			//return false;
+		}
+		
+		if(!delegateClass && appDomain)
+		{
+			var componentClass:String = className;
+			do 
+			{
+				try 
+				{
+					className = getQualifiedSuperclassName(appDomain.getDefinition(className));
+					if(className)
+					{
+						compClass = appDomain.getDefinition(className) as Class;
+						delegateClass = Automation.delegateDictionary[compClass] as Class;
+					}
+				}
+				catch(e:Error)
+				{
+					Automation.automationDebugTracer.traceMessage("AutomationManager","createDelegate()",e.message);
+					break;
+				}
+			}
+			while(!delegateClass && className);
+			
+			Automation.delegateDictionary[mainComponentClass] = delegateClass; 
+			//trace("Added mapping for : " + componentClass);
+			
+			if(!className)
+			{
+				message = "super class name for the object could not be obtained "+ componentClass;
+				Automation.automationDebugTracer.traceMessage("AutomationManager","createDelegate()",message);
+				return false;
+			}
+
+		}
+		
+
+		var c:Class = delegateClass;
+		if (c)
+		{
+			try
+			{
+				var delegate:Object = new c (obj);
+			}
+			catch(e:Error)
+			{
+				Automation.automationDebugTracer.traceMessage("AutomationManager","createDelegate()",e.message);
+				message = "Delegate object couldnot be created";
+				Automation.automationDebugTracer.traceMessage("AutomationManager","createDelegate()",message);
+			}
+			
+			try
+			{
+				component.automationDelegate = delegate;
+				retValue = true;
+			}
+			catch(e:Error)
+			{
+				Automation.automationDebugTracer.traceMessage("AutomationManager","createDelegate()",e.message);
+				message = "object created but delegates not set";
+				Automation.automationDebugTracer.traceMessage("AutomationManager","createDelegate()",message);
+			}
+		}
+		else{
+			message = "Unable to find definition for class : " + className;
+			Automation.automationDebugTracer.traceMessage("AutomationManager","createDelegate()",message);
+		}
+			
+		return retValue;
+	}
+
+	/**
+	 *  @private
+	 *  Do a tree walk and add all children you can find.
+	 */
+	private static function addDelegates(o:DisplayObject):void
+	{
+		var child:DisplayObject ;
+		var i:int;
+		
+		if (o is DisplayObjectContainer)
+		{
+			var doc:DisplayObjectContainer = DisplayObjectContainer(o);
+
+			if (o is IRawChildrenContainer)
+			{
+				// trace("using view rawChildren");
+				var rawChildren:IChildList = IRawChildrenContainer(o).rawChildren;
+				// recursively visit and add children of components
+				// we don't do this for containers because we get individual
+				// adds for the individual children
+				for (i = 0; i < rawChildren.numChildren; i++)
+				{
+					try
+					{
+						child = rawChildren.getChildAt(i);
+						createDelegate(child);
+						addDelegates(child);
+					}
+					catch(error:SecurityError)
+					{
+						// Ignore this child if we can't access it
+					}
+				}
+
+			}
+			else
+			{
+				// trace("using container's children");
+				// recursively visit and add children of components
+				// we don't do this for containers because we get individual
+				// adds for the individual children
+				for (i = 0; i < doc.numChildren; i++)
+				{
+					try
+					{
+						child = doc.getChildAt(i);
+						createDelegate(child);
+						addDelegates(child);
+					}
+					catch(error:SecurityError)
+					{
+						// Ignore this child if we can't access it
+					}
+				}
+			}
+		}
+		
+		// do special creation of repeater delegates as they do not
+		// get added as children of Containers
+		var container:Container;
+		var repeaters:Array;
+		var count:int;
+		if(o is Container)
+		{
+			container = o as Container;
+			repeaters = container.childRepeaters;
+			// change for https://bugs.adobe.com/jira/browse/FLEXENT-1044
+			//if(!repeaters)
+			//	return;
+			count = repeaters?repeaters.length:0;
+			for(i = 0; i < count; ++i)
+			{
+				createDelegate(repeaters[i]);
+			}
+		}
+
+		// do special creation of repeater delegates as they do not
+		// get added as children of Containers
+		if(o.parent is Container)
+		{
+			container = o.parent as Container;
+			repeaters = container.childRepeaters;
+			// change for https://bugs.adobe.com/jira/browse/FLEXENT-1044
+			//if(!repeaters)
+			//	return;
+			count = repeaters?repeaters.length:0;
+			for(i = 0; i < count; ++i)
+			{
+				var repeater:IAutomationObject = repeaters[i] as IAutomationObject;
+				if(repeater && !repeater.automationDelegate)
+					createDelegate(repeaters[i]);
+			}
+		}
+		
+		// let us add one more level of check for the repeaters.
+		// change for https://bugs.adobe.com/jira/browse/FLEXENT-1044
+		
+		if(o is UIComponent)
+		{
+			var uiComp:UIComponent = o as UIComponent;
+			repeaters = uiComp.repeaters;
+			count = repeaters? repeaters.length : 0;
+			for(i = 0; i < count; ++i)
+			{
+				var repeater1:IAutomationObject = repeaters[i] as IAutomationObject;
+				if(repeater1 && !repeater1.automationDelegate)
+					createDelegate(repeaters[i]);
+			}
+		}
+		
+	}
+
+    //--------------------------------------------------------------------------
+    //
+    //  Constructor
+    //
+    //--------------------------------------------------------------------------    
+    
+    /**
+	 *  @private
+	 *  Constructor
+	 */ 
+	public function AutomationManager()
+    { 
+		super();
+		
+		//if(mainListenerObj)
+		{
+			// when the application is completed we need to add listener to the existing bridge
+			sm1.addEventListener(FlexEvent.APPLICATION_COMPLETE, applicationCompleteHandler,false,EventPriority.DEFAULT);
+			sm1.addEventListener(FlexChangeEvent.ADD_CHILD_BRIDGE , childBridgeHandler);
+
+			sm1.addEventListener(Event.ADDED, childAddedHandler, false, 0, true);
+			// FLEXENT-894 or 895 it was observerd that popupmenubutton menu popup object is
+			// creatd before application completion. So we need to listen to the event
+			// from the main app before the application completion. 
+			// this event is removed lated when we listen to the after application completion
+			//mainListenerObj.addEventListener(MarshalledAutomationEvent.POPUP_HANDLER_REQUEST , popupHandlerBeforeApplicationCompletion, false, 0, true);
+			// FLEXENT-1002
+			// when the sdk changes happened with the IMarshaledSystemManager, since the mainListenerObj was not available here
+			// we moved the following line to the applicaiton completion handler. But we need this handled before the application completion
+			// the popups of the application domain is added to the sandbox root application, we can depend on the sanbox to add to the listener for this
+			// event.
+			sm1.getSandboxRoot().addEventListener(MarshalledAutomationEvent.POPUP_HANDLER_REQUEST , popupHandlerBeforeApplicationCompletion, false, 0, true);
+	
+		}
+    }
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Variables
+    //
+    //--------------------------------------------------------------------------    
+    
+    /**
+	 *  @private
+	 */
+	private var lastMouseTarget:IEventDispatcher = null;
+    
+    /**
+	 *  @private
+	 */
+    private var hierarchyCacheCounter:int = 0;
+    
+    /**
+	 *  @private
+	 */
+	private var rebuildPartCache:Boolean = true;
+    
+    /**
+	 *  @private
+	 *  Holds automationIDPart objects for reuse.
+	 *  The IDParts are cached for the duration of one recording/function call.
+	 */
+	private var cachedParts:Dictionary = null;
+    
+    /**
+	 *  @private
+	 *  Holds the array of automation children for a container.
+	 *  The children are cached for the duration of one recording/function call.
+	 */
+	private var cachedChildren:Dictionary = null;
+	
+    /**
+	 *  @private
+	 */
+	private var cachedCompositor:Dictionary = null;
+
+    /**
+	 *  @private
+	 */
+    private var cachingEvents:Boolean = false;
+    
+    /**
+	 *  @private
+	 */
+	private var cachedTargetOriginator:EventDispatcher = null;
+    
+    /**
+	 *  @private
+	 */
+	private var eventCache:Array = [];
+    
+    /**
+	 *  @private
+	 */
+	private var flushCacheTimeoutID:int = -1;
+    
+    /**
+	 *  @private
+	 */
+	private var recordedEventInCurrentMouseSequence:Boolean = false;
+    
+    /**
+	 *  @private
+	 */
+	private var inMouseSequence:Boolean = false;
+    
+    /**
+	 *  @private
+	 */
+	private var synchronization:Array = [];
+
+    /**
+	 *  @private
+	 */
+	private var _currentMousePositions:Array = [];
+    
+    /**
+	 *  @private
+	 */
+	private var _prevMouseTargets:Array = [];
+    
+	/**
+	 *  @private
+	 *  Used for accessing localized Error messages.
+	 */
+	private var resourceManager:IResourceManager =
+									ResourceManager.getInstance();
+
+    //--------------------------------------------------------------------------
+    //
+    //  Properties
+    //
+    //--------------------------------------------------------------------------    
+
+	//----------------------------------
+	//  automationEnvironment
+	//----------------------------------
+
+    /**
+	 *  @private
+	 *  Storage for the automationEnvironment property.
+	 */
+    private  static var _automationEnvironment:IAutomationEnvironment;
+     private static var _automationEnvironmentString:String;
+     private static var _automationEnvironmentHandlingClassName:String;
+
+    /**
+     *  @private
+     */
+    public  function get automationEnvironment():Object
+    {
+    	//For AIR apps it is possible that environment details for main app are set
+    	//after the child apps request handlers are handled. So it can be null for child apps
+    	//intially. We need a way to get the environment details for AIR apps when actually needed
+    	if(!_automationEnvironment)	//happens only for AIR apps
+    	{
+    		// we will listen to the initial details from our parent.
+    		var initialStatusRequest:MarshalledAutomationEvent = 
+    			new MarshalledAutomationEvent(MarshalledAutomationEvent.INITIAL_DETAILS_REQUEST);
+    		_inInitialDetailsRequestProcessing = true;
+    		dispatchToParent(initialStatusRequest);
+    	}
+        return _automationEnvironment;
+    }
+
+    /**
+     *  @private
+     */
+    public  function set automationEnvironment(value:Object):void
+    {
+        _automationEnvironment = value as IAutomationEnvironment;
+        // we expect this method to be called only on the top root applicaiton
+    }
+
+ /**
+     *  @private
+     */
+    public function get automationEnvironmentString():String
+    {
+        return _automationEnvironmentString;
+    }
+
+    /**
+     *  @private
+     */
+    public function set automationEnvironmentString(value:String):void
+    {
+        _automationEnvironmentString = value;
+       
+    }
+    
+     
+    public function getUniqueApplicationID():String
+    {
+    	if (_uniqueApplicationId == null)
+    	{
+	    	if(sm1.isTopLevelRoot() == false)
+	    	{
+	    		// we should the following approach only for the sub
+	    		// applicaiton in the main security domain
+	    		// applications across security domain cannot access the
+	    		// parents of the system manager
+	    		if(sm1.isTopLevel() && (sm1.topLevelSystemManager.getSandboxRoot() == sm1.getSandboxRoot()) )
+	 			{
+		    		// we need to get the id of the current application from the parent
+		    		dispatchUniqueAppIdRequestEvent();
+		    			
+		    		var currentApplicationId:String = Automation.getMainApplication().className; 
+					_uniqueApplicationId = currentApplicationId + "_"+ _uniqueApplicationId;
+					//trace(_uniqueApplicationId + "   -   "+ classNameArray.join("|"));
+
+	   			 }
+	   			 else
+	   			 {
+	   			 	// we expect this loop to reach for the sub applicaiton is 
+	   			 	// different security domain
+	   			 	var temp:int = 0;
+	   			 }
+	    		
+	    	}
+	    	else
+	    	{
+	    		 	if(Automation.getMainApplication().hasOwnProperty("applicationID"))// this should work for AIR app's
+					{
+						_uniqueApplicationId = Automation.getMainApplication().applicationID;
+					}
+					else
+	    				_uniqueApplicationId = Automation.getMainApplication().id;
+	    				
+	    			if(!_uniqueApplicationId)
+	    				_uniqueApplicationId = AutomationHelper.getAppTitle();
+	    			
+	    	}
+	    }
+	    		
+    	return _uniqueApplicationId;
+    }
+    
+    //This method is used only by Flex apps which are loaded from air apps
+    // to get the start point of their main air app in screen coordinates
+    public function getStartPointInScreenCoordinates(windowId:String):Point
+    {
+    	var startPointRequest:MarshalledAutomationEvent = 
+    			new MarshalledAutomationEvent(MarshalledAutomationEvent.START_POINT_REQUEST);
+    	_inStartPointRequestProcessing = true;
+    	var tempArray:Array = [];
+    	tempArray.push(windowId);
+    	startPointRequest.interAppDataToMainApp = tempArray;
+    	dispatchToParent(startPointRequest);
+    	//reply handler for the above event (startPointReplyHandler) would store the 
+    	//start point in the variable _appStartPoint
+    	
+    	return _appStartPoint;
+    }
+    
+    private function dispatchStartPointRequestEvent(windowId:String):void
+    {
+    	var startPointRequest:MarshalledAutomationEvent = 
+    			new MarshalledAutomationEvent(MarshalledAutomationEvent.START_POINT_REQUEST);
+    	_inStartPointRequestProcessing = true;
+    	var tempArray:Array = [];
+    	tempArray.push(windowId);
+    	startPointRequest.interAppDataToMainApp = tempArray;
+    	dispatchToBridgeParent(startPointRequest);
+    }
+    
+    private static function getChildIndex1(parent:DisplayObjectContainer, child:DisplayObject):int
+    {
+        try 
+        {
+            return parent.getChildIndex(child);
+        }
+        catch(e:Error)
+        {
+            if (parent is IRawChildrenContainer)
+                return IRawChildrenContainer(parent).rawChildren.getChildIndex(child);
+            throw e;
+        }
+        throw new Error("FocusManager.getChildIndex failed");   // shouldn't ever get here
+    }
+
+    
+     /**
+     *  @private
+     */
+	public function set automationEnvironmentHandlingClassName(className:String):void
+	{
+		 _automationEnvironmentHandlingClassName = className;
+	}
+	
+	/**
+     *  @private
+     */
+    public function get automationEnvironmentHandlingClassName():String
+    {
+        return _automationEnvironmentHandlingClassName;
+    }
+	//----------------------------------
+	//  recording
+	//----------------------------------
+
+    /**
+	 *  @private
+	 *  Storage for the recording property.
+	 */
+	private var _recording:Boolean = false;
+    /**
+     *  @private
+     */
+	public function get recording():Boolean
+	{
+		return _recording;
+	}
+
+	//----------------------------------
+	//  replaying
+	//----------------------------------
+
+    /**
+	 *  @private
+	 *  Storage for the replaying property.
+	 */
+    private var _replaying:Boolean = false;
+    
+    /**
+     *  @private
+     */
+    public function get replaying():Boolean
+    {
+        return _replaying;
+    }
+	
+    //--------------------------------------------------------------------------
+    //
+    //  Methods
+    //
+    //--------------------------------------------------------------------------    
+
+    /**
+     *  @private
+     */
+    public function getParent(
+					   obj:IAutomationObject, 
+                       parentToStopAt:IAutomationObject = null,
+                       ignoreShowInHierarchy:Boolean = false):IAutomationObject
+    {
+        while (obj)
+        {
+			var parent:IAutomationObject;
+			if(obj is IAutomationObject)
+				parent = (obj as IAutomationObject).automationOwner as IAutomationObject;
+			
+            if (!parent && (obj is IUIComponent ) &&(IUIComponent(obj).systemManager != null) && 
+				(IUIComponent(obj).systemManager.document != null) && (obj != IUIComponent(obj).systemManager.document))
+			{
+				var doc:Object = IUIComponent(obj).systemManager.document;
+				parent = (doc as IAutomationObject);
+			}
+			else 
+			{
+				var parentObj:DisplayObject;
+				if(obj is IAutomationObject)
+					parentObj = (obj as IAutomationObject).automationOwner as DisplayObject;
+				
+				var parentClassName:String = getQualifiedClassName(parentObj);
+				if(parentClassName == "mx.managers::SystemManagerProxy")
+				{
+					parent = (Automation.getMainApplication() as IAutomationObject);
+				}
+				
+			}
+			
+			if (parent && (parent == parentToStopAt || 
+                           ignoreShowInHierarchy ||
+                           showInHierarchy(parent)))
+			{
+				return parent;
+			}
+			else
+			{			
+				obj = parent;
+			}
+        }
+
+        return null;
+    }
+
+    /**
+     *  @private
+     */
+    public function getChildrenFromIDPart(
+						obj:IAutomationObject,
+    					part:AutomationIDPart = null,
+                        ignoreShowInHierarchy:Boolean = false):Array
+    {
+		if (part == null)
+		{
+			return getChildren(obj, ignoreShowInHierarchy);
+		}
+		else
+		{
+			// important to do this check and not rely on it being checked
+			// when getChildren is eventually called by resolveIDPart because
+			// resolving always ignores the show in hierarchy and automation
+			// composite flags because resolving can be delegated to children
+			// that are not visible in the hieararchy (see comment in scoreChild)
+	        if (!obj || 
+	            !(obj is IAutomationObject) || 
+	            !(ignoreShowInHierarchy || showInHierarchy(obj)))
+			{
+	            return [];
+			}
+		
+	    	return resolveIDPart(obj, part);
+		}
+    }
+    
+    private function getApplicationChildren(obj:IAutomationObject):Array
+    {
+    	var result:Array = [];
+        if ( (obj is IUIComponent) && (IUIComponent(obj).systemManager != null)&&(obj == IUIComponent(obj).systemManager.document))
+        {
+			var sm:IChildList = null;
+			if(IUIComponent(obj).systemManager is IChildList)
+				sm =  IChildList(IUIComponent(obj).systemManager);
+                
+            var x:DisplayObject;
+            var delegate:IAutomationObject;
+
+			var count:int = sm?sm.numChildren:0;
+            for (var i:int = 0; i < count; i++)
+            {
+                //check that the automationParent is null because
+                //popup menus will all be children of SM but only one
+                //is the root, the rest are automation children of other menus
+                x = sm.getChildAt(i);
+				
+				delegate = (x as IAutomationObject);
+				if (delegate && 
+                        delegate != obj && 
+                        (!(delegate.automationOwner is IAutomationObject) ||
+                        delegate.automationOwner == obj))
+				{
+                    result.push(delegate);
+				}
+            }
+            
+			var popupChildren:IChildList = null;
+			
+			if(IUIComponent(obj).systemManager && 
+				(IUIComponent(obj).systemManager.popUpChildren) is IChildList )
+				popupChildren=  IChildList(IUIComponent(obj).systemManager.popUpChildren);
+			
+			var count1:int = popupChildren? popupChildren.numChildren:0;
+			
+            for (i = 0; i < count1; i++)
+            {
+                //check that the automationParent is null because
+                //popup menus will all be children of SM but only one
+                //is the root, the rest are automation children of other menus
+                x = popupChildren.getChildAt(i);
+				
+				delegate = (x as IAutomationObject);
+				if (delegate && 
+                        delegate != obj && 
+                        (!(delegate.automationOwner is IAutomationObject) ||
+                        delegate.automationOwner == obj))
+				{
+                    result.push(delegate);
+				}
+            }
+        }
+        return result;
+    }
+
+    /**
+     *  @private
+     */
+    public function getChildren(obj:IAutomationObject,
+                                ignoreShowInHierarchy:Boolean = false):Array
+    {
+        if (!obj || 
+            !(obj is IAutomationObject) || 
+            !(ignoreShowInHierarchy || showInHierarchy(obj)))
+		{
+            return [];
+		}
+
+        var result:Array = cachedChildren != null ? cachedChildren[obj] : null;
+
+        if (result == null)
+        {
+            result = getChildrenRecursively(obj);
+            
+            if( (obj is IUIComponent) && (IUIComponent(obj).systemManager != null) && (obj == IUIComponent(obj).systemManager.document))
+	        {
+	        	 var children:Array = getApplicationChildren(obj);
+	        	 result = result ? result.concat(children) : children;
+	        }
+
+            result = result || [];
+            
+            if (hierarchyCacheCounter > 0)
+                cachedChildren[obj] = result;
+        }
+
+        return result;
+    }
+
+    /**
+     *  @private
+     */
+    private function getChildrenRecursively(
+							aoc:IAutomationObject):Array
+    {
+        var result:Array = null;
+		// code modified below to avoid the usage of numAutomationChildren and
+		// getAutomationChildAt in a loop
+		//var childList:Array = aoc.getAutomationChildren();
+		var childList:Array = getAutomationChildrenArray(aoc);
+		var numAutomationChildren:int = childList?childList.length:0;
+		
+        //var numAutomationChildren:int = aoc.numAutomationChildren;
+        for (var i:int = 0; i < numAutomationChildren; i++)
+        {
+            //var ao:IAutomationObject = aoc.getAutomationChildAt(i);
+			var ao:IAutomationObject = childList[i] as IAutomationObject;
+			if(ao)
+			{
+	            if (isAutomationComposite(ao))
+	                continue;
+	            
+				if (! result)
+	                result = [];
+	            result.push(ao);
+	            
+				if (showInHierarchy(ao))
+	                continue;
+	            
+				// we dont need this check as this check itself needs to
+				// calculate all its children
+				//if (ao.numAutomationChildren > 0)
+	            {
+	                var x:Array =
+						getChildrenRecursively(ao)
+	
+	                if (x && x.length)
+	                    result = result ? result.concat(x) : x;
+	            }
+			}
+        }
+
+        return result;
+    }
+
+    /**
+     *  @private
+     */
+    public function getAutomationName(obj:IAutomationObject):String
+    {
+        if (!obj)
+            return null;
+
+        var result:Object = createIDPart(obj);
+        return result.automationName;
+    }
+
+    /**
+     *  @private
+     */
+    public function getAutomationClassName(obj:IAutomationObject):String
+    {
+        if (!obj)
+            return null;
+       
+  	   if(automationEnvironment)
+        {
+			var automationClass:IAutomationClass = 
+            	automationEnvironment.getAutomationClassByInstance(obj);
+        
+			return automationClass ? automationClass.name : null;
+        }
+        else
+        	return null;
+    }
+
+    /**
+     *  @private
+     */
+    public function getProperties(obj:IAutomationObject, 
+                                  names:Array = null, 
+                                  forVerification:Boolean = true, 
+                                  forDescription:Boolean = true):Array
+    {
+        if (!obj)
+            return null;
+
+        try
+        {
+            incrementCacheCounter();
+
+			// in the marshalle application if the tool libraries have not
+			// handled the requriemetns all applications will not be getting the 
+			// env details.
+			if(!automationEnvironment)
+				return null;
+			
+            var automationClass:IAutomationClass =
+                automationEnvironment.getAutomationClassByInstance(obj);
+            var propertMap:Object = automationClass.propertyNameMap;
+            var i:int;
+            var result:Array = [];
+            if (!names)
+            {
+	            var propertyDescriptors:Array = 
+	                automationClass.getPropertyDescriptors(obj, 
+	                                                    forVerification, 
+	                                                    forDescription);
+                names = [];
+                for (i = 0; i < propertyDescriptors.length; i++)
+                {
+                    names[i] = propertyDescriptors[i].name;
+                }
+            }
+            var part:Object = createIDPartForSpecifiedProperties(names,obj as IAutomationObject);
+            for (i = 0; i < names.length; i++)
+            {
+                var propertyDescriptor:IAutomationPropertyDescriptor = 
+                    propertMap[ names[i] ];
+                var value:Object = (propertyDescriptor 
+                                    ? getPropertyValueFromPart(part,obj, propertyDescriptor)
+                                    : null);
+                //don't convert to String, testing tools want it 
+                //delivered in the correct type
+				
+				
+                result.push(value);
+            }
+            
+            decrementCacheCounter();
+        }
+        catch(e:Error)
+        {
+            decrementCacheCounter();
+            
+            throw e;
+        }
+
+        return result;
+    }
+
+    /**
+     *  @private
+     */
+    public function getTabularData(obj:IAutomationObject):IAutomationTabularData
+    {
+        return obj.automationTabularData as IAutomationTabularData;
+    }
+
+    /**
+     *  @private
+     */
+    public function replayAutomatableEvent(event:AutomationReplayEvent):Boolean
+    {
+        var re:AutomationReplayEvent = event as AutomationReplayEvent;
+        
+       // check the recorded line count whether it is the max allowed limit 	
+       var recordedLinesCount:Number=  Automation.incrementRecordedLinesCount();
+       var licencePresent:Boolean = Automation.isLicensePresent();
+       if((recordedLinesCount > Automation.recordReplayLimit ) && (licencePresent == false))
+       {
+       	 _replaying = false;
+       	if(Automation.errorShown == false)
+       	{
+       		var warningMessage:String = resourceManager.getString(
+					"automation_agent", "replayLimitReached");
+					
+          	Alert.show( warningMessage );
+      		Automation.errorShown = true;
+      	}
+        return false;
+
+       }
+       
+		// required to make MouseMove work
+        if (re.replayableEvent is MouseEvent || 
+            ("triggerEvent" in re.replayableEvent && 
+            re.replayableEvent["triggerEvent"] is MouseEvent))
+        {
+            var evDispatcher:IEventDispatcher = re.automationObject as IEventDispatcher;
+            var rollOver:MouseEvent = new MouseEvent(MouseEvent.ROLL_OVER, false);
+            replayMouseEventInternal(evDispatcher, rollOver);
+            var mouseOver:MouseEvent = new MouseEvent(MouseEvent.MOUSE_OVER);
+            replayMouseEventInternal(evDispatcher, mouseOver);
+        }
+        
+        if (! isVisible(re.automationObject as DisplayObject))
+		{
+            var message:String = resourceManager.getString(
+				"automation_agent", "notVisible",
+				[re.automationObject.automationName]);
+			throw new AutomationError(message,
+									  AutomationError.OBJECT_NOT_VISIBLE);
+		}
+        
+        pushMouseSimulator(re.automationObject, 
+                           re.replayableEvent);
+        _replaying = true;
+        var uiObject:IAutomationObject = re.automationObject as IAutomationObject;
+        if (uiObject && !(uiObject.automationVisible && uiObject.automationEnabled))
+        {
+            re.succeeded = false;
+        }    
+        else
+        { 
+            re.succeeded = re.automationObject.replayAutomatableEvent(re.replayableEvent);
+        }
+        _replaying = false;
+        popMouseSimulator();
+
+        return dispatchEvent(re);
+    }
+	
+    /**
+     *  @private
+     *
+     */
+     // commented out the sandbox mouse events as it was causing the event overflow when we have the air window
+     // in the application. Found all the trial cases worked even without that. when we face an issue we need to
+     // analyse the WindowedSystemManager -> System Manager otherSystemManagerMouseListener sequence to analyse the
+     // event overflow reason.
+    public  function beginRecording():void
+    {   
+        if (!recording)
+        {
+            _recording = true;
+                     
+            sm1.addEventListener(AutomationRecordEvent.RECORD,
+            						recordHandler, false, EventPriority.DEFAULT_HANDLER, true);
+            sm1.getSandboxRoot().addEventListener(MouseEvent.MOUSE_DOWN,
+                                captureIDFromMouseDownEvent, true, 0, true);
+                                
+            //sm1.getSandboxRoot().addEventListener(SandboxMouseEvent.MOUSE_DOWN_SOMEWHERE,
+             //                   captureIDFromMouseDownEvent, true, 0, true);
+            sm1.addEventListener(KeyboardEvent.KEY_DOWN,
+                                captureIDFromKeyDownEvent, true, 0, true);
+            //ideally we would listen in the bubble phase so
+            //we'd get this last and all components have had a chance
+            //to react and record events, but some components are stopping
+            //the propagation so capture first and flush events
+            //in a delayed manner
+            sm1.getSandboxRoot().addEventListener(MouseEvent.CLICK,
+                                onEndMouseSequence, true, 0, true);
+            sm1.getSandboxRoot().addEventListener(MouseEvent.DOUBLE_CLICK,
+                                onEndMouseSequence, true, 0, true);
+                                
+           	//sm1.getSandboxRoot().addEventListener(SandboxMouseEvent.CLICK_SOMEWHERE,
+                               // onEndMouseSequence, true, 0, true);
+           // sm1.getSandboxRoot().addEventListener(SandboxMouseEvent.DOUBLE_CLICK_SOMEWHERE,
+                               // onEndMouseSequence, true, 0, true);
+                                
+            sm1.addEventListener(KeyboardEvent.KEY_UP,
+                                onEndKeySequence, true, 0, true);
+            //Ideally we'd flush events after the last click (or double click)
+            //however the player has a bug where it doesn't always send click
+            //events (and also there can be legitimate times when a click
+            //event won't come through, souch as a mouse down, mouse move off 
+            //the component then a mouse up), so do a timed flush after the
+            //mouse up (it needs to be after any click events that might occur)
+            sm1.getSandboxRoot().addEventListener(MouseEvent.MOUSE_UP,
+                                onEndMouseSequence, true, 0, true);
+            //sm1.getSandboxRoot().addEventListener(SandboxMouseEvent.MOUSE_UP_SOMEWHERE,
+                                //onEndMouseSequence, true, 0, true);
+			sm1.getSandboxRoot().addEventListener(FocusEvent.KEY_FOCUS_CHANGE, keyFocusChangeHandler, false, 0, true);
+			
+            dispatchEvent(new AutomationEvent);
+            
+            // if we are the top level automation Manager, we should have recieved this call.
+            // we need to inform other managers about this record starting
+           if(sm1.isTopLevelRoot())
+           {
+	        	var beginRecordMarshalledEvent:MarshalledAutomationEvent = new MarshalledAutomationEvent
+	        		(MarshalledAutomationEvent.BEGIN_RECORDING);
+	        	dispatchMarshalledEventToSubApplications(beginRecordMarshalledEvent);
+           }
+        }
+    }
+    
+    /**
+     *  @private
+     */
+    public function endRecording():void
+    {
+        if (recording)
+        {
+            _recording = false;
+            
+            dispatchEvent(new AutomationEvent(AutomationEvent.END_RECORD));
+            
+            sm1.removeEventListener(AutomationRecordEvent.RECORD,
+            					   recordHandler);
+            sm1.getSandboxRoot().removeEventListener(MouseEvent.MOUSE_DOWN,
+                                   captureIDFromMouseDownEvent, true);
+            sm1.getSandboxRoot().removeEventListener(SandboxMouseEvent.MOUSE_DOWN_SOMEWHERE,
+                                   captureIDFromMouseDownEvent, true);
+            sm1.removeEventListener(KeyboardEvent.KEY_DOWN,
+                                   captureIDFromKeyDownEvent, true);
+            sm1.getSandboxRoot().removeEventListener(MouseEvent.CLICK,
+                                   onEndMouseSequence, true);
+            sm1.getSandboxRoot().removeEventListener(MouseEvent.DOUBLE_CLICK,
+                                   onEndMouseSequence, true);
+            sm1.getSandboxRoot().removeEventListener(MouseEvent.MOUSE_UP,
+                                   onEndMouseSequence, true);
+            sm1.getSandboxRoot().removeEventListener(SandboxMouseEvent.CLICK_SOMEWHERE,
+                                   onEndMouseSequence, true);
+            sm1.getSandboxRoot().removeEventListener(SandboxMouseEvent.DOUBLE_CLICK_SOMEWHERE,
+                                   onEndMouseSequence, true);
+            sm1.getSandboxRoot().removeEventListener(SandboxMouseEvent.MOUSE_UP_SOMEWHERE,
+                                   onEndMouseSequence, true);                       
+            sm1.removeEventListener(KeyboardEvent.KEY_UP,
+                                   onEndKeySequence, true);
+
+            clearHierarchyCache();
+            clearEventCache();
+
+            recordedEventInCurrentMouseSequence = false;
+            inMouseSequence = false;
+        }
+    }
+
+	public function getElementFromPoint2(x:int, y:int,windowId:String ):IAutomationObject
+	{
+		var stage:Stage = getAIRWindow(windowId).stage;
+		return getElementFromPointOnRequiredWindow(x,y,stage);
+	}
+	
+	private function getElementFromPointOnRequiredWindow(x:int, y:int, requiredStage:Stage):IAutomationObject
+	{
+		var o:Array = requiredStage.getObjectsUnderPoint(new Point(x, y));
+        for (var i:int = o.length - 1; i >= 0; i--)
+        {
+            var displayObject:DisplayObject = o[i];
+            while (displayObject != null)
+            {
+                // don't use showInHierarchy because that would prevent
+                // checkpoints on things like boxes
+                var delegate:IAutomationObject = (displayObject as IAutomationObject);
+                if (delegate &&
+                    // check that it's an IAutomationObject before
+                    // checking visible since some components
+                    // such as stage (which aren't IAutomationObjects)
+                    // will yell and shout if you call visible on them
+                    displayObject.visible)
+                {
+                	var obj:IAutomationObject ;
+                	if(isAutomationComposite(delegate))
+                		obj = getAutomationComposite(delegate);
+                	else
+                		obj = delegate;
+
+                	return obj;
+                }
+                
+                displayObject = displayObject.parent;
+            }
+        }
+        return null;
+	}
+    /**
+     *  @private
+     */
+    public function getElementFromPoint(x:int, y:int):IAutomationObject
+    {
+		//use the stage, not the system manager to find elements
+		//because popups do not appear as children of the system manager
+		//and so things like alerts wouldn't be found
+        var stage:Stage = Automation.getMainApplication().stage;
+      	return getElementFromPointOnRequiredWindow(x,y,stage);
+    }
+
+    /**
+     *  @private
+     */
+    public function getRectangle(obj:DisplayObject):Array
+    {
+		var p:Point = new Point(0,0);
+		p = obj.localToGlobal(p);
+		// it was observed that the start points and the width and height are getting as
+		// non interger values, which makes those values as zero at the other end.
+		// so we are converting to the near int and passing.
+        return [int(p.x), int(p.y),int( p.x + obj.width), int(p.y + obj.height)];
+    }
+    
+    /**
+     *  @private
+     */
+    public function isVisible(obj:DisplayObject):Boolean
+    {
+        while (obj && obj != obj.root && obj != obj.stage)
+        {
+            if (!obj.visible)
+                return false;
+            obj = obj.parent;
+        }
+        return true;
+    }
+
+    /**
+     *  @private
+     */
+    private function getDistanceFromOriginalEvent(event:AutomationRecordEvent):int
+    {
+        var distance:int = 0;
+        var displayObject:DisplayObject = cachedTargetOriginator as DisplayObject;
+        
+        while (displayObject != null && displayObject != event.automationObject)
+        {
+            ++distance;
+            displayObject = displayObject.parent;
+        }
+        
+        return displayObject == event.automationObject ? distance : int.MAX_VALUE;
+    }
+
+    /**
+     *  @private
+     */
+    public function onEndKeySequence(event:KeyboardEvent):void
+    {
+/* 		if (flushCachedEvents() == null)
+	        onFinishEventSequence();
+
+        inMouseSequence = false;
+ */    }
+    
+    /**
+     *  @private
+     */
+    public function onEndMouseSequence(event:Event):void
+    {
+    	if (flushCacheTimeoutID != -1)
+			clearTimeout(flushCacheTimeoutID);
+		
+		if(event.type == MouseEvent.MOUSE_UP || event.type == SandboxMouseEvent.MOUSE_UP_SOMEWHERE ||
+		 event.type == SandboxMouseEvent.CLICK_SOMEWHERE)
+			rebuildPartCache = true;
+		
+        // we're in the capture phase of mouse up sometimes,
+        // so put in the timeout in either case.  so don't try
+        // to optimize by checking eventCache.length
+        flushCacheTimeoutID = setTimeout(endMouseSequence, 
+                                         event.type == MouseEvent.MOUSE_UP || 
+                                         event.type == SandboxMouseEvent.MOUSE_UP_SOMEWHERE ||
+                                          event.type == SandboxMouseEvent.CLICK_SOMEWHERE ? 500 : 1);
+    }
+    
+    /**
+     *  @private
+     */
+    protected function keyFocusChangeHandler(event:FocusEvent):void
+    {
+         var focusTarget:Object = event.target;
+	    // check whether the focus target is from the same application
+	    // else do not record this event
+	    // we want to avoid the recording of the bubbled event from other applications
+	    if(focusTarget.root != sm1)
+	    	return;
+	    
+	
+	    var dispatcher:IAutomationObject = null;
+		if(Automation.getMainApplication() is IAutomationObject)
+			dispatcher = IAutomationObject(Automation.getMainApplication());
+	 	
+       	var ao:IAutomationObject = (focusTarget as IAutomationObject);
+	    if (ao)
+	        dispatcher = (getAutomationComposite(ao) || ao);
+	  
+	    recordAutomatableEvent(dispatcher, event);
+    }   
+
+    /**
+     *  @private
+     */
+    private function endMouseSequence():void
+    {
+		if (flushCacheTimeoutID != -1)
+		{
+			clearTimeout(flushCacheTimeoutID);
+			flushCacheTimeoutID = -1;
+        }
+
+		if (flushCachedEvents() == null)
+	        onFinishEventSequence();
+
+        inMouseSequence = false;
+    }
+
+    /**
+     *  @private
+     * 
+     *  This is only public because the test harness needs to call this
+     *  due to a bug in the player.  No one should call this.
+     */
+    public function flushCachedEvents():Event
+    {
+		var event:AutomationRecordEvent;
+
+        if (eventCache.length > 0)
+        {
+            var closestEvents:Array = [];
+            var closestDistance:int = int.MAX_VALUE;
+            
+            for (var i:int = 0; i < eventCache.length; ++i)
+            {
+                event = eventCache[i];
+                var distance:int = getDistanceFromOriginalEvent(event);
+
+                if (distance < closestDistance)
+                {
+				    closestDistance = distance;
+                    closestEvents = [];
+                    closestEvents.push(event);
+                }
+                else if (distance == closestDistance)
+                {
+                    closestEvents.push(event);
+                }
+            }
+                
+            if (closestEvents.length > 0)
+            	event = closestEvents[0];
+        }
+
+		if (event != null)
+		{
+        	dispatchRecordEvent(event, true);
+        	
+        	  // at this place we record a new line hence increment the counter
+        	  // since this happened with a previous decrement, we need not check the
+        	  // boundary conditions
+        	  var recordedLinesCount:Number= Automation.incrementRecordedLinesCount();
+  		}
+
+		return event;
+    }
+
+    /**
+     *  @private
+     */
+    public function resolveIDToSingleObject(rid:AutomationID, 
+                                            currentParent:IAutomationObject = null):IAutomationObject
+    {
+        
+		var childArray:Array = resolveID(rid, currentParent);
+        
+        var message:String;
+		
+		if (childArray == null || childArray.length == 0)
+		{
+			message = resourceManager.getString(
+				"automation_agent", "idNotResolved", [rid.toString()]);
+            throw new AutomationError(message,
+									  AutomationError.OBJECT_NOT_FOUND);
+		}
+
+        if (childArray.length > 1)
+        {
+            message = resourceManager.getString(
+				"automation_agent", "matchesMsg", [childArray.length,
+				rid.toString().replace(/\n/, ' ')]) + ":\n"; 
+
+            for (var i:int = 0; i < childArray.length; i++)
+			{
+                message += AutomationClass.getClassName(childArray[i]) + 
+						   "(" + childArray[i].automationName + ")\n";
+			}
+
+            throw new AutomationError(message,
+									  AutomationError.OBJECT_NOT_UNIQUE);
+        }
+        return (childArray[0] as IAutomationObject);
+    }
+    
+    private function isApplication(part:AutomationIDPart):Boolean
+    {
+    	// for Air we have top level parents which are notapplications
+    	// they will be of the class 
+    	// TBD this is just for prototype. This will not work if the user
+    	// has extended the Window class
+    	/*if(part["className"] == "mx.core.Window")
+    		return true;*/
+    		
+    	if(part.hasOwnProperty(AutomationManager.airWindowIndicatorPropertyName))
+    		return true;
+    			
+		if(scoreChild((Automation.getMainApplication() as IAutomationObject), part,true) >= 0)
+			return true;
+		
+		return false;
+    }
+
+    /**
+     *  @private
+     */
+    public function resolveID(rid:AutomationID, 
+                              currentParent:IAutomationObject = null):Array
+    {
+    	var part:AutomationIDPart;
+        var id:AutomationID = rid.clone();
+		var message:String;
+        if (currentParent == null)
+        {
+	        //remove the application
+	        part = id.removeFirst();
+	        if (!isApplication(part))
+			{
+				message = resourceManager.getString(
+					"automation_agent", "rootApplication",[ id.toString()]);
+	            throw new AutomationError(message,
+	                                      AutomationError.ILLEGAL_RUNTIME_ID);
+			}
+	
+			// check for the AIR window.we can get the current parent as null even for 
+			// window object
+			if (part.hasOwnProperty(AutomationManager.airWindowIndicatorPropertyName))	
+        	{
+        		// get the automationName
+        		//var currentAutomationName:String = part["automationName"];
+        		var currentAutomationName:String = getPassedUniqueName(part);
+        		currentParent = getAIRWindow(currentAutomationName) as IAutomationObject;
+        	}
+        	else
+            	currentParent = (Automation.getMainApplication() as IAutomationObject);
+        }
+
+        var result:Array = null;
+        var currentChildArray:Array = [currentParent];
+        
+        while (true)
+        {
+            if (id.isEmpty())
+            {
+                result = currentChildArray;
+                break;
+            }
+
+            // contains part for resolving
+            part = id.removeFirst();
+
+            // child found by resolving
+            currentChildArray = currentParent.resolveAutomationIDPart(part);
+            
+            //check for nothing found
+            if (currentChildArray.length == 0)
+            {
+				//null results are legal on the last node for regex searches
+				//because it just means there was no match, but not legal
+				//when still traversing the parent nodes
+				if (!id.isEmpty())
+				{
+					message = resourceManager.getString(
+						"automation_agent", "notResolved", [part.automationName,
+						part.className, currentParent.automationName]);
+	                throw new AutomationError(message,
+	                                          AutomationError.OBJECT_NOT_FOUND);
+				}
+            }
+			else
+			{
+	            //check for too many parents found
+	            if (currentChildArray.length > 1 && !id.isEmpty())
+				{
+	                message = resourceManager.getString(
+						"automation_agent", "matchesMsg",
+						[currentChildArray.length, part.toString()]);
+					throw new AutomationError(message,
+	                                          AutomationError.OBJECT_NOT_UNIQUE);
+				}
+
+	            //check for parent = child
+	            if (currentChildArray[0] == currentParent)
+				{
+					message = resourceManager.getString(
+						"automation_agent", "resolvedTo",
+						[currentParent, currentChildArray[0]]);
+	                throw new AutomationError(message,
+	                                          AutomationError.ILLEGAL_OPERATION);
+				}
+
+	            //traverse into the next parent
+	            if (currentChildArray[0].numAutomationChildren > 0)
+	                currentParent = currentChildArray[0] ;
+	            //check for nothing found
+	            else if (!id.isEmpty())
+				{
+					message = resourceManager.getString(
+						"automation_agent", "idResolved",[ id.toString()]);
+	                throw new AutomationError(message,
+	                                          AutomationError.ILLEGAL_RUNTIME_ID);
+				}
+			}
+        }
+        return result;
+    }
+
+    /**
+     *  @private
+     */
+    public function resolveIDPartToSingleObject(parent:IAutomationObject,
+                                                part:AutomationIDPart):IAutomationObject
+    {
+        var rid:AutomationID = new AutomationID();
+        rid.addFirst(part);
+
+        return resolveIDToSingleObject(rid, parent);
+    }
+
+    /**
+     *  @private
+     */
+    public function resolveIDPart(parent:IAutomationObject,
+                                  part:AutomationIDPart):Array
+    {
+        var rid:AutomationID = new AutomationID();
+        rid.addFirst(part);
+
+        return resolveID(rid, parent);
+    }
+
+    /**
+     *  @private
+     */
+	public function createID(obj:IAutomationObject, 
+                             relativeToParent:IAutomationObject = null):AutomationID
+	{
+        var result:AutomationID = new AutomationID();
+        
+        if (obj == relativeToParent)
+        	return result;
+        
+        do 
+        {
+            //if relativeToParent is not in the hiearchy, then we need to do a special
+            //getParent so that we don't skip this parent
+            var parent:IAutomationObject = 
+                getParent(obj, relativeToParent, true);
+            // use the real parent for creating child ids
+            var part:AutomationIDPart = createIDPart(obj, parent);
+            result.addFirst(part);
+
+            // respect showInHierarchy when walking parent chain
+            obj = getParent(obj, relativeToParent);
+            
+            if (obj == relativeToParent)
+                break;
+        } while (obj);
+        return result;
+	}
+
+    /**
+     *  @private
+     */
+    public function createIDPart(obj:IAutomationObject, 
+                                 parent:IAutomationObject = null):AutomationIDPart
+    {
+        if (parent == null)
+            parent = getParent(obj, null, true);
+
+        var part:AutomationIDPart = (cachedParts 
+                                     ? cachedParts[obj] as AutomationIDPart
+                                     : null);
+
+        if (!part)
+        {
+            part = (parent 
+                    ? parent.createAutomationIDPart(obj) as AutomationIDPart
+                    : helpCreateIDPart(null, obj));
+                    
+            if (hierarchyCacheCounter > 0)
+                cachedParts[obj] = part;
+        }
+
+        return part;
+    }
+    
+    /**
+     *  @private
+     */
+    public function showInHierarchy(obj:IAutomationObject):Boolean
+    {
+        return  obj == null || 
+                !(obj is IAutomationObject) ||
+                (!isAutomationComposite(obj) && obj.showInAutomationHierarchy);
+    }
+
+    /**
+     *  @private
+     *
+     *  Helper implementation of IAutomationIDHelper.  Resolves an id based 
+     *  on a set of properties.  This should not be used, instead use 
+     *  resolveID, resolveIDToSingleObject, or resolveIDPart.
+     */
+    public function helpResolveIDPart(parent:IAutomationObject,
+                                      partObj:Object):Array
+    {
+    	var part:AutomationIDPart = partObj as AutomationIDPart;
+    	if(!part)
+    		return [];
+        //        trace("--- searching for child [" + ObjectUtil.toString(part) +
+        //              "] in parent [" + parent.automationName + "]");
+        
+        //Because resolving can be delegated to a child composite
+        //we need to ignore hierarchy.  An example is
+        //ComboBox composites List.  List will call helpResolveIDPart
+        //but will appear to have no children since it's not in the
+        //hierarchy, so pass true to getChildren to ignore showInHierarchy
+        //Note that resolving off ComboBox instead of List would
+        //not be appropriate since ComboBox may have other children (such
+        //as edit propertyName or button)
+        var children:Array = getChildren(parent, true);
+		var winners:Array  = getWinners(children,part,false);
+		if(winners.length > 1)
+			winners = getWinners(children,part,true);
+        return winners;
+    }
+
+	/**
+	 *  @private
+	 *
+	 */
+	 private function getWinners(children:Array, part:AutomationIDPart,forceIndexCalculation:Boolean):Array
+	 {
+		 //Because resolving can be delegated to a child composite
+		 //we need to ignore hierarchy.  An example is
+		 //ComboBox composites List.  List will call helpResolveIDPart
+		 //but will appear to have no children since it's not in the
+		 //hierarchy, so pass true to getChildren to ignore showInHierarchy
+		 //Note that resolving off ComboBox instead of List would
+		 //not be appropriate since ComboBox may have other children (such
+		 //as edit propertyName or button)
+		 var winners:Array = [];
+		 var bestScore:int = -1;
+		 for (var i:int = 0; i < children.length; i++)
+		 {
+			 var child:IAutomationObject = children[i]; 
+			 /*
+			 if (!child)
+			 {
+			 var message:String = resourceManager.getString(
+			 "automation_agent", "nullReturned",
+			 [i, parent.automationName, children.length]);
+			 throw new Error(message);
+			 }
+			 */
+			 // we are commenting out the checks above for the following reason
+			 // this check stops the automation of the application if any cheild of the application
+			 // is null. Initially since the automation framework was supporting only flex, all components
+			 // by default will be inheriting IAutomationObject. But when the flash-flex compoenets got added
+			 // to the application, it broke the automation of other flex components also because of this check.
+			 // reason: flex-flash components were not implementing the IAutomationObjects and hence the components
+			 // corresponding to that became null and hence the automation stopped.
+			 // to avoid such a scenario we have commented out this check.
+			 // and the flash-flex components are planning to be changed to implement this interface soon.
+			 // till then the usage of this change will allow the users to continue with automation of other components.
+			 
+			 var score:int = -1;
+			 if (child != null)
+			 {
+				 score = scoreChild(child, part,forceIndexCalculation);
+			 }
+			 
+			 if (score == -1)
+				 continue;
+			 
+			 // we are not processing all possible objects to match
+			 // if we got an object with all the required properties of the part.
+			 if(score == int.MAX_VALUE)
+				 return [child];
+			 
+			 if (score > bestScore)
+			 {
+				 bestScore = score;
+				 winners = [];
+			 }
+			 
+			 if (score == bestScore)
+				 winners.push(child);
+		 }
+		 
+		 return winners;
+
+	 }
+    /**
+     *  @private
+     *
+     *  Helper implementation of IAutomationIDHelper.  Creates an id for
+     *  a given child.  This should not be used, instead use createID,
+     *  or createIDPart.
+     */
+     
+    public function helpCreateIDPart(parent:IAutomationObject,
+                                     child:IAutomationObject,
+                                     automationNameCallback:Function = null,
+                                     automationIndexCallback:Function = null):AutomationIDPart
+    {
+        var part:AutomationIDPart = new AutomationIDPart();
+        if(!automationEnvironment)
+        	return part;
+        	
+        var automationClass:IAutomationClass =
+            automationEnvironment.getAutomationClassByInstance(child);
+        if(!automationClass)
+        	return part;
+        	
+        var propertyDescriptors:Array = 
+            automationClass.getPropertyDescriptors(child, false, true);
+
+		if(!propertyDescriptors)
+			return part;
+			
+		//It doesn't matter if a property is null
+		//add it anyways, because the callee asked for it
+		//and not adding it will confuse QTP since we've
+		//told it already about the properties in the env file
+		//If this causes a problem and we need to add the if
+		//null checks back, then be sure to update QTPAdapter
+		//to not return null properties in Learn and ActiveScreen
+
+        for (var propNo:int = 0; propNo < propertyDescriptors.length; ++propNo)
+        {
+            var propertyName:String = propertyDescriptors[propNo].name;
+            
+            if (propertyName == "id")
+            {
+                part.id = child is IDeferredInstantiationUIComponent
+                			? IDeferredInstantiationUIComponent(child).id
+                			: null;    
+               if ((part.id == null) && (parent == null))
+               { 
+               	   //trace ("inside the helpCreateIDPart - id "+ child.automationName);
+	                // currently we are in the application object.
+	                // this is a temp fix till we have AIR delegates in place.
+	                // we need the application iD of this component instead of the id
+	               	if(Automation.getMainApplication().hasOwnProperty("applicationID"))// this should work for AIR app's
+					{
+						part.id = Automation.getMainApplication().applicationID;
+						 //trace ("inside the helpCreateIDPart - id "+ part.id );
+					}
+					else
+					{
+						//we are in flex app hosted from Air app
+						part.id = processAppIDFromUniqueAppID();						
+					}
+               }
+            }
+            else if (propertyName == "automationName")
+                part.automationName = (automationNameCallback == null 
+                                       ? child.automationName 
+                                       : automationNameCallback(child));
+            else if (propertyName == "automationIndex")
+				//note that parent can be null if it's the parentApplication
+                part.automationIndex = (automationIndexCallback == null ? 
+                				getChildIndex(getParent(child), child)
+                				: automationIndexCallback(child));
+            else if (propertyName == "className")
+                part.className = AutomationClass.getClassName(child);
+            else if (propertyName == "automationClassName")
+                part.automationClassName = getAutomationClassName(child);
+            else if (propertyName == AutomationManager.airWindowIndicatorPropertyName)
+            {
+            	// we added this property to identify the airtoplevel windows
+            	part.isAIRWindow = true;
+            }
+            else
+            {
+                if (propertyName in child)
+	                part[propertyName] = child[propertyName];
+				else if (child is IStyleClient)
+					part[propertyName] = IStyleClient(child).getStyle(propertyName);
+	            else
+				{
+					var message:String = resourceManager.getString(
+						"automation_agent", "notDefined", [propertyName, child]);
+					traceMessage("AutomationManager", "helpCreateIDPart()", message);
+                   // throw new Error(message);
+				}
+            }
+        }
+
+        if ("automationName" in part && ((part.automationName == null)||(part.automationName.length == 0)))
+            part.automationName = part.automationIndex;
+            
+        return part;
+    }
+    
+    private function processAppIDFromUniqueAppID():String
+    {
+    	var appId:String = getUniqueApplicationID();
+    	var index:int = appId.lastIndexOf("_");
+    	if(index != -1)
+    	{
+    		appId = appId.substring(index + 1, appId.length );
+    	}
+    	else
+    	{
+    		appId = null;
+    	}
+    	return appId;
+    }
+    
+    /**
+     *  @private
+     */
+    private function isClassAvailable(className:String):Boolean
+    {
+    	try
+    	{
+    		if(getDefinitionByName(className) != null)
+    			return true;
+    	}
+    	catch(e:Error)
+		{
+			return false;
+		}
+		
+		return false;
+    }
+
+    /**
+     * Dispatch the event as a replayable event.  Causes the 
+     * ReplayableEventEvent with REPLAYABLE_EVENT type to be fired.  
+     * However, this method will not attempt the dispatch if there are no 
+     * listeners.
+     *
+     * @param eventReplayer The IEventReplayer dispatching this 
+     *                            event since event.target may not be 
+     *                            accurate
+     * @param event The event that represents the replayable event.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function recordAutomatableEvent(recorder:IAutomationObject, event:Event,
+                                           cacheable:Boolean = false):void
+    {
+    	// this method should not get called with null event.
+    	// However during some usage of the events being dispatched programmatically
+    	// the trigger events may be null and the record of the same is called with the
+    	// null. Eventhough this is not the expected way of usage, a check is added.
+    	if (event == null)
+       		return;
+       		
+        if (!recording)
+        	return;
+        	
+		var message:String;
+        	
+        var re:AutomationRecordEvent;
+        if (event is AutomationRecordEvent)
+        	re = event as AutomationRecordEvent;
+        else
+        {
+        	re = new AutomationRecordEvent(AutomationRecordEvent.RECORD);
+		    re.automationObject = recorder;
+    		re.replayableEvent = event;
+        	re.cacheable = cacheable;
+        }
+        	
+		//swallow orphan clicks when not following a mouseDown
+		if (re.replayableEvent.type == MouseEvent.CLICK && !inMouseSequence)
+			return;
+
+		// in the marshalled application if the tool libraries have not
+		// handled the requriemetns all applications will not be getting the 
+		// env details.
+		if(!automationEnvironment)
+				return ;
+				
+        var automationClass:IAutomationClass = 
+                automationEnvironment.getAutomationClassByInstance(re.automationObject as IAutomationObject);
+
+         if (automationClass == null)
+		 {
+			  message = resourceManager.getString(
+			      "automation_agent", "classNotFound",
+				  [AutomationClass.getClassName(re.automationObject)]);
+              throw new Error(message);
+		 }
+
+         var eventDescriptor:IAutomationEventDescriptor =
+               automationClass.getDescriptorForEvent(re.replayableEvent);
+
+         if (eventDescriptor == null)
+		 {
+			   message = resourceManager.getString(
+			       "automation_agent", "methodNotFound",
+				   [AutomationClass.getClassName(re.replayableEvent),
+				   automationClass]); 
+               throw new Error(message);
+		 } 
+                
+         re.name = eventDescriptor.name;
+         re.args = eventDescriptor.record(re.automationObject, re.replayableEvent);
+
+ 		// check the recorded line count whether it is the max allowed limit 	
+       var recordedLinesCount:Number=  Automation.incrementRecordedLinesCount();
+       var licencePresent:Boolean = Automation.isLicensePresent();
+       if((recordedLinesCount > Automation.recordReplayLimit ) && (licencePresent == false))
+       {
+      	endRecording();
+      	
+      	  var warningMessage:String = resourceManager.getString(
+					"automation_agent", "recordLimitReached");
+					
+          Alert.show( warningMessage );
+         return;
+ 
+       }
+       	
+       	// if the components are part of the Popup winodws (e.g Alert and objects
+       	// hosted by the popUpManager and if they belong to the non root applicaiotn
+       	// they are hosted by the main application. So it looks like the events dispatched on
+       	// them does not reach the appropriate application. So to handle the special case,
+       	// we directly call the record Handler.
+       	 if(isObjectChildOfSystemManagerProxy (re.automationObject) )
+       	 	recordHandler(re);
+       	 	
+       	 if(getQualifiedClassName(re.automationObject) == "mx.controls::FlexNativeMenu")
+       	 	recordHandler(re);
+         if (re.bubbles && re.automationObject is IEventDispatcher)
+		 	IEventDispatcher(re.automationObject).dispatchEvent(re);
+		 else
+			recordHandler(re);
+    }
+    
+     /**
+     *  @private
+     */
+    public function isObjectChildOfSystemManagerProxy(automationObject:IAutomationObject):Boolean
+	{
+		var obj:DisplayObject = automationObject as DisplayObject;
+		if(obj == null)	//this happens for FlexNativeMenu in AIR as it is not a DisplayObject
+			return false;
+		if(obj.parent == null)
+		{
+			// when the focus of the popup objects are taken to some other application
+			// it is obsreverd that the parent is becoming null.
+			// dont know whether it is an issue with sdk.
+			// however since we have the list of poppup objects applicable to us
+			// we can check in that.
+			if((lastRemovedpopUpObject == automationObject as DisplayObject ) || (popUpObjects.indexOf(obj) != -1))
+				return true;
+
+		}
+		
+		while(obj.parent)
+		{
+			if(obj.parent is SystemManagerProxy)
+				return true;
+			obj = obj.parent;
+
+		}
+		return false;
+	}   
+     
+    /**
+     *  @private
+     */
+    public function isObjectPopUp(automationObject:IAutomationObject):Boolean
+	{
+		var obj:DisplayObject = automationObject as DisplayObject;
+		if(obj == null) //this happens for FlexNativeMenu in AIR as it is not a DisplayObject
+			return false;
+		if(obj.parent == null)
+		{
+			// when the focus of the popup objects are taken to some other application
+			// it is obsreverd that the parent is becoming null.
+			// dont know whether it is an issue with sdk.
+			// however since we have the list of poppup objects applicable to us
+			// we can check in that.
+			if((lastRemovedpopUpObject == automationObject as DisplayObject ) || (popUpObjects.indexOf(obj) != -1))
+				return true;
+
+		}
+		// we need to find out whether the object belongs to the system manager before it belongs to an application
+		// this is also needed to find the popups from the main application.
+		var applicationFound:Boolean = (obj is Application || isSparkApplication(obj))?true:false;
+		while(obj.parent)
+		{
+			if(obj.parent is SystemManagerProxy)
+				return true;
+			else
+			{
+				if(obj.parent is Application || isSparkApplication(obj.parent))
+					applicationFound = true;
+				else if ((obj.parent == sm1)&&(!applicationFound))
+					return true;
+			}
+
+			obj = obj.parent;
+
+		}
+		return false;
+	}   
+    
+    /**
+     *  @private
+     */
+    public function recordHandler(te:Event):void
+	{
+		var re:AutomationRecordEvent = te as AutomationRecordEvent;
+		if(re == null)
+			return;
+		if (re.isDefaultPrevented())
+		{
+			
+			// decrement the recording counter 
+        	// as the recording does not happen here
+        	var recordedLinesCount1:Number= Automation.decrementRecordedLinesCount();
+			return;
+		}
+
+        if (!isAutomationComposite(re.automationObject))
+        {
+            if (re.cacheable && cachingEvents)
+            {
+                eventCache.push(re);
+	            // decrement the recording counter 
+	        	// as the recording does not happen here
+	        	var recordedLinesCount2:Number= Automation.decrementRecordedLinesCount();
+            }
+            else
+                dispatchRecordEvent(re, false);
+        }
+        else
+        {
+        	// decrement the recording counter 
+        	// as the recording does not happen here
+        	  var recordedLinesCount3:Number= Automation.decrementRecordedLinesCount();
+        }
+    }
+
+    /**
+     *  @private
+     */
+    public function addSynchronization(isComplete:Function,
+                                       target:Object = null):void
+    {
+        synchronization.push({isComplete: isComplete, target: target });
+    }
+
+    /**
+     *  @private
+     */
+    public  function isSynchronized(target:IAutomationObject):Boolean
+    {
+        for (var i:int = 0; i < synchronization.length; i++)
+        {
+            if (synchronization[i].isComplete())
+                 synchronization.splice(i--, 1);
+            else if (target == synchronization[i].target || 
+            		(target && target == synchronization[i].target) ||
+            		 synchronization[i].target == null)
+                return false;
+            }
+        return true;
+    }
+
+    /**
+     *  @private
+     */ 
+    public function getMemberFromObject(obj:Object, 
+                                        name:String):Object
+    {
+    	var part:Object;
+    	var component:Object;
+
+        part = createIDPart(obj as IAutomationObject);
+        component = obj;
+	    	
+        var result:Object = null;
+
+        if (part != null && name in part)
+            result = part[name];
+        else if (name in obj)
+            result = obj[name];
+        else if (component != null)
+        {
+        	if (name in component)
+	            result = component[name];
+    	    else if (component is IStyleClient)
+        	    result = IStyleClient(component).getStyle(name);
+        }
+       
+        return result;
+    }
+    
+    /**
+     *  @private
+     */
+    public function getPropertyValue(obj:Object, 
+                                     pd:IAutomationPropertyDescriptor,
+                                     relativeParent:IAutomationObject = null):Object
+    {
+        return getMemberFromObject(obj, pd.name);
+    }
+
+	//--------------------------------------------------------------------------
+	//
+    //  Mouse simulator methods
+    //
+	//--------------------------------------------------------------------------
+
+    /**
+     *  @private
+     */
+    public function getMouseX(item:DisplayObject):Number
+    {
+        return item.globalToLocal(_currentMousePositions[_currentMousePositions.length - 1]).x;
+    }
+
+    /**
+     *  @private
+     */
+    public function getMouseY(item:DisplayObject):Number
+    {
+        return item.globalToLocal(_currentMousePositions[_currentMousePositions.length - 1]).y;
+    }
+
+    /**
+     *  @private
+     */
+    private function replayMouseEventInternal(target:IEventDispatcher, event:MouseEvent):Boolean
+    {
+		//feed mouseOut and rollOut events to the last-clicked object, for defocussing purposes.		
+		if (lastMouseTarget && lastMouseTarget != target)
+		{
+			var sendMouseEvents:Boolean = true;
+			// check whether the new target is child of the last target.
+			// if it is a child we should not send mouseOut, rollOut events
+			if(lastMouseTarget is DisplayObjectContainer && target is DisplayObject)
+			{
+				if(DisplayObjectContainer(lastMouseTarget).contains(target as DisplayObject))
+				{
+                    // make the inner most component as the last target.
+                    // should we have a stack of these inner components
+                    // so that we can playback rollOut for all of them?
+					lastMouseTarget = target;
+					sendMouseEvents = false;
+				}
+				
+			}
+			if(sendMouseEvents)
+			{
+				var mouseOut:MouseEvent = new MouseEvent(MouseEvent.MOUSE_OUT);
+				var rollOut:MouseEvent = new MouseEvent(MouseEvent.ROLL_OUT, false);
+				lastMouseTarget.dispatchEvent(mouseOut);
+				lastMouseTarget.dispatchEvent(rollOut);
+				lastMouseTarget = target as IEventDispatcher;
+			}
+		}
+
+		if(!lastMouseTarget)
+			lastMouseTarget = target as IEventDispatcher;
+
+        return target.dispatchEvent(event);
+    }
+
+    private static var fakeMouseX:QName = new QName(mx_internal, "_mouseX");
+    private static var fakeMouseY:QName = new QName(mx_internal, "_mouseY");
+
+    /**
+     *  @private
+     */
+    private function pushMouseSimulator(targetObj:Object, eventObj:Object):void
+    {
+        var target:DisplayObject = (targetObj is DisplayObject 
+                                    ? DisplayObject(targetObj) 
+                                    : null);
+        var event:MouseEvent = (eventObj is MouseEvent 
+                                ? MouseEvent(eventObj) 
+                                : null);
+        
+        var pt:Point = (event != null 
+                        ? new Point(event.localX, event.localY) 
+                        : new Point(0, 0));
+
+;
+		
+        pt = target != null ? target.localToGlobal(pt) : pt;
+
+        _currentMousePositions.push(pt);
+        _prevMouseTargets.push(target);
+        
+    
+    	try
+    	{
+   			target.root[fakeMouseX] = pt.x;
+   			target.root[fakeMouseY] = pt.y;
+   		}
+   		catch(e:Error)
+   		{
+			traceMessage("AutomationManager", "pushMouseSimulator()", AutomationConstants.invalidInAIR);
+   		}
+     
+       
+        
+        Automation.mouseSimulator = this;
+    }
+
+    /**
+     *  @private
+     */
+    private function popMouseSimulator():void
+    {
+        _currentMousePositions.pop();
+		_prevMouseTargets.pop();
+        var target:Object = _prevMouseTargets[_prevMouseTargets.length-1];
+        if(target && target.root)
+        {   
+    	    try
+	    	{
+		        target.root[fakeMouseX] = _currentMousePositions[_currentMousePositions.length-1].x;
+	    	    target.root[fakeMouseY] = _currentMousePositions[_currentMousePositions.length-1].y;
+  	   		}
+	   		catch(e:Error)
+	   		{
+				traceMessage("AutomationManager", "popMouseSimulator()", AutomationConstants.invalidInAIR);
+	   		}
+    	}
+    	else
+    	{
+            //var sm:ISystemManager = Application.application.systemManager;
+	        try
+	    	{
+	  			sm1[fakeMouseX] = undefined;
+				sm1[fakeMouseY] = undefined; 		
+			}
+	   		catch(e:Error)
+	   		{
+				traceMessage("AutomationManager", "popMouseSimulator()", AutomationConstants.invalidInAIR);
+	   		}
+		
+		
+			if (!_currentMousePositions.length)
+				Automation.mouseSimulator = null;
+    	}
+    }
+
+	//--------------------------------------------------------------------------
+	//
+    //  Replay helper methods
+    //
+	//--------------------------------------------------------------------------
+
+    /**
+     *  @private
+     */
+    public function replayKeyboardEvent(to:IEventDispatcher, event:KeyboardEvent):Boolean
+    {
+        return replayKeyDownKeyUp(to, event.keyCode, event.ctrlKey, event.shiftKey);
+    }
+    
+    /**
+     *  @private
+     */
+    public function replayKeyDownKeyUp(to:IEventDispatcher,
+                                       keyCode:uint,
+                                       ctrlKey:Boolean = false,
+                                       shiftKey:Boolean = false,
+                                       altKey:Boolean = false):Boolean
+	{		
+		map(function(type:String):void
+			{
+				var event:KeyboardEvent = new KeyboardEvent(type);
+				event.keyCode = keyCode;
+				event.ctrlKey = ctrlKey;
+				event.shiftKey = shiftKey;
+				event.altKey = altKey;
+				to.dispatchEvent(event);
+			},
+			KEY_CLICK_TYPES);
+        
+		return true;
+	}    									
+
+    /**
+     *  @private
+     */
+    public function replayMouseEvent(target:IEventDispatcher, event:MouseEvent):Boolean
+    {

[... 2400 lines stripped ...]