Transferred from the Adobe Open Source Subversion Repository

Revision: 12850
Author:   jimurphy@adobe.com
Date:     2009-12-11T14:57:14.623098Z

Log Message:
-----------
add 6 new DMV projects to the SDK:
automation
automation_air
automation_dmv
automation_flashflexkit
automation_spark
datavisualization

These projects are setup to build in an ant main call.  There are currently several warnings in the datavisualization project that will be cleaned up.  No checkintests exist for these projects as of yet.

I also modified the exisitng projects build files for easier management of the localization targets, bundle and fat-swc. If the projects that I updated:airframework,airspark,framework,playerglobal,rpc,and spark.  All the new projects have been implemented this same way.

QE notes: DMV folks should run through their tests
Doc notes: probably
Bugs: nope
Reviewer:
Tests run: ran the following targets: compile,checkintests,other.locales and doc
Is noteworthy for integration: no

Modified Paths:
--------------
1404 paths were modified

git-svn-id: 7146a936b37d36e51ea0d66f8acbe0b8281bc7b7@1290254 13f79535-47bb-0310-9956-ffa450edef68

--- frameworks/projects/advancedgrids/src/mx/collections/HierarchicalCollectionView.as
+++ frameworks/projects/advancedgrids/src/mx/collections/HierarchicalCollectionView.as
@@ -0,0 +1,1859 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  ADOBE SYSTEMS INCORPORATED
+//  Copyright 2009 Adobe Systems Incorporated
+//  All Rights Reserved.
+//
+//  NOTICE: Adobe permits you to use, modify, and distribute this file
+//  in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.collections
+{
+
+import flash.events.EventDispatcher;
+import flash.utils.Dictionary;
+import flash.xml.XMLNode;
+
+import mx.collections.errors.ItemPendingError;
+import mx.core.EventPriority;
+import mx.core.mx_internal;
+import mx.events.CollectionEvent;
+import mx.events.CollectionEventKind;
+import mx.events.PropertyChangeEvent;
+import mx.utils.IXMLNotifiable;
+import mx.utils.UIDUtil;
+import mx.utils.XMLNotifier;
+
+use namespace mx_internal;
+
+/**
+ *  The HierarchicalCollectionView class provides a hierarchical view of a standard collection.
+ *
+ *  @mxml
+ *
+ *  The <mx.HierarchicalCollectionView> inherits all the tag attributes of its superclass,
+ *  and defines the following tag attributes:

+ *
+ *

+ *  <mx:HierarchicalCollectionView
+ *  Properties
+ *    showRoot="true|false"
+ *    source="No default"
+ *  />
+ *

+ *
+ *  @langversion 3.0
+ *  @playerversion Flash 9
+ *  @playerversion AIR 1.1
+ *  @productversion Flex 3
+ */
+public class HierarchicalCollectionView extends EventDispatcher
+                                        implements IHierarchicalCollectionView, IXMLNotifiable
+{
+    include "../core/Version.as";
+
+    //--------------------------------------------------------------------------
+    //
+    //  Constructor
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  Constructor.
+     *
+     *  @param hierarchicalData The data structure containing the hierarchical data.
+     *
+     *  @param argOpenNodes The Object that defines a node to appear as open.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function HierarchicalCollectionView(
+                            hierarchicalData:IHierarchicalData = null,
+                            argOpenNodes:Object = null)
+    {
+        super();
+
+        if (hierarchicalData)
+            initializeCollection(hierarchicalData.getRoot(), hierarchicalData, argOpenNodes);
+    }
+
+    //--------------------------------------------------------------------------
+    //
+    // Variables
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  @private
+     */
+    private var hierarchicalData:IHierarchicalData;
+
+    /**
+     *  @private
+     */
+    private var cursor:HierarchicalCollectionViewCursor;
+
+    /**
+     *  @private
+     *  The total number of nodes we know about.
+     */
+    private var currentLength:int;
+
+    /**
+	 *  @private
+	 *  Top level XML node if there is one
+	 */
+	private var parentNode:XML;
+
+    /**
+     *  @private
+     *  Mapping of nodes to children.  Used by getChildren.
+     */
+    private var childrenMap:Dictionary;
+
+    /**
+     *  @private
+     */
+    private var childrenMapCache:Dictionary = new Dictionary(true);
+
+    /**
+     *  @private
+     */
+    mx_internal var treeData:ICollectionView;
+
+    /**
+     *  @private
+     *  Mapping of UID to parents.  Must be maintained as things get removed/added
+     *  This map is created as objects are visited
+     */
+    mx_internal var parentMap:Object;
+
+    //--------------------------------------------------------------------------
+    //
+    //  Properties
+    //
+    //--------------------------------------------------------------------------
+
+    //----------------------------------
+    //  hasRoot
+    //----------------------------------
+
+    private var _hasRoot:Boolean;
+
+    /**
+     *  @inheritDoc
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function get hasRoot():Boolean
+    {
+        return _hasRoot;
+    }
+
+    //----------------------------------
+    //  openNodes
+    //----------------------------------
+
+    /**
+     *  @private
+     *  Storage for the openNodes property.
+     */
+    private var _openNodes:Object;
+
+    /**
+     *  @inheritDoc
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function get openNodes():Object
+    {
+        return _openNodes;
+    }
+
+    /**
+     *  @private
+     */
+    public function set openNodes(value:Object):void
+    {
+        // openNodes cant be null
+        if (value)
+        {
+            _openNodes = {};
+            for each (var item:* in value)
+            {
+                _openNodes[UIDUtil.getUID(item)] = item;
+            }
+        }
+        else
+            _openNodes = {};
+
+        if (hierarchicalData)
+        {
+            //calc initial length
+            currentLength = calculateLength();
+
+            // need to refresh the collection after setting openNodes
+            var event:CollectionEvent =
+                new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
+            event.kind = CollectionEventKind.REFRESH;
+            dispatchEvent(event);
+        }
+    }
+
+    //----------------------------------
+    //  showRoot
+    //----------------------------------
+
+    private var _showRoot:Boolean = true;
+
+    [Bindable]
+    [Inspectable(category="Data", enumeration="true,false", defaultValue="true")]
+
+    /**
+     *  @inheritDoc
+     *
+     *  @default true
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function get showRoot():Boolean
+    {
+        return _showRoot;
+    }
+
+    /**
+     *  @private
+     */
+    public function set showRoot(value:Boolean):void
+    {
+        if (_showRoot != value)
+        {
+            _showRoot = value;
+            if (hierarchicalData)
+            {
+                initializeCollection(hierarchicalData.getRoot(), hierarchicalData, openNodes);
+
+                //setting showRoot resets the collection
+                var event:CollectionEvent =
+                    new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
+                event.kind = CollectionEventKind.RESET;
+                dispatchEvent(event);
+            }
+        }
+    }
+
+    //----------------------------------
+    //  source
+    //----------------------------------
+
+    /**
+     *  @inheritDoc
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function get source():IHierarchicalData
+    {
+        return hierarchicalData;
+    }
+
+    /**
+     *  @private
+     */
+    public function set source(value:IHierarchicalData):void
+    {
+        initializeCollection(value.getRoot(), value, openNodes);
+    }
+
+    //----------------------------------
+    //  filter
+    //----------------------------------
+
+    /**
+     *  @private
+     *  Storage for the filterFunction property.
+     */
+    private var _filterFunction:Function;
+
+    [Bindable("filterFunctionChanged")]
+    [Inspectable(category="General")]
+
+    /**
+     *  @private
+     */
+    public function get filterFunction():Function
+    {
+        return _filterFunction;
+    }
+
+    /**
+     *  @private
+     */
+    public function set filterFunction(value:Function):void
+    {
+        _filterFunction = value;
+    }
+
+    //----------------------------------
+    //  length
+    //----------------------------------
+
+    /**
+     *  The length of the currently parsed collection.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function get length():int
+    {
+        return currentLength;
+    }
+
+    //----------------------------------
+    //  sort
+    //----------------------------------
+
+    /**
+     *  @private
+     *  Storage for the sort property.
+     */
+    private var _sort:Sort;
+
+    [Bindable("sortChanged")]
+    [Inspectable(category="General")]
+
+    /**
+     *  @private
+     */
+    public function get sort():Sort
+    {
+        return _sort;
+    }
+
+    /**
+     *  @private
+     */
+    public function set sort(value:Sort):void
+    {
+        _sort = value;
+    }
+
+    //--------------------------------------------------------------------------
+    //
+    // ICollectionView Methods
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  Returns a new instance of a view iterator over the items in this view.
+     *
+     *  @return IViewCursor instance.
+     *
+     *  @see mx.utils.IViewCursor
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function createCursor():IViewCursor
+    {
+        return new HierarchicalCollectionViewCursor(
+            this, treeData, hierarchicalData);
+    }
+
+    /**
+     *  Checks the collection for the data item using standard equality test.
+     *
+     *  @param item The Object that defines the node to look for.
+     *
+     *  @param true if the collection contains the item,
+     *
+     *  @return true if the data item is in the collection,
+     *  and false if not.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function contains(item:Object):Boolean
+    {
+        var cursor:IViewCursor = createCursor();
+        while (!cursor.afterLast)
+        {
+            if (cursor.current == item)
+                return true;
+
+            try
+            {
+                cursor.moveNext();
+            }
+            catch (e:ItemPendingError)
+            {
+                // item is pending.
+                // we are not sure if the item is present or not,
+                // so return false
+                return false;
+            }
+        }
+        return false;
+    }
+
+    /**
+     *  @private
+     */
+    public function disableAutoUpdate():void
+    {
+        // propogate to all the child collections
+        treeData.disableAutoUpdate();
+        for (var p:Object in childrenMap)
+            ICollectionView(childrenMap[p]).disableAutoUpdate();
+    }
+
+    /**
+     *  @private
+     */
+    public function enableAutoUpdate():void
+    {
+        // propogate to all the child collections
+        treeData.enableAutoUpdate();
+        for (var p:Object in childrenMap)
+            ICollectionView(childrenMap[p]).enableAutoUpdate();
+    }
+
+    /**
+     *  @private
+     */
+    public function itemUpdated(item:Object, property:Object = null,
+                                oldValue:Object = null,
+                                newValue:Object = null):void
+    {
+        var event:CollectionEvent =
+            new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
+        event.kind = CollectionEventKind.UPDATE;
+
+        var objEvent:PropertyChangeEvent =
+            new PropertyChangeEvent(PropertyChangeEvent.PROPERTY_CHANGE);
+        objEvent.source = item;
+        objEvent.property = property;
+        objEvent.oldValue = oldValue;
+        objEvent.newValue = newValue;
+        event.items.push(objEvent);
+
+        dispatchEvent(event);
+    }
+
+    /**
+     *  @inheritDoc
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function refresh():Boolean
+    {
+        return internalRefresh(true);
+    }
+
+    //--------------------------------------------------------------------------
+    //
+    // IHierarchicalCollectionView Methods
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     * @inheritDoc
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function getNodeDepth(node:Object):int
+    {
+        var depth:int = 1;
+        var parent:Object = getParentItem(node);
+
+        while(parent != null)
+        {
+        	parent = getParentItem(parent);
+        	depth++;
+        }
+    	depth = (hasRoot && !showRoot) ? (depth - 1) : depth;
+
+        // depth cant be less then 1
+        return (depth < 1) ? 1 : depth;
+    }
+
+    /**
+     *  Returns the parent of a node.
+     *  The parent of a top-level node is null.
+     *
+     *  @param node The Object that defines the node.
+     *
+     *  @return The parent node containing the node,
+     *  null for a top-level node,
+     *  and undefined if the parent cannot be determined.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function getParentItem(node:Object):*
+    {
+        var uid:String = UIDUtil.getUID(node);
+        if (parentMap.hasOwnProperty(uid))
+            return parentMap[uid];
+
+        return undefined;
+    }
+
+    /**
+     *  @inheritDoc
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function getChildren(node:Object):ICollectionView
+    {
+        // Using uid because XML cant be referenced correctly using Dictionary
+        var uid:String = UIDUtil.getUID(node);
+        var children:* = hierarchicalData.getChildren(node);
+
+        var childrenCollection:ICollectionView = childrenMapCache[uid];
+
+        if (children is XMLList && childrenCollection)
+        {
+            //We don't want to send a RESET type of collectionChange event in this case.
+            XMLListCollection(childrenCollection).mx_internal::dispatchResetEvent = false;
+            XMLListCollection(childrenCollection).source = children;
+
+            // refresh the collection to apply the sort/filter
+            childrenCollection.refresh();
+        }
+
+        // check the cache and return from it.
+        // useful in sorting/filtering.
+        if(childrenCollection)
+        {
+        	// node might have changed, so update the childrenMap
+        	childrenMap[node] = childrenCollection;
+            return childrenCollection;
+        }
+
+        // if there is no children, return null
+        if (!children)
+            return null;
+
+        //then wrap children in ICollectionView if necessary
+        if (children is ICollectionView)
+        {
+            childrenCollection = ICollectionView(children);
+        }
+        else if (children is Array)
+        {
+            childrenCollection = new ArrayCollection(children);
+        }
+        else if (children is XMLList)
+        {
+            childrenCollection =  new XMLListCollection(children);
+        }
+        else
+        {
+            var childArray:Array = new Array(children);
+            if (childArray != null)
+            {
+                childrenCollection =  new ArrayCollection(childArray);
+            }
+        }
+
+        childrenMapCache[uid] = childrenCollection;
+
+
+        var oldChildren:ICollectionView = childrenMap[node];
+        if (oldChildren != childrenCollection)
+        {
+            if (oldChildren != null)
+            {
+                oldChildren.removeEventListener(CollectionEvent.COLLECTION_CHANGE,
+                                      nestedCollectionChangeHandler);
+            }
+            childrenCollection.addEventListener(CollectionEvent.COLLECTION_CHANGE,
+                                          nestedCollectionChangeHandler, false, 0, true);
+            childrenMap[node] = childrenCollection;
+        }
+
+        return childrenCollection;
+    }
+
+    /**
+     *  @inheritDoc
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function openNode(node:Object):void
+    {
+		var uid:String = UIDUtil.getUID(node);
+
+		// check if the node is already opened
+		if (_openNodes[uid] != null)
+			return;
+
+        // add the node to the openNodes object and update the length
+        _openNodes[uid] = node;
+
+        // apply the sort/filter to the child collection of the opened node.
+        var childrenCollection:ICollectionView = getChildren(node);
+
+        // return if there are no children
+        if (!childrenCollection)
+            return;
+
+        if (sortCanBeApplied(childrenCollection) && !(childrenCollection.sort == null && sort == null))
+        {
+            childrenCollection.sort = this.sort;
+        }
+        if (!(childrenCollection.filterFunction == null && filterFunction == null))
+        {
+            childrenCollection.filterFunction = this.filterFunction;
+        }
+        childrenCollection.refresh();
+
+		updateParentMapAndLength(childrenCollection, node);
+    }
+
+    /**
+     *  @inheritDoc
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function closeNode(node:Object):void
+    {
+        var childrenCollection:ICollectionView = childrenMap[node];
+
+        // removes the node from the openNodes object and update the length
+        delete _openNodes[UIDUtil.getUID(node)];
+
+		if (childrenCollection)
+		{
+			var cursor:IViewCursor = childrenCollection.createCursor();
+			while (!cursor.afterLast)
+			{
+				var uid:String = UIDUtil.getUID(cursor.current);
+				delete parentMap[uid];
+
+				try
+				{
+					cursor.moveNext();
+				}
+				catch (e:ItemPendingError)
+				{
+					break;
+				}
+
+			}
+		}
+
+		// update the length
+		updateLength();
+    }
+
+    /**
+     *  @inheritDoc
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function addChild(parent:Object, newChild:Object):Boolean
+    {
+        if (parent == null)
+            return addChildAt(parent, newChild, treeData.length);
+        else
+            return addChildAt(parent, newChild, getChildren(parent).length);
+    }
+
+    /**
+     *  @inheritDoc
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function removeChild(parent:Object, child:Object):Boolean
+    {
+        var cursor:IViewCursor;
+        var index:int = 0;
+        if (parent == null)
+        {
+            cursor = treeData.createCursor();
+        }
+        else
+        {
+             var children:ICollectionView = getChildren(parent);
+             cursor = children.createCursor();
+        }
+        while (!cursor.afterLast)
+        {
+            if (cursor.current == child)
+            {
+                cursor.remove();
+                return true;
+            }
+
+            try
+            {
+                cursor.moveNext();
+            }
+            catch (e:ItemPendingError)
+            {
+                // Items are pending - so return false
+                return false;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     *  Add a child node to a node at the specified index.
+     *  This implementation does the following:
+     *
+     *

+     *
If the parent is null or undefined,
+     *          inserts the child at the
+     *          specified index in the collection specified
+     *          by source.
+     *

+     *
If the parent has a children
+     *          field or property, the method adds the child
+     *          to it at the index location.
+     *          In this case, the source is not required.
+     *

+     *
If the parent does not have a children
+     *          field or property, the method adds the children
+     *          to the parent. The method then adds the
+     *          child to the parent at the
+     *          index location.
+     *          In this case, the source is not required.
+     *

+     *
If the index value is greater than the collection
+     *         length or number of children in the parent, adds the object as
+     *         the last child.
+     *

+     *

+     *
+     *  @param node The Object that defines the parent node.
+     *
+     *  @param newChild The Object that defines the child node.
+     *
+     *  @param index The 0-based index of where to insert the child node.
+     *
+     *  @param source The entire collection that this node is a part of.
+     *
+     *  @return true if the child is added successfully.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function addChildAt(parent:Object, newChild:Object, index:int):Boolean
+    {
+        var cursor:IViewCursor;
+        if (!parent)
+        {
+            cursor = treeData.createCursor();
+        }
+        else
+        {
+            if (!hierarchicalData.canHaveChildren(parent))
+                return false;
+
+            var children:ICollectionView = getChildren(parent);
+
+            cursor = children.createCursor();
+        }
+
+        try
+        {
+            cursor.seek(CursorBookmark.FIRST, index);
+        }
+        catch (e:ItemPendingError)
+        {
+            // Item Pending
+            return false;
+        }
+
+        cursor.insert(newChild);
+
+        return true;
+    }
+
+    /**
+     *  Removes the child node from a node at the specified index.
+     *
+     *  @param parent The Object that defines the parent node.
+     *
+     *  @param index The 0-based index of  the child node to remove relative to the parent.
+     *
+     *  @return true if the child is removed successfully.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function removeChildAt(parent:Object, index:int):Boolean
+    {
+        var cursor:IViewCursor;
+        if (!parent)
+        {
+            cursor = treeData.createCursor();
+        }
+        else
+        {
+            var children:ICollectionView = getChildren(parent);
+            cursor = children.createCursor();
+        }
+
+        try
+        {
+            cursor.seek(CursorBookmark.FIRST, index);
+        }
+        catch (e:ItemPendingError)
+        {
+            // Item Pending
+            return false;
+        }
+
+        if (cursor.beforeFirst || cursor.afterLast)
+            return false;
+
+        cursor.remove();
+        return true;
+    }
+
+    //--------------------------------------------------------------------------
+    //
+    // Methods
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     * @private
+     *
+     * returns the collection view of the given object
+     */
+    private function getCollection(value:Object):ICollectionView
+    {
+        // handle strings and xml
+        if (typeof(value)=="string")
+            value = new XML(value);
+        else if (value is XMLNode)
+            value = new XML(XMLNode(value).toString());
+        else if (value is XMLList)
+            value = new XMLListCollection(value as XMLList);
+
+        if (value is XML)
+        {
+            var xl:XMLList = new XMLList();
+            xl += value;
+            return new XMLListCollection(xl);
+        }
+        //if already a collection dont make new one
+        else if (value is ICollectionView)
+        {
+            return ICollectionView(value);
+        }
+        else if (value is Array)
+        {
+            return new ArrayCollection(value as Array);
+        }
+        //all other types get wrapped in an ArrayCollection
+        else if (value is Object)
+        {
+            // convert to an array containing this one item
+            var tmp:Array = [];
+            tmp.push(value);
+            return new ArrayCollection(tmp);
+        }
+        else
+        {
+            return new ArrayCollection();
+        }
+    }
+
+    /**
+     *  @private
+     *
+     *  Initialize the collection. set its various properties and
+     *  update its length.
+     */
+    private function initializeCollection(model:Object,
+                            hierarchicalData:IHierarchicalData,
+                            argOpenNodes:Object = null):void
+    {
+        parentMap = {};
+
+        childrenMap = new Dictionary(true);
+        childrenMapCache = new Dictionary(true);
+
+        if (treeData)
+            treeData.removeEventListener(CollectionEvent.COLLECTION_CHANGE,
+                                         collectionChangeHandler,
+                                         false);
+
+        if (this.hierarchicalData)
+            this.hierarchicalData.removeEventListener(CollectionEvent.COLLECTION_CHANGE,
+                                         collectionChangeHandler,
+                                         false);
+
+        treeData = getCollection(model);
+
+        if (treeData)
+            _hasRoot = treeData.length == 1;
+
+        var tmpCollection:Object = model;
+        // are we swallowing the root?
+        if (hierarchicalData && !showRoot && hasRoot)
+        {
+        	var obj:Object = treeData.createCursor().current;
+            if (hierarchicalData.hasChildren(obj))
+            {
+                // then get rootItem children
+                tmpCollection = hierarchicalData.getChildren(obj);
+                treeData = getCollection(tmpCollection);
+            }
+        }
+
+        // listen for add/remove events from developer as weak reference
+        treeData.addEventListener(CollectionEvent.COLLECTION_CHANGE,
+                                  collectionChangeHandler,
+                                  false,
+                                  EventPriority.DEFAULT_HANDLER,
+                                  true);
+
+        this.hierarchicalData = hierarchicalData;
+
+        // listen for reset/refresh events
+        this.hierarchicalData.addEventListener(
+        							CollectionEvent.COLLECTION_CHANGE,
+                                 	collectionChangeHandler,
+                                 	false,
+                                 	EventPriority.DEFAULT_HANDLER,
+                                 	true);
+
+        // openNodes cant be null
+        if (argOpenNodes)
+            _openNodes = argOpenNodes;
+        else
+            _openNodes = {};
+
+        //calc initial length
+        currentLength = calculateLength();
+    }
+
+	/**
+	 *  @private
+	 *
+	 *  Update the parent map and adjust the length.
+	 */
+	private function updateParentMapAndLength(collection:ICollectionView, node:Object):void
+	{
+		var cursor:IViewCursor = collection.createCursor();
+		currentLength += collection.length;
+
+		while (!cursor.afterLast)
+		{
+			var item:Object = cursor.current;
+			var uid:String = UIDUtil.getUID(item);
+			parentMap[uid] = node;
+
+			// check that the node is opened or not.
+			// If it is open, then update the length with the node's children.
+			if (_openNodes[uid] != null)
+			{
+				var childrenCollection:ICollectionView = getChildren(item);
+				if (childrenCollection)
+					updateParentMapAndLength(childrenCollection, item);
+			}
+
+			try
+			{
+				cursor.moveNext();
+			}
+			catch (e:ItemPendingError)
+			{
+				break;
+			}
+		}
+	}
+
+    /**
+     *  @private
+     *  Calculate the total length of the collection, but only count nodes
+     *  that we can reach.
+     */
+    public function calculateLength(node:Object = null, parent:Object = null):int
+    {
+        var length:int = 0;
+        var childNodes:ICollectionView;
+        var modelOffset:int = 0;
+        var firstNode:Boolean = true;
+
+        if (node == null)
+        {
+            // special case counting the whole thing
+            // watch for page faults
+            var modelCursor:IViewCursor = treeData.createCursor();
+            if (modelCursor.beforeFirst)
+			{
+				// indicates that an IPE occured on the first item
+				return treeData.length;
+			}
+            while (!modelCursor.afterLast)
+            {
+                node = modelCursor.current;
+                if (node is XML)
+				{
+					if (firstNode)
+					{
+						firstNode = false;
+						var parNode:* = node.parent();
+						if (parNode != null)
+						{
+							startTrackUpdates(parNode);
+							childrenMap[parNode] = treeData;
+							parentNode = parNode;
+						}
+					}
+					startTrackUpdates(node);
+				}
+				if (node === null)
+					length += 1;
+				else
+                	length += calculateLength(node, null) + 1;
+                modelOffset++;
+                try
+                {
+                    modelCursor.moveNext();
+                }
+                catch (e:ItemPendingError)
+                {
+                    // just stop where we are, no sense paging
+                    // the whole thing just to get length. make a rough
+                    // guess assuming that all un-paged nodes are closed
+                    length += treeData.length - modelOffset;
+                    return length;
+                }
+            }
+        }
+        else
+        {
+            var uid:String = UIDUtil.getUID(node);
+            parentMap[uid] = parent;
+            if (node != null &&
+                openNodes[uid] &&
+                hierarchicalData.canHaveChildren(node) &&
+                hierarchicalData.hasChildren(node))
+            {
+                childNodes = getChildren(node);
+                if (childNodes != null)
+                {
+                    var childCursor:IViewCursor = childNodes.createCursor();
+                    try
+                    {
+                        childCursor.seek(CursorBookmark.FIRST);
+                        while (!childCursor.afterLast)
+                        {
+                        	if (node is XML)
+								startTrackUpdates(childCursor.current);
+                            length += calculateLength(childCursor.current, node) + 1;
+                            modelOffset++;
+
+                            try
+                            {
+                                childCursor.moveNext();
+                            }
+                            catch (e:ItemPendingError)
+                            {
+                                // just stop where we are, no sense paging
+                                // the whole thing just to get length. make a rough
+                                // guess assuming that all un-paged nodes are closed
+                                length += childNodes.length - modelOffset;
+                                return length;
+                            }
+                        }
+                    }
+                    catch (e:ItemPendingError)
+                    {
+                        // assume that the child collection has one item
+                        length += 1;
+                    }
+                }
+            }
+        }
+        return length;
+    }
+
+    /**
+     *  @private
+     */
+    private function internalRefresh(dispatch:Boolean):Boolean
+    {
+        var obj:Object;
+        var coll:ICollectionView
+        var needUpdate:Boolean = false;
+
+        // apply filter function to all the collections including the child collections
+    	if (!(treeData.filterFunction == null && filterFunction == null))
+    	{
+            treeData.filterFunction = filterFunction;
+            treeData.refresh();
+            needUpdate = true;
+        }
+
+        for each(obj in openNodes)
+        {
+            coll = getChildren(obj);
+            if (coll && !(coll.filterFunction == null && filterFunction == null))
+            {
+                coll.filterFunction = filterFunction;
+                coll.refresh();
+                needUpdate = true
+           	}
+        }
+
+        // if filter is applied to any collection, only then update the length
+        if (needUpdate)
+        	updateLength();  // length will change after filtering, so update it.
+
+
+        // apply sort to all the collections including the child collections
+        if (sortCanBeApplied(treeData) && !(treeData.sort == null && sort == null))
+        {
+            treeData.sort = sort;
+            treeData.refresh();
+            dispatch = true;
+        }
+
+        // recursive sort for every field
+        for each(obj in openNodes)
+        {
+
+            coll = getChildren(obj);
+
+            if (coll && sortCanBeApplied(coll) && !(coll.sort == null && sort == null))
+            {
+                coll.sort = sort;
+                coll.refresh();
+                dispatch = true;
+            }
+        }
+
+        // No concept of a sort level, so commenting the code
+        /* for(var i:int = 0;i<sort.fields.length;i++)
+        {
+            if(sort.fields[i].hasOwnProperty("sortLevel"))
+                sortLevel = sort.fields[i].sortLevel;
+            //else
+                //sortLevel = 1;
+
+
+            if(sortLevel == 1)
+            {
+                var srt:Sort = new Sort();
+
+                if(sort.usingCustomCompareFunction)
+                {
+                    srt.compareFunction = sort.compareFunction;
+                }
+
+                srt.unique = sort.unique;
+
+                srt.fields = [sort.fields[i]];
+                treeData.sort = srt;
+                treeData.refresh();
+            }
+            else
+            {
+                for each(var obj:Object in openNodes)
+                {
+
+                    var depth:int = 2;
+                    var o:Object = obj;
+                    while(getParentItem(o) != null)
+                    {
+                        depth++;
+                        o = getParentItem(o);
+                    }
+
+                    if(depth == sortLevel)
+                    {
+                        var coll:ICollectionView = getChildren(obj);
+
+                        var srt:Sort = new Sort();
+
+                        if(sort.usingCustomCompareFunction)
+                            srt.compareFunction = sort.compareFunction;
+
+                        srt.unique = sort.unique;
+
+                        srt.fields = [sort.fields[i]];
+
+                        coll.sort = srt;
+                        coll.refresh();
+                    }
+                }
+            }
+        } */
+
+        if (dispatch)
+        {
+            var refreshEvent:CollectionEvent =
+                new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
+            refreshEvent.kind = CollectionEventKind.REFRESH;
+            dispatchEvent(refreshEvent);
+        }
+        return true;
+    }
+
+    /**
+     * @private
+     * Check if a collection has the properties on which the sort is applied.
+     */
+    private function sortCanBeApplied(coll:ICollectionView):Boolean
+    {
+    	if (sort == null)
+    		return true;
+
+        // get the current item
+        var obj:Object = coll.createCursor().current;
+
+        if (!obj || !sort.fields)
+            return false;
+
+        // check for the properties (sort fields) in the current object
+        for (var i:int = 0; i < sort.fields.length; i++)
+        {
+            var sf:SortField = sort.fields[i];
+            if (!obj.hasOwnProperty(sf.name))
+                return false;
+        }
+        return true;
+    }
+
+    /**
+     * @private
+     * Force a recalulation of length
+     */
+     private function updateLength(node:Object=null, parent:Object = null):void
+     {
+        currentLength = calculateLength();
+     }
+
+    /**
+     * @private
+     *  Fill the node array with the node and all of its visible children
+     *  update the parentMap as you go.
+     */
+    private function getVisibleNodes(node:Object, parent:Object, nodeArray:Array):void
+    {
+        var childNodes:ICollectionView;
+        nodeArray.push(node);
+
+        var uid:String = UIDUtil.getUID(node);
+        parentMap[uid] = parent;
+        if (openNodes[uid] != null &&
+            hierarchicalData.canHaveChildren(node) &&
+            hierarchicalData.hasChildren(node))
+        {
+            childNodes = getChildren(node);
+            if (childNodes != null)
+            {
+                var cursor:IViewCursor = childNodes.createCursor();
+                while (!cursor.afterLast)
+                {
+                    getVisibleNodes(cursor.current, node, nodeArray);
+                    try
+                    {
+                        cursor.moveNext();
+                    }
+                    catch (e:ItemPendingError)
+                    {
+                        // Items are pending - so return
+                        return;
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     *  @private
+     *  Factor in the available open children before this location in the model
+     */
+    private function getVisibleLocation(oldLocation:int):int
+    {
+        var newLocation:int = 0;
+        var modelCursor:IViewCursor = treeData.createCursor();
+        for (var i:int = 0; i < oldLocation && !modelCursor.afterLast; i++)
+        {
+            newLocation += calculateLength(modelCursor.current, null) + 1;
+            try
+            {
+                modelCursor.moveNext();
+            }
+            catch (e:ItemPendingError)
+            {
+                // just return the location as the items are pending
+                return newLocation;
+            }
+        }
+        return newLocation;
+    }
+
+    /**
+     * @private
+     * factor in the open children before this location in a sub collection
+     */
+    private function getVisibleLocationInSubCollection(parent:Object, oldLocation:int):int
+    {
+        var newLocation:int = oldLocation;
+        var target:Object = parent;
+        parent = getParentItem(parent);
+        var children:ICollectionView;
+        var cursor:IViewCursor;
+        while (parent != null)
+        {
+            children = childrenMap[parent];
+            cursor = children.createCursor();
+            while (!cursor.afterLast)
+            {
+                if (cursor.current == target)
+                {
+                    newLocation++;
+                    break;
+                }
+                newLocation += calculateLength(cursor.current, parent) + 1;
+                try
+                {
+                    cursor.moveNext();
+                }
+                catch (e:ItemPendingError)
+                {
+                    break;
+                }
+            }
+            target = parent;
+            parent = getParentItem(parent);
+        }
+        cursor = treeData.createCursor();
+        while (!cursor.afterLast)
+        {
+            if (cursor.current == target)
+            {
+                newLocation++;
+                break;
+            }
+            newLocation += calculateLength(cursor.current, parent) + 1;
+            try
+            {
+                cursor.moveNext();
+            }
+            catch (e:ItemPendingError)
+            {
+                break;
+            }
+        }
+        return newLocation;
+    }
+
+    //--------------------------------------------------------------------------
+    //
+    //  Event handlers
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  @private
+     */
+    public function collectionChangeHandler(event:CollectionEvent):void
+    {
+        var i:int;
+        var n:int;
+        var location:int;
+        var uid:String;
+        var parent:Object;
+        var node:Object;
+        var items:Array;
+
+        var convertedEvent:CollectionEvent;
+
+        if (event is CollectionEvent)
+        {
+            var ce:CollectionEvent = CollectionEvent(event);
+            if (ce.kind == CollectionEventKind.RESET)
+            {
+                // initialize the collection again - its source is modified
+                if (hierarchicalData)
+                    initializeCollection(hierarchicalData.getRoot(), hierarchicalData, openNodes);
+                updateLength();
+                internalRefresh(false);
+                dispatchEvent(event);
+            }
+            else if (ce.kind == CollectionEventKind.ADD)
+            {
+                n = ce.items.length;
+                convertedEvent = new CollectionEvent(
+                                        CollectionEvent.COLLECTION_CHANGE,
+                                        false,
+                                        true,
+                                        ce.kind);
+                convertedEvent.location = getVisibleLocation(ce.location);
+                for (i = 0; i < n; i++)
+                {
+                    node = ce.items[i];
+                    if (node is XML)
+						startTrackUpdates(node);
+                    getVisibleNodes(node, null, convertedEvent.items);
+                }
+                currentLength += convertedEvent.items.length;
+                dispatchEvent(convertedEvent);
+            }
+            else if (ce.kind == CollectionEventKind.REMOVE)
+            {
+                n = ce.items.length;
+                convertedEvent = new CollectionEvent(
+                                        CollectionEvent.COLLECTION_CHANGE,
+                                        false,
+                                        true,
+                                        ce.kind);
+                convertedEvent.location = getVisibleLocation(ce.location);
+                for (i = 0; i < n; i++)
+                {
+                    node = ce.items[i];
+                    if (node is XML)
+						stopTrackUpdates(node);
+                    getVisibleNodes(node, null, convertedEvent.items);
+                }
+                currentLength -= convertedEvent.items.length;
+                dispatchEvent(convertedEvent);
+
+            }
+            else if (ce.kind == CollectionEventKind.UPDATE)
+            {
+                // so far, nobody cares about the details so just
+                // send it
+                dispatchEvent(event);
+            }
+            else if (ce.kind == CollectionEventKind.REPLACE)
+            {
+                // someday handle case where node is marked as open
+                // before it becomes the replacement.
+                // for now, just pass on the data and remove
+                // old visible rows
+                n = ce.items.length;
+                convertedEvent = new CollectionEvent(
+                                        CollectionEvent.COLLECTION_CHANGE,
+                                        false,
+                                        true,
+                                        CollectionEventKind.REMOVE);
+
+                for (i = 0; i < n; i++)
+                {
+                    node = ce.items[i].oldValue;
+                    if (node is XML)
+						stopTrackUpdates(node);
+                    getVisibleNodes(node, null, convertedEvent.items);
+                }
+
+                // prune the replacements from this list
+                var j:int = 0;
+                for (i = 0; i < n; i++)
+                {
+                    node = ce.items[i].oldValue;
+                    while (convertedEvent.items[j] != node)
+                        j++;
+                    convertedEvent.items.splice(j, 1);
+                }
+                if (convertedEvent.items.length)
+                {
+                    currentLength -= convertedEvent.items.length;
+                    // nobody cares about location yet.
+                    dispatchEvent(convertedEvent);
+                }
+                dispatchEvent(event);
+            }
+        }
+    }
+
+    /**
+     *  @private
+     */
+    public function nestedCollectionChangeHandler(event:CollectionEvent):void
+    {
+        var i:int;
+        var n:int;
+        var location:int;
+        var uid:String;
+        var parent:Object;
+        var node:Object;
+        var items:Array;
+        var convertedEvent:CollectionEvent;
+
+        if (event is CollectionEvent)
+        {
+            var ce:CollectionEvent = CollectionEvent(event);
+            if (ce.kind == CollectionEventKind.mx_internal::EXPAND)
+            {
+                event.stopImmediatePropagation();
+            }
+            else if (ce.kind == CollectionEventKind.ADD)
+            {
+                // optimize someday.  We do a full tree walk so we can
+                // not only count how many but find the parents of the
+                // new nodes.  A better scheme would be to just
+                // increment by the number of visible nodes, but we
+                // don't have a good way to get the parents.
+                updateLength();
+                n = ce.items.length;
+                convertedEvent = new CollectionEvent(
+                                        CollectionEvent.COLLECTION_CHANGE,
+                                        false,
+                                        true,
+                                        ce.kind);
+                for (i = 0; i < n; i++)
+                {
+                    node = ce.items[i];
+                    if (node is XML)
+						startTrackUpdates(node);
+                    parent = getParentItem(node);
+                    if (parent != null)
+                        getVisibleNodes(node, parent, convertedEvent.items);
+                }
+                convertedEvent.location = getVisibleLocationInSubCollection(parent, ce.location);
+                dispatchEvent(convertedEvent);
+            }
+            else if (ce.kind == CollectionEventKind.REMOVE)
+            {
+                n = ce.items.length;
+                convertedEvent = new CollectionEvent(
+                                        CollectionEvent.COLLECTION_CHANGE,
+                                        false,
+                                        true,
+                                        ce.kind);
+                for (i = 0; i < n; i++)
+                {
+                    node = ce.items[i];
+                    if (node is XML)
+						stopTrackUpdates(node);
+                    parent = getParentItem(node);
+                    if (parent != null)
+                        getVisibleNodes(node, parent, convertedEvent.items);
+                }
+                convertedEvent.location = getVisibleLocationInSubCollection(parent, ce.location);
+                currentLength -= convertedEvent.items.length;
+                dispatchEvent(convertedEvent);
+            }
+            else if (ce.kind == CollectionEventKind.UPDATE)
+            {
+                // so far, nobody cares about the details so just
+                // send it
+                dispatchEvent(event);
+            }
+            else if (ce.kind == CollectionEventKind.REPLACE)
+            {
+                // someday handle case where node is marked as open
+                // before it becomes the replacement.
+                // for now, just pass on the data and remove
+                // old visible rows
+                n = ce.items.length;
+                convertedEvent = new CollectionEvent(
+                                        CollectionEvent.COLLECTION_CHANGE,
+                                        false,
+                                        true,
+                                        CollectionEventKind.REMOVE);
+
+                for (i = 0; i < n; i++)
+                {
+                    node = ce.items[i].oldValue;
+                    parent = getParentItem(node);
+
+                    if (parent != null)
+					{
+                        getVisibleNodes(node, parent, convertedEvent.items);
+						// update the parent of the new item only
+						// if the parent node is opened
+						if (_openNodes[UIDUtil.getUID(parent)] != null)
+						{
+							var newNode:Object = ce.items[i].newValue;
+							uid = UIDUtil.getUID(newNode);
+							parentMap[uid] = parent;
+
+							// delete the parent map for the old node
+							delete parentMap[UIDUtil.getUID(node)];
+						}
+					}
+                }
+
+                // prune the replacements from this list
+                var j:int = 0;
+                for (i = 0; i < n; i++)
+                {
+                    node = ce.items[i].oldValue;
+					if (node is XML)
+						stopTrackUpdates(node);
+                    while (convertedEvent.items[j] != node)
+                        j++;
+                    convertedEvent.items.splice(j, 1);
+                }
+                if (convertedEvent.items.length)
+                {
+                    currentLength -= convertedEvent.items.length;
+                    // nobody cares about location yet.
+                    dispatchEvent(convertedEvent);
+                }
+                dispatchEvent(event);
+            }
+            else if (ce.kind == CollectionEventKind.RESET)
+            {
+                // removeAll() sends a RESET.
+                // when we get a reset we don't know what went away
+                // and we don't know how many things went away, so
+                // we just fake a refresh as if there was a filter
+                // applied that filtered out whatever went away
+                updateLength();
+                convertedEvent = new CollectionEvent(
+                                        CollectionEvent.COLLECTION_CHANGE,
+                                        false,
+                                        true,
+                                        CollectionEventKind.REFRESH);
+                dispatchEvent(convertedEvent);
+            }
+        }
+    }
+
+    /**
+     * Called whenever an XML object contained in our list is updated
+     * in some way.  The initial implementation stab is very lenient,
+     * any changeType will cause an update no matter how much further down
+     * in a hierarchy.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function xmlNotification(currentTarget:Object,
+                                        type:String,
+                                        target:Object,
+                                        value:Object,
+                                        detail:Object):void
+    {
+        var prop:String;
+        var oldValue:Object;
+        var newValue:Object;
+		var children:XMLListCollection;
+		var location:int;
+        var event:CollectionEvent;
+		var list:XMLListAdapter;
+
+		// trace("currentTarget", currentTarget.toXMLString());
+		// trace("target", target.toXMLString());
+		// trace("value", value.toXMLString());
+		// trace("type", type);
+
+		if (currentTarget === target)
+        {
+	        switch(type)
+	        {
+	            case "nodeAdded":
+	            {
+					for (var q:* in childrenMap)
+					{
+						if (q === currentTarget)
+						{
+							list = childrenMap[q].list as XMLListAdapter;
+							if (list && !list.busy())
+							{
+								if (childrenMap[q] === treeData)
+								{
+									children = treeData as XMLListCollection;
+									if (parentNode != null)
+									{
+										children.mx_internal::dispatchResetEvent = false;
+										children.source = parentNode.*;
+										children.refresh();
+									}
+								}
+								else
+								{
+									// this should refresh the collection
+									children = getChildren(q) as XMLListCollection;
+								}
+								if (children)
+								{
+									// now we fake an event on behalf of the
+									// child collection
+									location = value.childIndex();
+									event = new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
+									event.kind = CollectionEventKind.ADD;
+									event.location = location;
+									event.items = [ value ];
+									children.dispatchEvent(event);
+								}
+							}
+							break;
+						}
+					}
+	                break;
+	            }
+
+				/* needed?
+	            case "nodeChanged":
+	            {
+	                prop = value.localName();
+	                oldValue = detail;
+	                newValue = value;
+	                break;
+	            }
+				*/
+
+	            case "nodeRemoved":
+	            {
+					// lookup doesn't work, must scan instead
+					for (var p:* in childrenMap)
+					{
+						if (p === currentTarget)
+						{
+							children = childrenMap[p];
+							list = children.list as XMLListAdapter;
+							if (list && !list.busy())
+							{
+								var xmllist:XMLList = children.source as XMLList;
+
+								if (childrenMap[p] === treeData)
+								{
+									children = treeData as XMLListCollection;
+									if (parentNode)
+									{
+										children.mx_internal::dispatchResetEvent = false;
+										children.source = parentNode.*;
+										children.refresh();
+									}
+								}
+								else
+								{
+									var oldChildren:XMLListCollection = children;
+									// this should refresh the collection
+									children = getChildren(p) as XMLListCollection;
+									if (!children)
+									{
+										// last item got removed so there's no child collection
+    									oldChildren.addEventListener(CollectionEvent.COLLECTION_CHANGE,
+    																  nestedCollectionChangeHandler, false, 0, true);
+
+										event = new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
+										event.kind = CollectionEventKind.REMOVE;
+										event.location = 0;
+										event.items = [ value ];
+										oldChildren.dispatchEvent(event);
+    									oldChildren.removeEventListener(CollectionEvent.COLLECTION_CHANGE,
+    																  nestedCollectionChangeHandler);
+
+									}
+								}
+								if (children)
+								{
+									var n:int = xmllist.length();
+									for (var i:int = 0; i < n; i++)
+									{
+										if (xmllist[i] === value)
+										{
+											event = new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
+											event.kind = CollectionEventKind.REMOVE;
+											event.location = location;
+											event.items = [ value ];
+											children.dispatchEvent(event);
+											break;
+										}
+									}
+								}
+							}
+							break;
+						}
+					}
+	                break;
+	            }
+
+	            default:
+				{
+	                break;
+				}
+	        }
+        }
+    }
+
+    /**
+     *  This is called by addItemAt and when the source is initially
+     *  assigned.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    private function startTrackUpdates(item:Object):void
+    {
+        XMLNotifier.getInstance().watchXML(item, this);
+    }
+
+    /**
+     *  This is called by removeItemAt, removeAll, and before a new
+     *  source is assigned.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    private function stopTrackUpdates(item:Object):void
+    {
+        XMLNotifier.getInstance().unwatchXML(item, this);
+    }
+}
+
+}


Transferred from the Adobe Open Source Subversion Repository

Revision: 21882
Author:   aaltman@adobe.com
Date:     2011-08-05T23:10:29.686539Z

Log Message:
-----------
Don't let StageText get a rectangle with negative dimensions or non-integer coordinates.
Make sure taps on the padding around StageText request a soft keyboard.
Fixed flicker at the end of view transitions when StageText hides.
Fixed setting StyleableStageText.text to null.
Changed default autoCorrect value to true.

QE notes: None
Doc notes: None
Bugs: SDK-30737 SDK-30991 SDK-31008 SDK-31012 SDK-31013
Reviewer: cframpto
Tests run: checkintests mustella-mobile
Is noteworthy for integration: No

Modified Paths:
--------------
<path kind="file" action="M">/private/flex/sdk/branches/4.y/frameworks/projects/mobilecomponents/src/spark/components/supportClasses/StyleableStageText.as</path>
<path kind="file" action="M">/private/flex/sdk/branches/4.y/frameworks/projects/spark/src/spark/components/supportClasses/SkinnableTextBase.as</path>

git-svn-id: 7146a936b37d36e51ea0d66f8acbe0b8281bc7b7@1282886 13f79535-47bb-0310-9956-ffa450edef68

--- frameworks/projects/spark/src/spark/components/supportClasses/SkinnableTextBase.as
+++ frameworks/projects/spark/src/spark/components/supportClasses/SkinnableTextBase.as
@@ -1448,7 +1448,7 @@
             return softKeyboardClient.autoCorrect;

         var v:* = textDisplay ? undefined : textDisplayProperties.autoCorrect;
-        return (v === undefined) ? false : v;
+        return (v === undefined) ? true : v;
     }

     public function set autoCorrect(value:Boolean):void


Transferred from the Adobe Open Source Subversion Repository

Revision: 7554
Author:   cframpto@adobe.com
Date:     2009-06-04T17:33:18.612906Z

Log Message:
-----------
-Dispatch FlexEvent.VALUE_COMMIT events from TextArea/TextInput when text changes.  This is the default trigger event for the validator.
- Added [DefaultTriggerEvent] tag to TextArea/TextInput per mail from Sameer Bhatt from FB.
- Made RET text bindable.

QA Notes:
Doc Notes:
Bugs: SDK-20165, SDK-20667
Reviewers: Gordon

Modified Paths:
--------------
<path kind="file" action="M">/flex/sdk/trunk/frameworks/projects/flex4/src/spark/components/supportClasses/TextBase.as</path>
<path kind="file" action="M">/flex/sdk/trunk/frameworks/projects/flex4/src/spark/primitives/RichEditableText.as</path>
<path kind="file" action="M">/flex/sdk/trunk/frameworks/projects/flex4/src/spark/components/TextArea.as</path>
<path kind="file" action="M">/flex/sdk/trunk/frameworks/projects/flex4/src/spark/components/TextInput.as</path>

git-svn-id: 7146a936b37d36e51ea0d66f8acbe0b8281bc7b7@1282821 13f79535-47bb-0310-9956-ffa450edef68

--- frameworks/projects/spark/src/spark/components/supportClasses/SkinnableTextBase.as
+++ frameworks/projects/spark/src/spark/components/supportClasses/SkinnableTextBase.as
@@ -744,7 +744,10 @@
             textViewProperties.text = value;
         }

-        invalidateProperties();
+        invalidateProperties();
+
+        // The default event to trigger a validator.
+        dispatchEvent(new FlexEvent(FlexEvent.VALUE_COMMIT));
      }

     //----------------------------------
@@ -1315,6 +1318,9 @@

         // Redispatch the event that came from the RichEditableText.
         dispatchEvent(event);
+
+        // The default event to trigger a validator.
+        dispatchEvent(new FlexEvent(FlexEvent.VALUE_COMMIT));
     }

     /**


Transferred from the Adobe Open Source Subversion Repository

Revision: 23243
Author:   cframpto@adobe.com
Date:     2011-12-20T00:59:57.384047Z

Log Message:
-----------
In frameworks, remove Adobe headers from all files except xml/mxml file types.  There are also a few .txt files that are license files that I didn't touch yet.

Modified Paths:
--------------
2361 paths were modified

git-svn-id: 7146a936b37d36e51ea0d66f8acbe0b8281bc7b7@1284204 13f79535-47bb-0310-9956-ffa450edef68

--- frameworks/projects/spark/src/spark/effects/supportClasses/AnimateColorInstance.as
+++ frameworks/projects/spark/src/spark/effects/supportClasses/AnimateColorInstance.as
@@ -1,13 +1,3 @@
-////////////////////////////////////////////////////////////////////////////////
-//
-//  ADOBE SYSTEMS INCORPORATED
-//  Copyright 2008 Adobe Systems Incorporated
-//  All Rights Reserved.
-//
-//  NOTICE: Adobe permits you to use, modify, and distribute this file
-//  in accordance with the terms of the license agreement accompanying it.
-//
-////////////////////////////////////////////////////////////////////////////////

 package spark.effects.supportClasses
 {


fixed null pointer error

fixed null pointer error

--- WeaveUI/src/weave/utils/PopUpUtils.as
+++ WeaveUI/src/weave/utils/PopUpUtils.as
@@ -27,7 +27,6 @@
 	import mx.controls.Alert;
 	import mx.controls.ToolTip;
 	import mx.core.IFlexDisplayObject;
-	import mx.core.UIComponent;
 	import mx.events.CloseEvent;
 	import mx.managers.PopUpManager;

@@ -76,7 +75,7 @@
 								noVoidFunction();
 						}
 					}
-				);
+				);
 			Alert.yesLabel = null;
 			Alert.noLabel = null;
 			Alert.buttonWidth = prevButtonWidth;
@@ -97,7 +96,6 @@
 			tip.mouseChildren = false;
 			tip.text = text;
 			tip.validateNow();
-			show();

 			// Periodically bring tooltip to front so user sees it.
 			// This is required in case the user clicks on another popup that obscures the tooltip.
@@ -106,6 +104,8 @@
 			timer.addEventListener(TimerEvent.TIMER, show);
 			timer.addEventListener(TimerEvent.TIMER_COMPLETE, hide);
 			timer.start();
+
+			show();

 			function show(_:* = null):void
 			{


Rewrote padding logic; now seems to play video with no issues.

--- HLSPlugin/src/com/kaltura/hls/manifest/HLSManifestEncryptionKey.as
+++ HLSPlugin/src/com/kaltura/hls/manifest/HLSManifestEncryptionKey.as
@@ -22,7 +22,7 @@
 	public class HLSManifestEncryptionKey extends EventDispatcher
 	{
 		private static const LOADER_CACHE:Dictionary = new Dictionary();
-		private var _key:  FastAESKey;
+		private var _key:FastAESKey;
 		public var usePadding:Boolean = false;
 		public var iv:String = "";
 		public var url:String = "";
@@ -159,29 +159,30 @@
 			}
 			return decrypt;
 		}
-		public function unpad(a : ByteArray) : ByteArray {
-			var c : uint = a.length % 16;
-			if (c != 0) {
-				trace("PKCS#5::unpad: ByteArray.length isn't a multiple of the blockSize");
+		public function unpad(bytesToUnpad : ByteArray) : ByteArray {
+			if ((bytesToUnpad.length % 16) != 0)
+			{
+				throw new Error("PKCS#5::unpad: ByteArray.length isn't a multiple of the blockSize");
 				return a;
 			}
-			c = a[a.length - 1];
-			var success:Boolean = true;
-			var newLength:uint = a.length;
-			for (var i : uint = c; i > 0; i--) {
-				var v : uint = a[a.length - 1];
-				if (c != v) {
-					trace("PKCS#5:unpad: Invalid padding value. expected [" + c + "], found [" + v + "]");
-					success = false;
-					break;
+
+			const paddingValue:int = bytesToUnpad[bytesToUnpad.length - 1];
+			var doUnpad:Boolean = true;
+			for (var i:int = 0; i<paddingValue; i++) {
+				var readValue:int = bytesToUnpad[bytesToUnpad.length - (1 + i)];
+				if (paddingValue != readValue) {
+					//throw new Error("PKCS#5:unpad: Invalid padding value. expected [" + paddingValue + "], found [" + readValue + "]");
+					//break;
+					doUnpad = false;
 				}
-				newLength--;
-			}
-			if (success){
-				a.length = newLength;
-			}
-			return a;
-		}
+			}
+
+			if(doUnpad)
+				bytesToUnpad.length -= paddingValue;
+
+			return bytesToUnpad;
+		}
+
 		public function retrieveStoredIV():ByteArray
 		{
 			trace("IV of " + iv + " for " + url + ", key=" + Hex.fromArray(_keyData));


Transferred from the Adobe Open Source Subversion Repository

Revision: 7062
Author:   dloverin@adobe.com
Date:     2009-05-19T11:16:05.869220Z

Log Message:
-----------
Spark WindowedApplication fixes.

https://bugs.adobe.com/jira/browse/SDK-21186

Fix returning a bogus state.

spark.components.Window
spark.components.WindowedApplication
                Return “disabled” instead of “disableActive”. “disabledActive” was renamed to “disabled” but the code didn’t get updated.

http://bugs.adobe.com/jira/browse/SDK-21039

Fix returning an out of range value from the “type” and “systemChrome” properties.

mx.core.WindowedApplication
spark.components.WindowedApplication

                get type()
                                The initial Window is always normal so don’t bother with getting the nativeWindow.

                get systemChrome()
                                Fix returning an out of range value.  Set the value as soon as possible and stick with it.

                override initialize() to set _systemChrome as early as possible.
                Initialize _nativateWindow in initialize() instead of in the createComplete handler. This seems better but doesn’t fix a bug.

QE Notes: None.
Doc Notes: None.
Bugs: SDK-21186, SDK-21039
Reviewer: Darrell
tests: checkintests

Modified Paths:
--------------
<path kind="file" action="M">/flex/sdk/trunk/frameworks/projects/airframework/src/spark/components/WindowedApplication.as</path>
<path kind="file" action="M">/flex/sdk/trunk/frameworks/projects/airframework/src/spark/components/Window.as</path>
<path kind="file" action="M">/flex/sdk/trunk/frameworks/projects/airframework/src/mx/core/WindowedApplication.as</path>

git-svn-id: 7146a936b37d36e51ea0d66f8acbe0b8281bc7b7@1250507 13f79535-47bb-0310-9956-ffa450edef68

--- frameworks/projects/airspark/src/spark/components/Window.as
+++ frameworks/projects/airspark/src/spark/components/Window.as
@@ -2291,7 +2291,7 @@
             return "disabled";

         if (nativeWindow.active)
-            return enabled ? "normal" : "disabledActive";
+            return enabled ? "normal" : "disabled";
         else
             return enabled ? "normalInactive" : "disabledInactive";


Transferred from the Adobe Open Source Subversion Repository

Revision: 3035
Author:   jvroom@adobe.com
Date:     2008-08-29T06:18:11.275196Z

Log Message:
-----------
* Added HTTPMultiService component - refactored the guts of HTTPService into a new
class AbstractOperation which HTTPService now wraps.

* Moved concurrency and showBusyCursor classes up to the mx.rpc level from mx.rpc.mxml.
Partly this improves consistency and partly because it is awkward to implement them
with the wrapping design in the subclass.  This does introduce a new dependency on
CursorManager in mx.rpc.HTTPService, though I think that should turn into a "runtime binding"
so we remove the compile time binding altogether.

* Added managers, operationManager, resultType, resultElementType, properties to the
AbstractService and AbstractInvoker classes.  These are used to improve the metadata information
on these operations for better tooling in the future, and to allow management services to
tie into the service infrastructure.

* AsyncToken gets a default parameter for its constructor so it can be used in MXML.

* Moved endpoint property up from the MXML to the regular mx.rpc version to improve consistency

The blazeds RPC tests passed unfortunately I had problems getting the RPC tests in the sdk branch
to build and run so let me know if you see any problems on those.

Modified Paths:
--------------
<path kind="file" action="M">/flex/sdk/trunk/frameworks/projects/rpc/src/mx/rpc/remoting/mxml/RemoteObject.as</path>
<path kind="file" action="M">/flex/sdk/trunk/frameworks/projects/rpc/src/mx/rpc/AbstractOperation.as</path>
<path kind="file" action="M">/flex/sdk/trunk/frameworks/projects/rpc/src/mx/rpc/AbstractService.as</path>
<path kind="file" action="M">/flex/sdk/trunk/frameworks/projects/rpc/src/mx/rpc/remoting/Operation.as</path>
<path kind="file" action="A">/flex/sdk/trunk/frameworks/projects/rpc/src/mx/rpc/http/HTTPMultiService.as</path>
<path kind="file" action="M">/flex/sdk/trunk/frameworks/projects/rpc/src/mx/rpc/http/mxml/HTTPService.as</path>
<path kind="file" action="M">/flex/sdk/trunk/frameworks/projects/rpc/src/mx/rpc/AbstractInvoker.as</path>
<path kind="file" action="A">/flex/sdk/trunk/frameworks/projects/rpc/src/mx/rpc/http/SerializationFilter.as</path>
<path kind="file" action="M">/flex/sdk/trunk/frameworks/projects/rpc/src/mx/rpc/soap/Operation.as</path>
<path kind="file" action="A">/flex/sdk/trunk/frameworks/projects/rpc/src/mx/rpc/http/AbstractOperation.as</path>
<path kind="file" action="M">/flex/sdk/trunk/frameworks/projects/rpc/manifest.xml</path>
<path kind="file" action="M">/flex/sdk/trunk/frameworks/projects/rpc/src/mx/rpc/remoting/RemoteObject.as</path>
<path kind="file" action="M">/flex/sdk/trunk/frameworks/projects/rpc/src/mx/rpc/soap/mxml/WebService.as</path>
<path kind="file" action="M">/flex/sdk/trunk/frameworks/projects/rpc/src/mx/rpc/AsyncToken.as</path>
<path kind="file" action="M">/flex/sdk/trunk/frameworks/projects/rpc/src/mx/rpc/http/HTTPService.as</path>
<path kind="file" action="A">/flex/sdk/trunk/frameworks/projects/rpc/src/mx/rpc/http/Operation.as</path>

git-svn-id: 7146a936b37d36e51ea0d66f8acbe0b8281bc7b7@1274181 13f79535-47bb-0310-9956-ffa450edef68

--- frameworks/projects/rpc/src/mx/rpc/http/HTTPMultiService.as
+++ frameworks/projects/rpc/src/mx/rpc/http/HTTPMultiService.as
@@ -0,0 +1,421 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  ADOBE SYSTEMS INCORPORATED
+//  Copyright 2005-2007 Adobe Systems Incorporated
+//  All Rights Reserved.
+//
+//  NOTICE: Adobe permits you to use, modify, and distribute this file
+//  in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.rpc.http
+{
+
+import mx.core.mx_internal;
+import mx.logging.ILogger;
+import mx.logging.Log;
+import mx.messaging.ChannelSet;
+import mx.messaging.channels.DirectHTTPChannel;
+import mx.messaging.config.LoaderConfig;
+import mx.messaging.messages.HTTPRequestMessage;
+import mx.resources.IResourceManager;
+import mx.resources.ResourceManager;
+import mx.rpc.AbstractService;
+import mx.rpc.events.FaultEvent;
+import mx.utils.URLUtil;
+
+use namespace mx_internal;
+
+/**
+ *  Dispatched when an HTTPMultiService call returns successfully.
+ * @eventType mx.rpc.events.ResultEvent.RESULT
+ */
+[Event(name="result", type="mx.rpc.events.ResultEvent")]
+
+/**
+ *  Dispatched when an HTTPMultiService call fails.
+ * @eventType mx.rpc.events.FaultEvent.FAULT
+ */
+[Event(name="fault", type="mx.rpc.events.FaultEvent")]
+
+/**
+ *  The invoke event is fired when an HTTPMultiService call is invoked so long as
+ *  an Error is not thrown before the Channel attempts to send the message.
+ * @eventType mx.rpc.events.InvokeEvent.INVOKE
+ */
+[Event(name="invoke", type="mx.rpc.events.InvokeEvent")]
+
+[ResourceBundle("rpc")]
+
+/**
+ *  You use the <mx:HTTPMultiService> tag to represent a
+ *  collection of http operations.  Each one has a URL, method, parameters and
+ *  return type.  You can set attributes such as the URL, method etc. on the
+ *  HTTPMultiService tag to act as defaults for values set on each individual
+ *  operation tag.  The URL of the HTTPMultiService serves as the base url (i.e. the prefix)
+ *  for any relative urls set on the http operation tags.
+ *  Each http operation has a send() method, which makes an HTTP request to the
+ *  specified URL, and an HTTP response is returned. You can pass
+ *  parameters to the specified URL which are used to put data into the HTTP request.
+ *  The contentType property specifies a mime-type which is used to determine the over-the-wire
+ *  data format (i.e. HTTP forms, XML).  You can also use a serialization filter to
+ *  implement a custom resultFormat such as JSON.
+ *  When you do not go through the server-based
+ *  proxy service, you can use only HTTP GET or POST methods. However, when you set
+ *  the useProxy  property to true and you use the server-based proxy service, you
+ *  can also use the HTTP HEAD, OPTIONS, TRACE, and DELETE methods.
+ *
+ *
Note: Due to a software limitation, like HTTPService, the HTTPMultiService does
+ *  not generate user-friendly error messages when using GET and not using a proxy.

+ *  @see mx.rpc.http.mxml.HTTPMultiService, mx.rpc.http.HTTPService, mx.rpc.http.HTTPOperation
+ */
+[DefaultProperty("operationList")]
+public dynamic class HTTPMultiService extends AbstractService
+{
+    //--------------------------------------------------------------------------
+    //
+    // Constructor
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  Creates a new HTTPService. If you expect the service to send using relative URLs you may
+     *  wish to specify the rootURL that will be the basis for determining the full URL (one example
+     *  would be Application.application.url).
+     *
+     * @param rootURL The URL the HTTPService should use when computing relative URLS.
+     */
+    public function HTTPMultiService(rootURL:String = null, destination:String = null)
+    {
+        super();
+
+        makeObjectsBindable = true;
+
+        if (destination == null)
+        {
+            if (URLUtil.isHttpsURL(LoaderConfig.url))
+                asyncRequest.destination = HTTPService.DEFAULT_DESTINATION_HTTPS;
+            else
+                asyncRequest.destination = HTTPService.DEFAULT_DESTINATION_HTTP;
+        }
+        else
+            asyncRequest.destination = destination;
+
+        _log = Log.getLogger("mx.rpc.http.HTTPMultiService");
+    }
+
+    //--------------------------------------------------------------------------
+    //
+    // Variables
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  @private
+     *  A shared direct Http channelset used for service instances that do not use the proxy.
+     */
+    private static var _directChannelSet:ChannelSet;
+
+    /**
+     *  @private
+     *  Logger
+     */
+    private var _log:ILogger;
+
+    /**
+     *  @private
+     */
+    private var resourceManager:IResourceManager = ResourceManager.getInstance();
+
+    //--------------------------------------------------------------------------
+    //
+    // Properties
+    //
+    //--------------------------------------------------------------------------
+
+    //----------------------------------
+    //  contentType
+    //----------------------------------
+
+    [Inspectable(enumeration="application/x-www-form-urlencoded,application/xml", defaultValue="application/x-www-form-urlencoded", category="General")]
+    /**
+     *  Type of content for service requests.
+     *  The default is application/x-www-form-urlencoded which sends requests
+     *  like a normal HTTP POST with name-value pairs. application/xml send
+     *  requests as XML.
+     */
+    public var contentType:String = AbstractOperation.CONTENT_TYPE_FORM;
+
+    //----------------------------------
+    //  headers
+    //----------------------------------
+
+    [Inspectable(defaultValue="undefined", category="General")]
+    /**
+     *  Custom HTTP headers to be sent to the third party endpoint. If multiple headers need to
+     *  be sent with the same name the value should be specified as an Array.  These headers are sent
+     *  to all operations.  You can also set headers at the operation level.
+     */
+    public var headers:Object = {};
+
+    //----------------------------------
+    //  makeObjectsBindable
+    //----------------------------------
+
+    [Inspectable(defaultValue="true", category="General")]
+    /**
+     *  When true, the objects returned support data binding to UI controls - i.e. they
+     *  send PropertyChangeEvents when their property values are being changed.  This is the
+     *  default value for any operations whose makeObjectsBindable property is not set explicitly.
+     */
+    public var makeObjectsBindable:Boolean = true;
+
+    //----------------------------------
+    //  method
+    //----------------------------------
+
+    [Inspectable(enumeration="GET,get,POST,post,HEAD,head,OPTIONS,options,PUT,put,TRACE,trace,DELETE,delete", defaultValue="GET", category="General")]
+    /**
+     *  HTTP method for sending the request if a method is not set explicit on the operation.
+     *  Permitted values are GET, POST, HEAD,
+     *  OPTIONS, PUT, TRACE and DELETE.
+     *  Lowercase letters are converted to uppercase letters. The default value is GET.
+     */
+    public var method:String = HTTPRequestMessage.GET_METHOD;
+
+    //----------------------------------
+    //  resultFormat
+    //----------------------------------
+
+    /**
+     *  @private
+     */
+    private var _resultFormat:String = AbstractOperation.RESULT_FORMAT_OBJECT;
+
+    [Inspectable(enumeration="object,array,xml,flashvars,text,e4x", defaultValue="object", category="General")]
+    /**
+     *  Value that indicates how you want to deserialize the result
+     *  returned by the HTTP call. The value for this is based on the following:
+     *

+     *
Whether you are returning XML or name/value pairs.

+     *
How you want to access the results; you can access results as an object,
+     *    text, or XML.

+     *

+     *
+     *
The default value is object. The following values are permitted:

+     *

+     *
object The value returned is XML and is parsed as a tree of ActionScript
+     *    objects. This is the default.

+     *
array The value returned is XML and is parsed as a tree of ActionScript
+     *    objects however if the top level object is not an Array, a new Array is created and the result
+     *    set as the first item. If makeObjectsBindable is true then the Array
+     *    will be wrapped in an ArrayCollection.

+     *
xml The value returned is XML and is returned as literal XML in an
+     *    ActionScript XMLnode object.

+     *
flashvars The value returned is text containing
+     *    name=value pairs separated by ampersands, which
+     *  is parsed into an ActionScript object.

+     *
text The value returned is text, and is left raw.

+     *
e4x The value returned is XML and is returned as literal XML
+     *    in an ActionScript XML object, which can be accessed using ECMAScript for
+     *    XML (E4X) expressions.

+     *

+     */
+    public function get resultFormat():String
+    {
+        return _resultFormat;
+    }
+
+    /**
+     *  @private
+     */
+    public function set resultFormat(value:String):void
+    {
+        switch (value)
+        {
+            case AbstractOperation.RESULT_FORMAT_OBJECT:
+            case AbstractOperation.RESULT_FORMAT_ARRAY:
+            case AbstractOperation.RESULT_FORMAT_XML:
+            case AbstractOperation.RESULT_FORMAT_E4X:
+            case AbstractOperation.RESULT_FORMAT_TEXT:
+            case AbstractOperation.RESULT_FORMAT_FLASHVARS:
+            {
+                break;
+            }
+
+            default:
+            {
+                if (value != null && (serializationFilter = SerializationFilter.filterForResultFormatTable[value]) == null)
+                {
+                    var message:String = resourceManager.getString(
+                        "rpc", "invalidResultFormat",
+                        [ value, AbstractOperation.RESULT_FORMAT_OBJECT, AbstractOperation.RESULT_FORMAT_ARRAY,
+                          AbstractOperation.RESULT_FORMAT_XML, AbstractOperation.RESULT_FORMAT_E4X,
+                          AbstractOperation.RESULT_FORMAT_TEXT, AbstractOperation.RESULT_FORMAT_FLASHVARS ]);
+                    throw new ArgumentError(message);
+                }
+            }
+        }
+        _resultFormat = value;
+    }
+
+    /** Default serializationFilter used by all operations which do not set one explicitly */
+    public var serializationFilter:SerializationFilter;
+
+    //----------------------------------
+    //  rootURL
+    //----------------------------------
+
+    /**
+     *  @private
+     */
+    mx_internal var _rootURL:String;
+
+    /**
+     *  The URL that the HTTPService object should use when computing relative URLs.
+     *  If not set explicitly rootURL is automatically set to the URL of
+     *  mx.messaging.config.LoaderConfig.url.
+     */
+    public function get rootURL():String
+    {
+        if (_rootURL == null)
+            _rootURL = LoaderConfig.url;
+        return _rootURL;
+    }
+
+    /**
+     *  @private
+     */
+    public function set rootURL(value:String):void
+    {
+        _rootURL = value;
+    }
+
+    /**
+     *  @private
+     */
+    override public function set destination(value:String):void
+    {
+        useProxy = true;
+        super.destination = value;
+    }
+
+    /**
+     *  @private
+     */
+    private var _useProxy:Boolean = false;
+
+    [Inspectable(defaultValue="false", category="General")]
+    /**
+     *  Specifies whether to use the Flex proxy service. The default value is false. If you
+     *  do not specify true to proxy requests though the Flex server, you must ensure that the player
+     *  can reach the target URL. You also cannot use destinations defined in the services-config.xml file if the
+     *  useProxy property is set to false.
+     *
+     *  @default false
+     */
+    public function get useProxy():Boolean
+    {
+        return _useProxy;
+    }
+
+    /**
+     *  @private
+     */
+    public function set useProxy(value:Boolean):void
+    {
+        if (value != _useProxy)
+        {
+            _useProxy = value;
+            var dcs:ChannelSet = getDirectChannelSet();
+            if (!useProxy)
+            {
+                if (dcs != asyncRequest.channelSet)
+                    asyncRequest.channelSet = dcs;
+            }
+            else
+            {
+                if (asyncRequest.channelSet == dcs)
+                    asyncRequest.channelSet = null;
+            }
+        }
+    }
+
+    /**
+     * This serves as the default property for this instance so that we can
+     * define a set of operations as direct children of the HTTPMultiService
+     * tag in MXML.
+     */
+    public function set operationList(ol:Array):void
+    {
+        if (ol == null)
+            operations = null;
+        else
+        {
+            var op:AbstractOperation;
+            var ops:Object = new Object();
+            for (var i:int = 0; i < ol.length; i++)
+            {
+                op = AbstractOperation(ol[i]);
+                var name:String = op.name;
+                if (!name)
+                    throw new ArgumentError("Operations must have a name property value for HTTPMultiService");
+                ops[name] = op;
+            }
+            operations = ops;
+        }
+    }
+
+    public function get operationList():Array
+    {
+        // Note: does not preserve order of the elements
+        if (operations == null)
+            return null;
+        var ol:Array = new Array();
+        for (var i:String in operations)
+        {
+            var op:AbstractOperation = operations[i];
+            ol.push(op);
+        }
+        return ol
+    }
+
+    /**
+     * Ensures that this method reports an accurate error when an attempt is made to
+     * retrieve a non-existent operation.
+     */
+    override public function getOperation(name:String):mx.rpc.AbstractOperation
+    {
+        var op:mx.rpc.AbstractOperation = super.getOperation(name);
+        if (op == null)
+            throw new ArgumentError("No operation named: " + name + " defined on HTTPMultiService");
+        return op;
+    }
+
+    //--------------------------------------------------------------------------
+    //
+    // Methods
+    //
+    //--------------------------------------------------------------------------
+
+
+    //--------------------------------------------------------------------------
+    //
+    // Internal Methods
+    //
+    //--------------------------------------------------------------------------
+
+    mx_internal function getDirectChannelSet():ChannelSet
+    {
+        if (_directChannelSet == null)
+        {
+            var dcs:ChannelSet = new ChannelSet();
+            dcs.addChannel(new DirectHTTPChannel("direct_http_channel"));
+            _directChannelSet = dcs;
+        }
+        return _directChannelSet;
+    }
+}
+
+}