This is an automated email from the ASF dual-hosted git repository.

pent pushed a commit to branch feature/MXRoyale
in repository https://gitbox.apache.org/repos/asf/royale-asjs.git


The following commit(s) were added to refs/heads/feature/MXRoyale by this push:
     new 3135e47  ArrayList and ArrayUtil now compile along some ancillary 
classes.
3135e47 is described below

commit 3135e4747505fc6439cbdf105377419b6daf129d
Author: Peter Ent <[email protected]>
AuthorDate: Thu Mar 29 16:51:51 2018 -0400

    ArrayList and ArrayUtil now compile along some ancillary classes.
---
 .../MXRoyale/src/main/royale/MXRoyaleClasses.as    |    2 +
 .../src/main/royale/mx/collections/ArrayList.as    |  849 +++++++++++++++
 .../src/main/royale/mx/collections/IList.as        |  271 +++++
 .../src/main/royale/mx/events/CollectionEvent.as   |  281 +++++
 .../main/royale/mx/events/CollectionEventKind.as   |  133 +++
 .../main/royale/mx/events/PropertyChangeEvent.as   |  282 +++++
 .../royale/mx/events/PropertyChangeEventKind.as    |   63 ++
 .../MXRoyale/src/main/royale/mx/utils/ArrayUtil.as |  215 ++++
 .../src/main/royale/mx/utils/ObjectProxy.as        |  831 ++++++++++++++
 .../src/main/royale/mx/utils/ObjectUtil.as         | 1130 ++++++++++++++++++++
 10 files changed, 4057 insertions(+)

diff --git a/frameworks/projects/MXRoyale/src/main/royale/MXRoyaleClasses.as 
b/frameworks/projects/MXRoyale/src/main/royale/MXRoyaleClasses.as
index 39b68a1..9c62e94 100644
--- a/frameworks/projects/MXRoyale/src/main/royale/MXRoyaleClasses.as
+++ b/frameworks/projects/MXRoyale/src/main/royale/MXRoyaleClasses.as
@@ -27,6 +27,7 @@ package
  */
 internal class MXRoyaleClasses
 {
+       import mx.collections.ArrayList; ArrayList;
     import mx.core.UIComponent; UIComponent;
        import mx.core.Container; Container;
        import mx.containers.beads.ApplicationLayout; ApplicationLayout;
@@ -34,6 +35,7 @@ internal class MXRoyaleClasses
        import mx.containers.beads.CanvasLayout; CanvasLayout;
        import mx.controls.ToolTip; ToolTip;
        import mx.controls.beads.ToolTipBead; ToolTipBead;
+       import mx.utils.ArrayUtil; ArrayUtil;
        
     COMPILE::SWF
     {
diff --git 
a/frameworks/projects/MXRoyale/src/main/royale/mx/collections/ArrayList.as 
b/frameworks/projects/MXRoyale/src/main/royale/mx/collections/ArrayList.as
new file mode 100644
index 0000000..e6606ac
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/collections/ArrayList.as
@@ -0,0 +1,849 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.collections 
+{
+COMPILE::JS {
+       import goog.DEBUG;
+}
+import mx.events.CollectionEvent;
+import mx.events.CollectionEventKind;
+import mx.events.PropertyChangeEvent;
+import mx.events.PropertyChangeEventKind;
+
+import org.apache.royale.events.Event;
+import org.apache.royale.events.EventDispatcher;
+import org.apache.royale.events.IEventDispatcher;
+/*
+import mx.resources.IResourceManager;
+import mx.resources.ResourceManager;
+*/
+import mx.utils.ArrayUtil;
+/*
+import mx.utils.UIDUtil;
+*/
+
+//--------------------------------------
+//  Events
+//--------------------------------------
+
+/**
+ *  Dispatched when the IList has been updated in some way.
+ *  
+ *  @eventType mx.events.CollectionEvent.COLLECTION_CHANGE
+ *  
+ *  @langversion 3.0
+ *  @playerversion Flash 9
+ *  @playerversion AIR 1.1
+ *  @productversion Flex 3
+ */
+[Event(name="collectionChange", type="mx.events.CollectionEvent")]
+
+[DefaultProperty("source")]
+
+/**
+ *  The ArrayList class is a simple implementation of IList 
+ *  that uses a backing Array as the source of the data. 
+ * 
+ *  Items in the backing Array can be accessed and manipulated 
+ *  using the methods and properties of the <code>IList</code>
+ *  interface. Operations on an ArrayList instance modify the 
+ *  data source; for example, if you use the <code>removeItemAt()</code> 
+ *  method on an ArrayList, you remove the item from the underlying 
+ *  Array.
+ * 
+ *  This base class will not throw ItemPendingErrors but it
+ *  is possible that a subclass might.
+ * 
+ *  <pre>
+ *  &lt;mx:ArrayList
+ *  <b>Properties</b>
+ *  source="null"
+ *  /&gt;
+ *  </pre>
+ * 
+ *  @langversion 3.0
+ *  @playerversion Flash 10
+ *  @playerversion AIR 1.5
+ *  @productversion Flex 4
+ */
+public class ArrayList extends EventDispatcher
+       implements IList//, IExternalizable, IPropertyChangeNotifier
+{
+    
//--------------------------------------------------------------------------
+    //
+    // Constructor
+    // 
+    
//--------------------------------------------------------------------------
+
+    /**
+     *  Construct a new ArrayList using the specified array as its source.
+     *  If no source is specified an empty array will be used.
+     * 
+     *  @param source The Array to use as a source for the ArrayList.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function ArrayList(source:Array = null)
+    {
+        super();
+
+        disableEvents();
+        this.source = source;
+        enableEvents();
+    }
+    
+    
//--------------------------------------------------------------------------
+    //
+    // Variables
+    // 
+    
//--------------------------------------------------------------------------
+
+    /**
+     *  @private
+     *  Used for accessing localized Error messages.
+     */
+//    private var resourceManager:IResourceManager =
+//        ResourceManager.getInstance();
+                                    
+    /**
+     *  @private 
+     *  Indicates if events should be dispatched.
+     *  calls to enableEvents() and disableEvents() effect the value when == 0
+     *  events should be dispatched. 
+     */
+    private var _dispatchEvents:int = 0;
+
+    
//--------------------------------------------------------------------------
+    //
+    // Properties
+    // 
+    
//--------------------------------------------------------------------------
+    
+    //----------------------------------
+    // length
+    //----------------------------------
+    
+    [Bindable("collectionChange")]
+    
+    /**
+     *  Get the number of items in the list.  An ArrayList should always
+     *  know its length so it shouldn't return -1, though a subclass may 
+     *  override that behavior.
+     *
+     *  @return int representing the length of the source.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function get length():int
+    {
+        if (source)
+            return source.length;
+        else
+            return 0;
+    }
+    
+    //----------------------------------
+    // source
+    //----------------------------------
+    
+    /**
+     *  @private
+     *  Storage for the source Array.
+     */
+    private var _source:Array;
+    
+    /**
+     *  The source array for this ArrayList.  
+     *  Any changes done through the IList interface will be reflected in the 
+     *  source array.  
+     *  If no source array was supplied the ArrayList will create one 
internally.
+     *  Changes made directly to the underlying Array (e.g., calling 
+     *  <code>theList.source.pop()</code> will not cause 
<code>CollectionEvents</code> 
+     *  to be dispatched.
+     *
+     *  @return An Array that represents the underlying source.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function get source():Array
+    {
+        return _source;
+    }
+    
+    public function set source(s:Array):void
+    {
+        var i:int;
+        var len:int;
+        if (_source && _source.length)
+        {
+            len = _source.length;
+            for (i = 0; i < len; i++)
+            {
+                stopTrackUpdates(_source[i]);
+            }
+        }
+        _source  = s ? s : [];
+        len = _source.length;
+        for (i = 0; i < len; i++)
+        {
+            startTrackUpdates(_source[i]);
+        }
+        
+        if (_dispatchEvents == 0)
+        {
+           var event:CollectionEvent =
+            new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
+           event.kind = CollectionEventKind.RESET;
+           dispatchEvent(event);
+        }
+    }
+    
+    //----------------------------------
+    // uid -- mx.core.IPropertyChangeNotifier
+    //----------------------------------
+    
+    /**
+     *  @private
+     *  Storage for the UID String. 
+     */
+    private var _uid:String;
+    
+    /**
+     *  Provides access to the unique id for this list.
+     *  
+     *  @return String representing the internal uid. 
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */  
+    public function get uid():String
+    {
+               if (!_uid) {
+                       //_uid = UIDUtil.createUID();
+                       if (GOOG::DEBUG)
+                               trace("get_uid not implemented");
+               }
+        return _uid;
+    }
+    
+    public function set uid(value:String):void
+    {
+        _uid = value;
+    }
+
+    
//--------------------------------------------------------------------------
+    //
+    // Methods
+    // 
+    
//--------------------------------------------------------------------------
+
+       /**
+        *  Converts an Array List to JavaScript Object Notation (JSON) format.
+        *      Called by the JSON.stringify() method and should not be called 
directly.
+        *  
+        *  @langversion 3.0
+        *  @playerversion Flash 11
+        *  @playerversion AIR 3.0
+        *  @productversion Apache Flex 4.12
+        */
+//     public function toJSON(s:String):*
+//     {
+//             return toArray();
+//     }
+       
+    /**
+     *  Get the item at the specified index.
+     * 
+     *  @param  index the index in the list from which to retrieve the item
+     *  @param  prefetch int indicating both the direction and amount of items
+     *          to fetch during the request should the item not be local.
+     *  @return the item at that index, null if there is none
+     *  @throws ItemPendingError if the data for that index needs to be 
+     *                           loaded from a remote location
+     *  @throws RangeError if the index &lt; 0 or index &gt;= length
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function getItemAt(index:int, prefetch:int = 0):Object
+    {
+        if (index < 0 || index >= length)
+        {
+//            var message:String = resourceManager.getString(
+//                "collections", "outOfBounds", [ index ]);
+//            throw new RangeError(message);
+                       if( GOOG::DEBUG) 
+                               trace("getItemAt throwing RangeError - not 
implemented");
+                       return null;
+        }
+            
+        return source[index];
+    }
+    
+    /**
+     *  Place the item at the specified index.  
+     *  If an item was already at that index the new item will replace it and 
it 
+     *  will be returned.
+     *
+     *  @param  item the new value for the index
+     *  @param  index the index at which to place the item
+     *  @return the item that was replaced, null if none
+     *  @throws RangeError if index is less than 0 or greater than or equal to 
length
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function setItemAt(item:Object, index:int):Object
+    {
+        if (index < 0 || index >= length) 
+        {
+//            var message:String = resourceManager.getString(
+//                "collections", "outOfBounds", [ index ]);
+//            throw new RangeError(message);
+                       if (GOOG::DEBUG)
+                               trace("setItemAt throwing RangeError - not 
implemented");
+                       return null;
+        }
+        
+        var oldItem:Object = source[index];
+        source[index] = item;
+        stopTrackUpdates(oldItem);
+        startTrackUpdates(item);
+        
+        //dispatch the appropriate events 
+        if (_dispatchEvents == 0)
+        {
+            var hasCollectionListener:Boolean = 
+                hasEventListener(CollectionEvent.COLLECTION_CHANGE);
+            var hasPropertyListener:Boolean = 
+                hasEventListener(PropertyChangeEvent.PROPERTY_CHANGE);
+            var updateInfo:PropertyChangeEvent; 
+            
+            if (hasCollectionListener || hasPropertyListener)
+            {
+                updateInfo = new 
PropertyChangeEvent(PropertyChangeEvent.PROPERTY_CHANGE);
+                updateInfo.kind = PropertyChangeEventKind.UPDATE;
+                updateInfo.oldValue = oldItem;
+                updateInfo.newValue = item;
+                updateInfo.property = index;
+            }
+            
+            if (hasCollectionListener)
+            {
+                var event:CollectionEvent =
+                    new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
+                event.kind = CollectionEventKind.REPLACE;
+                event.location = index;
+                event.items.push(updateInfo);
+                dispatchEvent(event);
+            }
+            
+            if (hasPropertyListener)
+            {
+                dispatchEvent(updateInfo);
+            }
+        }
+        return oldItem;    
+    }
+    
+    /**
+     *  Add the specified item to the end of the list.
+     *  Equivalent to addItemAt(item, length);
+     * 
+     *  @param item the item to add
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function addItem(item:Object):void
+    {
+        addItemAt(item, length);
+    }
+    
+    /**
+     *  Add the item at the specified index.  
+     *  Any item that was after this index is moved out by one.  
+     * 
+     *  @param item the item to place at the index
+     *  @param index the index at which to place the item
+     *  @throws RangeError if index is less than 0 or greater than the length
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function addItemAt(item:Object, index:int):void
+    {
+        const spliceUpperBound:int = length;
+
+        if (index < spliceUpperBound && index > 0)
+        {
+            source.splice(index, 0, item);
+        }
+        else if (index == spliceUpperBound)
+        {
+            source.push(item);
+        }
+        else if (index == 0)
+        {
+            source.unshift(item);
+        }
+        else
+        {
+//            var message:String = resourceManager.getString(
+//                "collections", "outOfBounds", [ index ]);
+//            throw new RangeError(message);
+                       if (GOOG::DEBUG)
+                               trace("addItemAt throwing RangeError - not 
implemented");
+                       return;
+        }
+
+        startTrackUpdates(item);
+        internalDispatchEvent(CollectionEventKind.ADD, item, index);
+    }
+    
+    /**
+     *  @copy mx.collections.ListCollectionView#addAll()
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function addAll(addList:IList):void
+    {
+        addAllAt(addList, length);
+    }
+    
+    /**
+     *  @copy mx.collections.ListCollectionView#addAllAt()
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function addAllAt(addList:IList, index:int):void
+    {
+        const addListLength:int = addList.length;
+        if (addListLength == 0)
+            return;
+
+        const addedItems:Array = [];
+        
+        disableEvents();
+        for (var i:int = 0; i < addListLength; i++)
+        {
+            var item:Object = addList.getItemAt(i);
+            this.addItemAt(item, i + index);
+            addedItems.push(item);
+        }
+        enableEvents();
+        
+        if (_dispatchEvents == 0)
+        {
+            const event:CollectionEvent = new 
CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
+            event.kind = CollectionEventKind.ADD;
+            event.location = index;
+            event.items = addedItems;
+            dispatchEvent(event);
+        }
+    }
+    
+    /**
+     *  Return the index of the item if it is in the list such that
+     *  getItemAt(index) == item.  
+     *  Note that in this implementation the search is linear and is therefore 
+     *  O(n).
+     * 
+     *  @param item the item to find
+     *  @return the index of the item, -1 if the item is not in the list.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function getItemIndex(item:Object):int
+    {
+        return ArrayUtil.getItemIndex(item, source);
+    }
+    
+    /**
+     *  Removes the specified item from this list, should it exist.
+     *
+     *  @param  item Object reference to the item that should be removed.
+     *  @return Boolean indicating if the item was removed.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function removeItem(item:Object):Boolean
+    {
+        var index:int = getItemIndex(item);
+        var result:Boolean = index >= 0;
+        if (result)
+            removeItemAt(index);
+
+        return result;
+    }
+    
+    /**
+     *  Remove the item at the specified index and return it.  
+     *  Any items that were after this index are now one index earlier.
+     *
+     *  @param index The index from which to remove the item.
+     *  @return The item that was removed.
+     *  @throws RangeError if index &lt; 0 or index &gt;= length.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function removeItemAt(index:int):Object
+    {
+        const spliceUpperBound:int = length - 1;
+        var removed:Object;
+
+        if (index > 0 && index < spliceUpperBound)
+        {
+            removed = source.splice(index, 1)[0];
+        }
+        else if (index == spliceUpperBound)
+        {
+            removed = source.pop();
+        }
+        else if (index == 0)
+        {
+            removed = source.shift();
+        }
+        else
+        {
+//            var message:String = resourceManager.getString(
+//                "collections", "outOfBounds", [ index ]);
+//            throw new RangeError(message);
+                       if (GOOG::DEBUG)
+                               trace("removeItemAt throwing RangeError - not 
implemented");
+                       return null;
+        }
+
+        stopTrackUpdates(removed);
+        internalDispatchEvent(CollectionEventKind.REMOVE, removed, index);
+        return removed;
+    }
+    
+    /** 
+     *  Remove all items from the list.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function removeAll():void
+    {
+        if (length > 0)
+        {
+            var len:int = length;
+            for (var i:int = 0; i < len; i++)
+            {
+                stopTrackUpdates(source[i]);
+            }
+
+            source.splice(0, length);
+            internalDispatchEvent(CollectionEventKind.RESET);
+        }    
+    }
+    
+    /**
+     *  Notify the view that an item has been updated.  
+     *  This is useful if the contents of the view do not implement 
+     *  <code>IEventDispatcher</code>.  
+     *  If a property is specified the view may be able to optimize its 
+     *  notification mechanism.
+     *  Otherwise it may choose to simply refresh the whole view.
+     *
+     *  @param item The item within the view that was updated.
+     *
+     *  @param property A String, QName, or int
+     *  specifying the property that was updated.
+     *
+     *  @param oldValue The old value of that property.
+     *  (If property was null, this can be the old value of the item.)
+     *
+     *  @param newValue The new value of that property.
+     *  (If property was null, there's no need to specify this
+     *  as the item is assumed to be the new value.)
+     *
+     *  @see mx.events.CollectionEvent
+     *  @see mx.core.IPropertyChangeNotifier
+     *  @see mx.events.PropertyChangeEvent
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+     public function itemUpdated(item:Object, property:Object = null, 
+                                 oldValue:Object = null, 
+                                 newValue:Object = null):void
+    {
+        var event:PropertyChangeEvent = new 
PropertyChangeEvent(PropertyChangeEvent.PROPERTY_CHANGE);
+        
+        event.kind = PropertyChangeEventKind.UPDATE;
+        event.source = item;
+        event.property = property;
+        event.oldValue = oldValue;
+        event.newValue = newValue;
+        
+        if(!property)
+        {
+            stopTrackUpdates(oldValue);
+            startTrackUpdates(newValue);
+        }
+
+        itemUpdateHandler(event);
+    }    
+    
+    /**
+     *  Return an Array that is populated in the same order as the IList
+     *  implementation.  
+     *
+     *  @return An Array populated in the same order as the IList
+     *  implementation.
+     * 
+     *  @throws ItemPendingError if the data is not yet completely loaded
+     *  from a remote location
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */ 
+    public function toArray():Array
+    {
+        return source.concat();
+    }
+    
+    /**
+     *  Ensures that only the source property is serialized.
+     *  @private
+     */
+//    public function readExternal(input:IDataInput):void
+//    {
+//        source = input.readObject();
+//    }
+    
+    /**
+     *  Ensures that only the source property is serialized.
+     *  @private
+     */
+//    public function writeExternal(output:IDataOutput):void
+//    {
+//        output.writeObject(_source);
+//    }
+
+    /**
+     *  Pretty prints the contents of this ArrayList to a string and returns 
it.
+     *
+     *  @return A String containing the contents of the ArrayList.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    override public function toString():String
+    {
+        if (source)
+            return source.toString();
+//        else
+//            return getQualifiedClassName(this); 
+               if (GOOG::DEBUG)
+                       trace("toString using getQualifiedClassName not 
implemented");
+               return "<ArrayList>";
+    }   
+    
+    
//--------------------------------------------------------------------------
+    //
+    // Internal Methods
+    // 
+    
//--------------------------------------------------------------------------
+
+    /**
+     *  Enables event dispatch for this list.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    private function enableEvents():void
+    {
+        _dispatchEvents++;
+        if (_dispatchEvents > 0)
+            _dispatchEvents = 0;
+    }
+    
+    /**
+     *  Disables event dispatch for this list.
+     *  To re-enable events call enableEvents(), enableEvents() must be called
+     *  a matching number of times as disableEvents().
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    private function disableEvents():void
+    {
+        _dispatchEvents--;
+    }
+    
+    /**
+     *  Dispatches a collection event with the specified information.
+     *
+     *  @param kind String indicates what the kind property of the event 
should be
+     *  @param item Object reference to the item that was added or removed
+     *  @param location int indicating where in the source the item was added.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    private function internalDispatchEvent(kind:String, item:Object = null, 
location:int = -1):void
+    {
+        if (_dispatchEvents == 0)
+        {
+            if (hasEventListener(CollectionEvent.COLLECTION_CHANGE))
+            {
+                var event:CollectionEvent = new 
CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
+                event.kind = kind;
+                               if(kind != CollectionEventKind.RESET && kind != 
CollectionEventKind.REFRESH)
+                                   event.items.push(item);
+                event.location = location;
+                dispatchEvent(event);
+            }
+
+            // now dispatch a complementary PropertyChangeEvent
+            if (hasEventListener(PropertyChangeEvent.PROPERTY_CHANGE) && 
+               (kind == CollectionEventKind.ADD || kind == 
CollectionEventKind.REMOVE))
+            {
+                var objEvent:PropertyChangeEvent = new 
PropertyChangeEvent(PropertyChangeEvent.PROPERTY_CHANGE);
+                objEvent.property = location;
+                if (kind == CollectionEventKind.ADD)
+                    objEvent.newValue = item;
+                else
+                    objEvent.oldValue = item;
+                dispatchEvent(objEvent);
+            }
+        }
+    }
+    
+    /**
+     *  Called when any of the contained items in the list dispatches a
+     *  <code>PropertyChangeEvent</code>.
+     *  Wraps it in a <code>CollectionEventKind.UPDATE</code> object.
+     *
+     *  @param event The event object for the <code>PropertyChangeEvent</code>.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */    
+    protected function itemUpdateHandler(event:PropertyChangeEvent):void
+    {
+        internalDispatchEvent(CollectionEventKind.UPDATE, event);
+        // need to dispatch object event now
+        if (_dispatchEvents == 0 && 
hasEventListener(PropertyChangeEvent.PROPERTY_CHANGE))
+        {
+            var objEvent:PropertyChangeEvent = 
PropertyChangeEvent(event.cloneEvent());
+            var index:uint = getItemIndex(event.target);
+            objEvent.property = index.toString() + "." + event.property;
+            dispatchEvent(objEvent);
+        }
+    }
+    
+    /** 
+     *  If the item is an IEventDispatcher, watch it for updates.  
+     *  This method is called by the <code>addItemAt()</code> method, 
+     *  and when the source is initially assigned.
+     *
+     *  @param item The item passed to the <code>addItemAt()</code> method.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    protected function startTrackUpdates(item:Object):void
+    {
+        if (item && (item is IEventDispatcher))
+        {
+            
//IEventDispatcher(item).addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, 
itemUpdateHandler, false, 0, true);
+                       
IEventDispatcher(item).addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, 
itemUpdateHandler, false);
+        }
+    }
+    
+    /** 
+     *  If the item is an IEventDispatcher, stop watching it for updates.
+     *  This method is called by the <code>removeItemAt()</code> and 
+     *  <code>removeAll()</code> methods, and before a new
+     *  source is assigned.
+     *
+     *  @param item The item passed to the <code>removeItemAt()</code> method.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    protected function stopTrackUpdates(item:Object):void
+    {
+        if (item && item is IEventDispatcher)
+        {
+            
IEventDispatcher(item).removeEventListener(PropertyChangeEvent.PROPERTY_CHANGE, 
itemUpdateHandler);
+        }
+    }
+}
+}
diff --git 
a/frameworks/projects/MXRoyale/src/main/royale/mx/collections/IList.as 
b/frameworks/projects/MXRoyale/src/main/royale/mx/collections/IList.as
new file mode 100644
index 0000000..399f7a0
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/collections/IList.as
@@ -0,0 +1,271 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.collections 
+{
+    
+import org.apache.royale.events.IEventDispatcher;
+import mx.events.CollectionEvent;
+
+/**
+ *  Dispatched when the IList has been updated in some way.
+ *
+ *  @eventType mx.events.CollectionEvent.COLLECTION_CHANGE
+ *  
+ *  @langversion 3.0
+ *  @playerversion Flash 9
+ *  @playerversion AIR 1.1
+ *  @productversion Flex 3
+ */
+[Event(name="collectionChange", type="mx.events.CollectionEvent")]
+
+/**
+ *  A collection of items organized in an ordinal fashion.  
+ *  Provides access and manipulation methods based on index.  
+ *  
+ *  <p>An <code>IList</code> may be a view onto data
+ *  that has been retrieved from a  remote location.  
+ *  When writing for a collection that may be remote,
+ *  it is important to handle the case where data
+ *  may not yet be available, which is indicated
+ *  by the  <code>ItemPendingError</code>.</p>
+ *  
+ *  <p>The <code>ICollectionView</code> is an alternative
+ *  to the <code>IList</code>.</p>
+ *
+ *  @see mx.collections.errors.ItemPendingError
+ *  @see mx.collections.ICollectionView
+ *  @see mx.collections.ListCollectionView
+ *  
+ *  @langversion 3.0
+ *  @playerversion Flash 9
+ *  @playerversion AIR 1.1
+ *  @productversion Flex 3
+ */
+public interface IList extends IEventDispatcher
+{
+    
//--------------------------------------------------------------------------
+    //
+    //  Properties
+    //
+    
//--------------------------------------------------------------------------
+
+    //----------------------------------
+    //  length
+    //----------------------------------
+
+    /**
+     *  The number of items in this collection. 
+     *  0 means no items while -1 means the length is unknown. 
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    function get length():int;
+
+    
//--------------------------------------------------------------------------
+    //
+    //  Methods
+    //
+    
//--------------------------------------------------------------------------
+
+    /**
+     *  Adds the specified item to the end of the list.
+     *  Equivalent to <code>addItemAt(item, length)</code>.
+     *
+     *  @param item The item to add.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    function addItem(item:Object):void;
+    
+    /**
+     *  Adds the item at the specified index.  
+     *  The index of any item greater than the index of the added item is 
increased by one.  
+     *  If the the specified index is less than zero or greater than the length
+     *  of the list, a RangeError is thrown.
+     * 
+     *  @param item The item to place at the index.
+     *
+     *  @param index The index at which to place the item.
+     *
+     *  @throws RangeError if index is less than 0 or greater than the length 
of the list. 
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    function addItemAt(item:Object, index:int):void;
+    
+    /**
+     *  Gets the item at the specified index.
+     * 
+     *  @param index The index in the list from which to retrieve the item.
+     *
+     *  @param prefetch An <code>int</code> indicating both the direction
+     *  and number of items to fetch during the request if the item is
+     *  not local.
+     *
+     *  @return The item at that index, or <code>null</code> if there is none.
+     *
+     *  @throws mx.collections.errors.ItemPendingError if the data for that 
index needs to be 
+     *  loaded from a remote location.
+     *
+     *  @throws RangeError if <code>index &lt; 0</code>
+     *  or <code>index >= length</code>.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    function getItemAt(index:int, prefetch:int = 0):Object;
+    
+    /**
+     *  Returns the index of the item if it is in the list such that
+     *  getItemAt(index) == item.
+     * 
+     *  <p>Note: unlike <code>IViewCursor.find<i>xxx</i>()</code> methods,
+     *  The <code>getItemIndex()</code> method cannot take a parameter with 
+     *  only a subset of the fields in the item being serched for; 
+     *  this method always searches for an item that exactly matches
+     *  the input parameter.</p>
+     * 
+     *  @param item The item to find.
+     *
+     *  @return The index of the item, or -1 if the item is not in the list.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    function getItemIndex(item:Object):int;
+    
+    /**
+     *  Notifies the view that an item has been updated.  
+     *  This is useful if the contents of the view do not implement 
+     *  <code>IEventDispatcher</code> and dispatches a 
+     *  <code>PropertyChangeEvent</code>.  
+     *  If a property is specified the view may be able to optimize its 
+     *  notification mechanism.
+     *  Otherwise it may choose to simply refresh the whole view.
+     *
+     *  @param item The item within the view that was updated.
+     *
+     *  @param property The name of the property that was updated.
+     *
+     *  @param oldValue The old value of that property. (If property was null,
+     *  this can be the old value of the item.)
+     *
+     *  @param newValue The new value of that property. (If property was null,
+     *  there's no need to specify this as the item is assumed to be
+     *  the new value.)
+     *
+     *  @see mx.events.CollectionEvent
+     *  @see mx.events.PropertyChangeEvent
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    function itemUpdated(item:Object, property:Object = null, 
+                         oldValue:Object = null, 
+                         newValue:Object = null):void;
+
+    /** 
+     *  Removes all items from the list.
+     *
+     *  <p>If any item is not local and an asynchronous operation must be
+     *  performed, an <code>ItemPendingError</code> will be thrown.</p>
+     *
+     *  <p>See the ItemPendingError documentation as well as
+     *  the collections documentation for more information
+     *   on using the <code>ItemPendingError</code>.</p>
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    function removeAll():void;
+       
+    /**
+     *  Removes the item at the specified index and returns it.  
+     *  Any items that were after this index are now one index earlier.
+     *
+     *  @param index The index from which to remove the item.
+     *
+     *  @return The item that was removed.
+     *
+     *  @throws RangeError is index is less than 0 or greater than length. 
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    function removeItemAt(index:int):Object;
+    
+    /**
+     *  Places the item at the specified index.  
+     *  If an item was already at that index the new item will replace it
+     *  and it will be returned.
+     *
+     *  @param item The new item to be placed at the specified index.
+     *
+     *  @param index The index at which to place the item.
+     *
+     *  @return The item that was replaced, or <code>null</code> if none.
+     *
+     *  @throws RangeError if index is less than 0 or greater than length.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    function setItemAt(item:Object, index:int):Object;
+    
+    /**
+     *  Returns an Array that is populated in the same order as the IList
+     *  implementation.
+     *  This method can throw an ItemPendingError.
+     *
+     *  @return The array.
+     *  
+     *  @throws mx.collections.errors.ItemPendingError If the data is not yet 
completely loaded
+     *  from a remote location.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */ 
+    function toArray():Array;
+}
+
+}
diff --git 
a/frameworks/projects/MXRoyale/src/main/royale/mx/events/CollectionEvent.as 
b/frameworks/projects/MXRoyale/src/main/royale/mx/events/CollectionEvent.as
new file mode 100644
index 0000000..370057a
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/events/CollectionEvent.as
@@ -0,0 +1,281 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.events
+{
+COMPILE::JS {
+       import goog.DEBUG;
+}
+
+import org.apache.royale.events.Event;
+import org.apache.royale.events.IRoyaleEvent;
+
+/**
+ *  The mx.events.CollectionEvent class represents an event that is  
+ *  dispatched when the associated collection changes.
+ *
+ *  @see FlexEvent#CURSOR_UPDATE
+ *  
+ *  @langversion 3.0
+ *  @playerversion Flash 9
+ *  @playerversion AIR 1.1
+ *  @productversion Flex 3
+ */
+public class CollectionEvent extends Event
+{
+    
//--------------------------------------------------------------------------
+    //
+    //  Class constants
+    //
+    
//--------------------------------------------------------------------------
+
+    /**
+     *  The CollectionEvent.COLLECTION_CHANGE constant defines the value of the
+     *  <code>type</code> property of the event object for an event that is
+     *  dispatched when a collection has changed.
+     *
+     *  <p>The properties of the event object have the following values.
+     *  Not all properties are meaningful for all kinds of events.
+        *  See the detailed property descriptions for more information.</p>
+     *  <table class="innertable">
+     *     <tr><th>Property</th><th>Value</th></tr>
+     *     <tr><td><code>bubbles</code></td><td>false</td></tr>
+     *     <tr><td><code>cancelable</code></td><td>false</td></tr>
+     *     <tr><td><code>currentTarget</code></td><td>The Object that defines 
the
+     *       event listener that handles the event. For example, if you use
+     *       <code>myButton.addEventListener()</code> to register an event 
listener,
+     *       myButton is the value of the <code>currentTarget</code>. 
</td></tr>
+     *     <tr><td><code>items</code></td><td>An Array of objects with
+     *       information about the items affected by the event.
+        *               The contents of this field depend on the event kind;
+        *       for details see the <code>items</code> property</td></tr>
+     *     <tr><td><code>kind</code></td><td>The kind of event.
+     *       The valid values are defined in the CollectionEventKind 
+        *       class as constants.</td></tr>
+     *     <tr><td><code>location</code></td><td>Location within the target 
collection
+     *         of the item(s) specified in the <code>items</code> 
property.</td></tr>
+     *     <tr><td><code>oldLocation</code></td><td>the previous location in 
the collection
+     *         of the item specified in the <code>items</code> 
property.</td></tr>
+     *     <tr><td><code>target</code></td><td>The Object that dispatched the 
event;
+     *       it is not always the Object listening for the event.
+     *       Use the <code>currentTarget</code> property to always access the
+     *       Object listening for the event.</td></tr>
+     *     
<tr><td><code>type</code></td><td>CollectionEvent.COLLECTION_CHANGE</td></tr>
+     *  </table>
+     *
+     *  @eventType collectionChange
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static const COLLECTION_CHANGE:String = "collectionChange";
+
+    
//--------------------------------------------------------------------------
+    //
+    // Constructor
+    //
+    
//--------------------------------------------------------------------------
+
+    /**
+     *  Constructor.
+        *
+     *  @param type The event type; indicates the action that triggered the 
event.
+     *
+     *  @param bubbles Specifies whether the event can bubble
+     *  up the display list hierarchy.
+     *
+     *  @param cancelable Specifies whether the behavior
+     *  associated with the event can be prevented.
+     *
+     *  @param kind Indicates the kind of event that occured.
+     *  The parameter value can be one of the values in the 
CollectionEventKind 
+        *  class, or <code>null</code>, which indicates that the kind is 
unknown.
+     *
+     *  @param location When the <code>kind</code> is
+     *  <code>CollectionEventKind.ADD</code>,
+     *  <code>CollectionEventKind.MOVE</code>,
+     *  <code>CollectionEventKind.REMOVE</code>, or
+     *  <code>CollectionEventKind.REPLACE</code>,
+     *  this value indicates at what location the item(s) specified
+     *  in the <code>items property</code> can be found
+     *  within the target collection.
+     *
+     *  @param oldLocation When the <code>kind</code> is
+     *  <code>CollectionEventKind.MOVE</code>, this value indicates
+     *  the old location within the target collection
+     *  of the item(s) specified in the <code>items</code> property.
+      *
+     *  @param items Array of objects with information about the items 
+        *  affected by the event, as described in the <code>items</code> 
property.
+     *  When the <code>kind</code> is <code>CollectionEventKind.REFRESH</code>
+     *  or <code>CollectionEventKind.RESET</code>, this Array has zero length.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function CollectionEvent(type:String, bubbles:Boolean = false,
+                                    cancelable:Boolean = false,
+                                    kind:String = null, location:int = -1,
+                                    oldLocation:int = -1, items:Array = null)
+    {
+        super(type, bubbles, cancelable);
+
+        this.kind = kind;
+        this.location = location;
+        this.oldLocation = oldLocation;
+        this.items = items ? items : [];
+    }
+
+    
//--------------------------------------------------------------------------
+    //
+    // Properties
+    //
+    
//--------------------------------------------------------------------------
+
+       //----------------------------------
+       //  kind
+       //----------------------------------
+
+    /**
+     *  Indicates the kind of event that occurred.
+     *  The property value can be one of the values in the 
+        *  CollectionEventKind class, 
+        *  or <code>null</code>, which indicates that the kind is unknown.
+        * 
+     *  @default null
+        * 
+        *  @see CollectionEventKind
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public var kind:String;
+
+       //----------------------------------
+       //  items
+       //----------------------------------
+
+    /**
+        *  When the <code>kind</code> is <code>CollectionEventKind.ADD</code>
+     *  or <code>CollectionEventKind.REMOVE</code> the <code>items</code> 
property
+     *  is an Array of added/removed items.
+        *  When the <code>kind</code> is 
<code>CollectionEventKind.REPLACE</code>
+     *  or <code>CollectionEventKind.UPDATE</code> the <code>items</code> 
property
+     *  is an Array of PropertyChangeEvent objects with information about the 
items
+     *  affected by the event.
+     *  When a value changes, query the <code>newValue</code> and
+     *  <code>oldValue</code> fields of the PropertyChangeEvent objects
+     *  to find out what the old and new values were.
+     *  When the <code>kind</code> is <code>CollectionEventKind.REFRESH</code>
+     *  or <code>CollectionEventKind.RESET</code>, this array has zero length.
+     *
+     *  @default [ ]
+     *
+     *  @see PropertyChangeEvent
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public var items:Array;
+
+       //----------------------------------
+       //  location
+       //----------------------------------
+
+    /**
+     *  When the <code>kind</code> value is 
<code>CollectionEventKind.ADD</code>,
+     *  <code>CollectionEventKind.MOVE</code>,
+     *  <code>CollectionEventKind.REMOVE</code>, or
+     *  <code>CollectionEventKind.REPLACE</code>, this property is the 
+        *  zero-base index in the collection of the item(s) specified in the 
+        *  <code>items</code> property.
+     *
+     *  @see CollectionEventKind
+     *
+     *  @default -1
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public var location:int;
+
+       //----------------------------------
+       //  oldLocation
+       //----------------------------------
+
+    /**
+     *  When the <code>kind</code> value is 
<code>CollectionEventKind.MOVE</code>,
+     *  this property is the zero-based index in the target collection of the
+     *  previous location of the item(s) specified by the <code>items</code> 
property.
+     *
+     *  @default -1
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public var oldLocation:int;
+
+    
//--------------------------------------------------------------------------
+    //
+    //  Overridden methods: Object
+    //
+    
//--------------------------------------------------------------------------
+
+    /**
+     *  @private
+     */
+       COMPILE::SWF
+    override public function toString():String
+    {
+//        return formatToString("CollectionEvent", "kind", "location",
+//                                                       "oldLocation", 
"type", "bubbles",
+//                                                       "cancelable", 
"eventPhase");
+               if (GOOG::DEBUG)
+                       trace("toString not implemented");
+               return "<CollectionEvent>";
+    }
+
+    
//--------------------------------------------------------------------------
+    //
+    //  Overridden methods: Event
+    //
+    
//--------------------------------------------------------------------------
+
+    /**
+     *  @private
+     */
+       override public function cloneEvent():IRoyaleEvent
+    {
+        return new CollectionEvent(type, bubbles, cancelable, kind, location, 
oldLocation, items);
+    }
+}
+
+}
diff --git 
a/frameworks/projects/MXRoyale/src/main/royale/mx/events/CollectionEventKind.as 
b/frameworks/projects/MXRoyale/src/main/royale/mx/events/CollectionEventKind.as
new file mode 100644
index 0000000..8cdcdb1
--- /dev/null
+++ 
b/frameworks/projects/MXRoyale/src/main/royale/mx/events/CollectionEventKind.as
@@ -0,0 +1,133 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.events
+{
+
+/**
+ *  The CollectionEventKind class contains constants for the valid values 
+ *  of the mx.events.CollectionEvent class <code>kind</code> property.
+ *  These constants indicate the kind of change that was made to the 
collection.
+ *
+ *  @see mx.events.CollectionEvent
+ *  
+ *  @langversion 3.0
+ *  @playerversion Flash 9
+ *  @playerversion AIR 1.1
+ *  @productversion Flex 3
+ */
+public final class CollectionEventKind
+{
+    
//--------------------------------------------------------------------------
+    //
+    //  Class constants
+    //
+    
//--------------------------------------------------------------------------
+
+    /**
+     *  Indicates that the collection added an item or items.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static const ADD:String = "add";
+
+    /**
+     *  Indicates that the item has moved from the position identified
+     *  by the CollectionEvent <code>oldLocation</code> property to the 
+        *  position identified by the <code>location</code> property.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static const MOVE:String = "move";
+
+    /**
+     *  Indicates that the collection applied a sort, a filter, or both.
+     *  This change can potentially be easier to handle than a RESET.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static const REFRESH:String = "refresh";
+
+    /**
+     *  Indicates that the collection removed an item or items.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static const REMOVE:String = "remove";
+
+    /**
+     *  Indicates that the item at the position identified by the 
+     *  CollectionEvent <code>location</code> property has been replaced.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static const REPLACE:String = "replace";
+
+    /**
+    *  Indicates that the collection has internally expanded. 
+    *  This event kind occurs when a branch opens in a 
+       *  hierarchical collection, for example when a Tree control branch 
opens.
+    *  
+    *  @langversion 3.0
+    *  @playerversion Flash 9
+    *  @playerversion AIR 1.1
+    *  @productversion Flex 3
+    */
+    public static const EXPAND:String = "expand";
+
+    /**
+     *  Indicates that the collection has changed so drastically that
+     *  a reset is required.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static const RESET:String = "reset";
+
+    /**
+     *  Indicates that one or more items were updated within the collection.
+     *  The affected item(s) 
+     *  are stored in the <code>items</code> property.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static const UPDATE:String = "update";
+}
+
+}
diff --git 
a/frameworks/projects/MXRoyale/src/main/royale/mx/events/PropertyChangeEvent.as 
b/frameworks/projects/MXRoyale/src/main/royale/mx/events/PropertyChangeEvent.as
new file mode 100644
index 0000000..6735819
--- /dev/null
+++ 
b/frameworks/projects/MXRoyale/src/main/royale/mx/events/PropertyChangeEvent.as
@@ -0,0 +1,282 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.events
+{
+
+import mx.events.PropertyChangeEventKind;
+
+import org.apache.royale.events.Event;
+import org.apache.royale.events.IRoyaleEvent;
+
+/**
+ * The PropertyChangeEvent class represents the event object 
+ * passed to the event listener when one of the properties of 
+ * an object has changed, and provides information about the change. 
+ * This event is used by collection classes, and is the only way for 
+ * collections to know that the data they represent has changed.
+ * This event is also used by the Flex data binding mechanism.
+ * 
+ * @see PropertyChangeEventKind
+ *  
+ *  @langversion 3.0
+ *  @playerversion Flash 9
+ *  @playerversion AIR 1.1
+ *  @productversion Flex 3
+ */
+public class PropertyChangeEvent extends Event
+{
+    
//--------------------------------------------------------------------------
+    //
+    //  Class constants
+    //
+    
//--------------------------------------------------------------------------
+
+    // Note: If the value for CHANGE changes,
+    // update mx.utils.ObjectProxy's Bindable metadata.
+    
+    /**
+     *  The <code>PropertyChangeEvent.PROPERTY_CHANGE</code> constant defines 
the value of the 
+     *  <code>type</code> property of the event object for a 
<code>PropertyChange</code> event.
+     * 
+     *  <p>The properties of the event object have the following values:</p>
+     *  <table class="innertable">
+     *     <tr><th>Property</th><th>Value</th></tr>
+     *     <tr><td><code>bubbles</code></td><td>Determined by the constructor; 
defaults to false.</td></tr>
+     *     <tr><td><code>cancelable</code></td><td>Determined by the 
constructor; defaults to false.</td></tr>
+     *     <tr><td><code>kind</code></td><td>The kind of change; 
PropertyChangeEventKind.UPDATE
+     *             or PropertyChangeEventKind.DELETE.</td></tr>
+     *     <tr><td><code>oldValue</code></td><td>The original property 
value.</td></tr>
+     *     <tr><td><code>newValue</code></td><td>The new property value, if 
any.</td></tr>
+     *     <tr><td><code>property</code></td><td>The property that 
changed.</td></tr>
+     *     <tr><td><code>source</code></td><td>The object that contains the 
property that changed.</td></tr>
+     *     <tr><td><code>currentTarget</code></td><td>The Object that defines 
the 
+     *       event listener that handles the event. For example, if you use 
+     *       <code>myButton.addEventListener()</code> to register an event 
listener, 
+     *       myButton is the value of the <code>currentTarget</code>. 
</td></tr>
+     *     <tr><td><code>target</code></td><td>The Object that dispatched the 
event; 
+     *       it is not always the Object listening for the event. 
+     *       Use the <code>currentTarget</code> property to always access the 
+     *       Object listening for the event.</td></tr>
+     *  </table>
+     *
+     *  @eventType propertyChange
+     *
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static const PROPERTY_CHANGE:String = "propertyChange";
+
+    
//--------------------------------------------------------------------------
+    //
+    //  Class methods
+    //
+    
//--------------------------------------------------------------------------
+
+    /**
+     *  Returns a new PropertyChangeEvent of kind
+     *  <code>PropertyChangeEventKind.UPDATE</code>
+     *  with the specified properties.
+     *  This is a convenience method.
+     * 
+     *  @param source The object where the change occured.
+     *
+     *  @param property A String, QName, or int
+     *  specifying the property that changed,
+     *
+     *  @param oldValue The value of the property before the change.
+     *
+     *  @param newValue The value of the property after the change.
+     *
+     *  @return A newly constructed PropertyChangeEvent
+     *  with the specified properties. 
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static function createUpdateEvent(
+                                    source:Object,
+                                    property:Object,
+                                    oldValue:Object,
+                                    newValue:Object):PropertyChangeEvent
+    {
+        var event:PropertyChangeEvent =
+            new PropertyChangeEvent(PROPERTY_CHANGE);
+        
+        event.kind = PropertyChangeEventKind.UPDATE;
+        event.oldValue = oldValue;
+        event.newValue = newValue;
+        event.source = source;
+        event.property = property;
+        
+        return event;
+    }
+
+    
//--------------------------------------------------------------------------
+    //
+    //  Constructor
+    //
+    
//--------------------------------------------------------------------------
+
+    /**
+     *  Constructor.
+     *
+     *  @param type The event type; indicates the action that triggered the 
event.
+     *
+     *  @param bubbles Specifies whether the event can bubble
+     *  up the display list hierarchy.
+     *
+     *  @param cancelable Specifies whether the behavior
+     *  associated with the event can be prevented.
+     *
+     *  @param kind Specifies the kind of change.
+     *  The possible values are <code>PropertyChangeEventKind.UPDATE</code>,
+     *  <code>PropertyChangeEventKind.DELETE</code>, and <code>null</code>.
+     *
+     *  @param property A String, QName, or int
+     *  specifying the property that changed.
+     *
+     *  @param oldValue The value of the property before the change.
+     *
+     *  @param newValue The value of the property after the change.
+     *
+     *  @param source The object that the change occured on.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function PropertyChangeEvent(type:String, bubbles:Boolean = false,
+                                        cancelable:Boolean = false,
+                                        kind:String = null,
+                                        property:Object = null, 
+                                        oldValue:Object = null,
+                                        newValue:Object = null,
+                                        source:Object = null)
+    {
+        super(type, bubbles, cancelable);
+
+        this.kind = kind;
+        this.property = property;
+        this.oldValue = oldValue;
+        this.newValue = newValue;
+        this.source = source;
+    }
+
+    
//--------------------------------------------------------------------------
+    //
+    //  Properties
+    //
+    
//--------------------------------------------------------------------------
+
+    //----------------------------------
+    //  kind
+    //----------------------------------
+
+    /**
+     *  Specifies the kind of change.
+     *  The possible values are <code>PropertyChangeEventKind.UPDATE</code>,
+     *  <code>PropertyChangeEventKind.DELETE</code>, and <code>null</code>.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public var kind:String;
+
+    //----------------------------------
+    //  newValue
+    //----------------------------------
+
+    /**
+     *  The value of the property after the change.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public var newValue:Object;
+
+    //----------------------------------
+    //  oldValue
+    //----------------------------------
+ 
+    /**
+     *  The value of the property before the change.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public var oldValue:Object;
+
+    //----------------------------------
+    //  property
+    //----------------------------------
+
+    /**
+     *  A String, QName, or int specifying the property that changed.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public var property:Object;
+
+    //----------------------------------
+    //  source
+    //----------------------------------
+
+    /**
+     *  The object that the change occured on.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public var source:Object;
+
+    
//--------------------------------------------------------------------------
+    //
+    //  Class methods: Event
+    //
+    
//--------------------------------------------------------------------------
+
+    /**
+     *  @private
+     */
+       override public function cloneEvent():IRoyaleEvent
+    {
+        return new PropertyChangeEvent(type, bubbles, cancelable, kind,
+                                       property, oldValue, newValue, source);
+    }
+}
+
+}
diff --git 
a/frameworks/projects/MXRoyale/src/main/royale/mx/events/PropertyChangeEventKind.as
 
b/frameworks/projects/MXRoyale/src/main/royale/mx/events/PropertyChangeEventKind.as
new file mode 100644
index 0000000..a2e82be
--- /dev/null
+++ 
b/frameworks/projects/MXRoyale/src/main/royale/mx/events/PropertyChangeEventKind.as
@@ -0,0 +1,63 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.events
+{
+
+/**
+ *  The PropertyChangeEventKind class defines the constant values 
+ *  for the <code>kind</code> property of the PropertyChangeEvent class.
+ * 
+ *  @see mx.events.PropertyChangeEvent
+ *  
+ *  @langversion 3.0
+ *  @playerversion Flash 9
+ *  @playerversion AIR 1.1
+ *  @productversion Flex 3
+ */
+public final class PropertyChangeEventKind
+{
+       
//--------------------------------------------------------------------------
+       //
+       //  Class constants
+       //
+       
//--------------------------------------------------------------------------
+
+    /**
+        *  Indicates that the value of the property changed.
+        *  
+        *  @langversion 3.0
+        *  @playerversion Flash 9
+        *  @playerversion AIR 1.1
+        *  @productversion Flex 3
+        */
+       public static const UPDATE:String = "update";
+
+    /**
+        *  Indicates that the property was deleted from the object.
+        *  
+        *  @langversion 3.0
+        *  @playerversion Flash 9
+        *  @playerversion AIR 1.1
+        *  @productversion Flex 3
+        */
+       public static const DELETE:String = "delete";
+}
+
+}
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/utils/ArrayUtil.as 
b/frameworks/projects/MXRoyale/src/main/royale/mx/utils/ArrayUtil.as
new file mode 100644
index 0000000..5c16cb7
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/utils/ArrayUtil.as
@@ -0,0 +1,215 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.utils
+{
+import mx.utils.ObjectUtil;
+
+/**
+ *  The ArrayUtil utility class is an all-static class
+ *  with methods for working with arrays within Flex.
+ *  You do not create instances of ArrayUtil;
+ *  instead you call static methods such as the 
+ *  <code>ArrayUtil.toArray()</code> method.
+ *  
+ *  @langversion 3.0
+ *  @playerversion Flash 9
+ *  @playerversion AIR 1.1
+ *  @productversion Flex 3
+ */
+public class ArrayUtil
+{      
+       import mx.collections.IList;
+
+    
//--------------------------------------------------------------------------
+    //
+    //  Class methods
+    //
+    
//--------------------------------------------------------------------------
+
+    /**
+     *  Ensures that an Object can be used as an Array.
+     *
+     *  <p>If the Object is already an Array, it returns the object. 
+     *  If the object is not an Array, it returns an Array
+     *  in which the only element is the Object.
+        *  If the Object implements IList it returns the IList's array.
+     *  As a special case, if the Object is null,
+     *  it returns an empty Array.</p>
+     *
+     *  @param obj Object that you want to ensure is an array.
+     *
+     *  @return An Array. If the original Object is already an Array, 
+     *  the original Array is returned. If the original Object is an
+        *  IList then it's array is returned. Otherwise, a new Array whose
+     *  only element is the Object is returned or an empty Array if 
+     *  the Object was null. 
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static function toArray(obj:Object):Array
+    {
+        if (obj == null) 
+            return [];
+        
+               else if (obj is Array)
+                       return obj as Array;
+               
+               else if (obj is IList)
+                       return (obj as IList).toArray();
+        
+        else
+            return [ obj ];
+    }
+    
+    /**
+     *  Returns the index of the item in the Array.
+     * 
+     *  @param item The item to find in the Array. 
+     *
+     *  @param source The Array to search for the item.
+     * 
+     *  @return The index of the item, and -1 if the item is not in the list.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static function getItemIndex(item:Object, source:Array):int
+    {
+        var n:int = source.length;
+        for (var i:int = 0; i < n; i++)
+        {
+            if (source[i] === item)
+                return i;
+        }
+
+        return -1;           
+    }
+
+    /**
+     *  Checks if the Array instances contain the same values
+     *  against the same indexes, even if in different orders.
+     *
+     *  @param a The first Array instance.
+     *  @param b The second Array instance.
+     *  @param strictEqualityCheck true if we should compare the
+     *  values of the two Arrays using the strict equality
+     *  operator (===) or not (==).
+     *  @return true if the two Arrays contain the same values
+     *  (determined using the strict equality operator) associated
+     *  with the same indexes.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static function arraysMatch(a:Array, b:Array, 
strictEqualityCheck:Boolean = true):Boolean
+    {
+        if(!a || !b)
+            return false;
+
+        if(a.length != b.length)
+            return false;
+
+        var indexesA:Array = ObjectUtil.getEnumerableProperties(a);
+
+        for (var i:int = 0; i < indexesA.length; i++)
+        {
+            var index:String = indexesA[i];
+
+            if(!b.hasOwnProperty(index))
+                return false;
+
+            if(strictEqualityCheck && a[index] !== b[index])
+                return false;
+
+            if(!strictEqualityCheck && a[index] != b[index])
+                return false;
+        }
+
+        return true;
+    }
+
+    /**
+     *  Checks if the Array instances contain the same values,
+     *  even if in different orders.
+     *
+     *  @param a The first Array instance.
+     *  @param b The second Array instance.
+     *  @param strictEqualityCheck true if we should compare the
+     *  values of the two Arrays using the strict equality
+     *  operator (===) or not (==).
+     *  @return true if the two Arrays contain the same values.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static function arrayValuesMatch(a:Array, b:Array, 
strictEqualityCheck:Boolean = true):Boolean
+    {
+        if(!a || !b)
+            return false;
+
+        var valuesOfA:Array = getArrayValues(a);
+        valuesOfA.sort();
+
+        var valuesOfB:Array = getArrayValues(b);
+        valuesOfB.sort();
+
+        return arraysMatch(valuesOfA, valuesOfB, strictEqualityCheck);
+    }
+
+    /**
+     *  Used to obtain the values in an Array, whether indexed
+     *  or associative.
+     *
+     *  @param value The Array instance.
+     *  @return an indexed Array with the values found in <code>value</code>.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static function getArrayValues(value:Array):Array
+    {
+        var result:Array = [];
+
+        if(!value)
+            return result;
+
+        var indexes:Array = ObjectUtil.getEnumerableProperties(value);
+
+        for each(var index:String in indexes)
+        {
+            result.push(value[index]);
+        }
+
+        return result;
+    }
+}
+
+}
diff --git 
a/frameworks/projects/MXRoyale/src/main/royale/mx/utils/ObjectProxy.as 
b/frameworks/projects/MXRoyale/src/main/royale/mx/utils/ObjectProxy.as
new file mode 100644
index 0000000..117b350
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/utils/ObjectProxy.as
@@ -0,0 +1,831 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.utils
+{
+COMPILE::JS {
+       import goog.DEBUG;
+}
+/*
+import flash.events.Event;
+import flash.events.EventDispatcher;
+import flash.utils.getQualifiedClassName;
+import flash.utils.IDataInput;
+import flash.utils.IDataOutput;
+import flash.utils.IExternalizable;
+import flash.utils.Proxy;
+import flash.utils.flash_proxy;
+import mx.core.IPropertyChangeNotifier;
+import mx.events.PropertyChangeEvent;
+import mx.events.PropertyChangeEventKind;
+
+use namespace flash_proxy;
+use namespace object_proxy;
+
+[Bindable("propertyChange")]
+[RemoteClass(alias="flex.messaging.io.ObjectProxy")]
+*/
+
+/**
+ *  This class provides the ability to track changes to an item
+ *  managed by this proxy.
+ *  Any number of objects can "listen" for changes on this
+ *  object, by using the <code>addEventListener()</code> method.
+ *
+ *  @example
+ *  <pre>
+ *  import mx.events.PropertyChangeEvent;
+ *  import mx.utils.ObjectUtil;
+ *  import mx.utils.ObjectProxy;
+ *  import mx.utils.StringUtil;
+ *
+ *  var a:Object = { name: "Tyler", age: 5, ssnum: "555-55-5555" };
+ *  var p:ObjectProxy = new ObjectProxy(a);
+ *  p.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, updateHandler);
+ *  p.name = "Jacey";
+ *  p.age = 2;
+ *  delete p.ssnum;
+ *
+ *  // handler function
+ *  function updateHandler(event:ChangeEvent):void
+ *  {
+ *      trace(StringUtil.substitute("updateHandler('{0}', {1}, {2}, {3}, 
'{4}')",
+ *                                     event.kind,
+ *                                     event.property,
+ *                                     event.oldValue,
+ *                                     event.newValue,
+ *                                     event.target.object_proxy::UUID));
+ *  }
+ * 
+ *  // The trace output appears as:
+ *  // updateHandler('opUpdate', name, Tyler, Jacey, 
'698AF8CB-B3D9-21A3-1AFFDGHT89075CD2')
+ *  // updateHandler('opUpdate', age, 5, 2, 
'698AF8CB-B3D9-21A3-1AFFDGHT89075CD2')
+ *  // updateHandler('opDelete', ssnum, 555-55-5555, null, 
'698AF8CB-B3D9-21A3-1AFFDGHT89075CD2')
+ *  </pre>
+ *  
+ *  @langversion 3.0
+ *  @playerversion Flash 9
+ *  @playerversion AIR 1.1
+ *  @productversion Flex 3
+ */
+public dynamic class ObjectProxy //extends Proxy
+                                 //implements IExternalizable,
+                                 //IPropertyChangeNotifier
+{
+    
//--------------------------------------------------------------------------
+    //
+    //  Constructor
+    //
+    
//--------------------------------------------------------------------------
+
+    /**
+     *  Initializes this proxy with the specified object, id and proxy depth.
+     * 
+     *  @param item Object to proxy.
+     *  If no item is specified, an anonymous object will be constructed
+     *  and assigned.
+     *
+     *  @param uid String containing the unique id
+     *  for this object instance.
+     *  Required for IPropertyChangeNotifier compliance as every object must 
+     *  provide a unique way of identifying it.
+     *  If no value is specified, a random id will be assigned.
+     *
+     *  @param proxyDepth An integer indicating how many levels in a complex
+     *  object graph should have a proxy created during property access.
+     *  The default is -1, meaning "proxy to infinite depth".
+     *  
+     *  @example
+     *
+     *  <pre>
+     *  import mx.events.PropertyChangeEvent;
+     *  import mx.utils.ObjectUtil;
+     *  import mx.utils.ObjectProxy;
+     *  import mx.utils.StringUtil;
+     *
+     *  var a:Object = { name: "Tyler", age: 5, ssnum: "555-55-5555" };
+     *  var p:ObjectProxy = new ObjectProxy(a);
+     *  p.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, updateHandler);
+     *  p.name = "Jacey";
+     *  p.age = 2;
+     *  delete p.ssnum;
+     *
+     *  // handler function
+     *  function updateHandler(event:PropertyChangeEvent):void
+     *  {
+     *      trace(StringUtil.substitute("updateHandler('{0}', {1}, {2}, {3}, 
'{4}')",
+     *                                     event.kind,
+     *                                     event.property,
+     *                                     event.oldValue,
+     *                                     event.newValue,
+     *                                     event.target.uid));
+     *  }
+     *
+     *  // trace output
+     *  updateHandler('opUpdate', name, Jacey, 
'698AF8CB-B3D9-21A3-1AFFDGHT89075CD2')
+     *  updateHandler('opUpdate', age, 2, 
'698AF8CB-B3D9-21A3-1AFFDGHT89075CD2')
+     *  updateHandler('opDelete', ssnum, null, 
'698AF8CB-B3D9-21A3-1AFFDGHT89075CD2')
+     *  </pre>
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function ObjectProxy(item:Object = null, uid:String = null,
+                                proxyDepth:int = -1)
+    {
+               if (GOOG::DEBUG)
+                       trace("ObjectProxy not implemented");
+//        super();
+//
+//        if (!item)
+//            item = {};
+//        _item = item;
+//
+//        _proxyLevel = proxyDepth;
+//       
+//        notifiers = {};
+//
+//        dispatcher = new EventDispatcher(this);
+//
+//        // If we got an id, use it.  Otherwise the UID is lazily
+//        // created in the getter for UID.
+//        if (uid)
+//            _id = uid;
+    }
+
+    
//--------------------------------------------------------------------------
+    //
+    //  Variables
+    //
+    
//--------------------------------------------------------------------------
+
+    /**
+     *  A reference to the EventDispatcher for this proxy.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+//    protected var dispatcher:EventDispatcher;
+
+    /**
+     *  A hashmap of property change notifiers that this proxy is 
+     *  listening for changes from; the key of the map is the property name.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+//    protected var notifiers:Object;
+    
+    /**
+     *  Indicates what kind of proxy to create
+     *  when proxying complex properties.
+     *  Subclasses should assign this value appropriately.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+//    protected var proxyClass:Class = ObjectProxy;
+    
+    /**
+     *  Contains a list of all of the property names for the proxied object.
+     *  Descendants need to fill this list by overriding the
+     *  <code>setupPropertyList()</code> method.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+//    protected var propertyList:Array;
+    
+    /**
+     *  Indicates how deep proxying should be performed.
+     *  If -1 (default), always proxy; 
+     *  if this value is zero, no proxying will be performed.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+//    private var _proxyLevel:int;
+    
+    
//--------------------------------------------------------------------------
+    //
+    //  Properties
+    //
+    
//--------------------------------------------------------------------------
+
+    //----------------------------------
+    //  object
+    //----------------------------------
+
+    /**
+     *  Storage for the object property.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+//    private var _item:Object;
+
+    /**
+     *  The object being proxied.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+//    object_proxy function get object():Object
+//    {
+//        return _item;
+//    }
+
+    //----------------------------------
+    //  type
+    //----------------------------------
+
+    /**
+     *  @private
+     *  Storage for the qualified type name.
+     */
+//    private var _type:QName;
+
+    /**
+     *  The qualified type name associated with this object.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+//    object_proxy function get type():QName
+//    {
+//        return _type;
+//    }
+
+    /**
+     *  @private
+     */
+//    object_proxy function set type(value:QName):void
+//    {
+//        _type = value;
+//    }
+
+    //----------------------------------
+    //  uid
+    //----------------------------------
+
+    /**
+     *  @private
+     *  Storage for the uid property.
+     */
+//    private var _id:String;
+
+    /**
+     *  The unique identifier for this object.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+//    public function get uid():String
+//    {
+//        if (_id === null)
+//            _id = UIDUtil.createUID();
+//            
+//        return _id;
+//    }
+
+    /**
+     *  @private
+     */
+//    public function set uid(value:String):void
+//    {
+//        _id = value;
+//    }
+
+    
//--------------------------------------------------------------------------
+    //
+    //  Overridden methods
+    //
+    
//--------------------------------------------------------------------------
+
+    /**
+     *  Returns the specified property value of the proxied object.
+     *
+     *  @param name Typically a string containing the name of the property,
+     *  or possibly a QName where the property name is found by 
+     *  inspecting the <code>localName</code> property.
+     *
+     *  @return The value of the property.
+     *  In some instances this value may be an instance of 
+     *  <code>ObjectProxy</code>.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+//    override flash_proxy function getProperty(name:*):*
+//    {
+//        // if we have a data proxy for this then
+//        var result:*;
+//
+//        if (notifiers[name.toString()])
+//            return notifiers[name];
+//
+//        result = _item[name];
+//
+//        if (result)
+//        {
+//            if (_proxyLevel == 0 || ObjectUtil.isSimple(result))
+//            {
+//                return result;
+//            }
+//            else
+//            {
+//                result = object_proxy::getComplexProperty(name, result);
+//            } // if we are proxying
+//        }
+//
+//        return result;
+//    }
+
+    /**
+     *  Returns the value of the proxied object's method with the specified 
name.
+     *
+     *  @param name The name of the method being invoked.
+     *
+     *  @param rest An array specifying the arguments to the
+     *  called method.
+     *
+     *  @return The return value of the called method.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+//    override flash_proxy function callProperty(name:*, ... rest):*
+//    {
+//        return _item[name].apply(_item, rest)
+//    }
+
+    /**
+     *  Deletes the specified property on the proxied object and
+     *  sends notification of the delete to the handler.
+     * 
+     *  @param name Typically a string containing the name of the property,
+     *  or possibly a QName where the property name is found by 
+     *  inspecting the <code>localName</code> property.
+     *
+     *  @return A Boolean indicating if the property was deleted.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+//    override flash_proxy function deleteProperty(name:*):Boolean
+//    {
+//        var notifier:IPropertyChangeNotifier = 
IPropertyChangeNotifier(notifiers[name]);
+//        if (notifier)
+//        {
+//            notifier.removeEventListener(PropertyChangeEvent.PROPERTY_CHANGE,
+//                                         propertyChangeHandler);
+//            delete notifiers[name];
+//        }
+//
+//        var oldVal:* = _item[name];
+//        var deleted:Boolean = delete _item[name]; 
+//
+//        if (dispatcher.hasEventListener(PropertyChangeEvent.PROPERTY_CHANGE))
+//        {
+//            var event:PropertyChangeEvent = new 
PropertyChangeEvent(PropertyChangeEvent.PROPERTY_CHANGE);
+//            event.kind = PropertyChangeEventKind.DELETE;
+//            event.property = name;
+//            event.oldValue = oldVal;
+//            event.source = this;
+//            dispatcher.dispatchEvent(event);
+//        }
+//
+//        return deleted;
+//    }
+
+    /**
+     *  @private
+     */
+//    override flash_proxy function hasProperty(name:*):Boolean
+//    {
+//        return(name in _item);
+//    }
+    
+    /**
+     *  @private
+     */
+//    override flash_proxy function nextName(index:int):String
+//    {
+//        return propertyList[index -1];
+//    }
+    
+    /**
+     *  @private
+     */
+//    override flash_proxy function nextNameIndex(index:int):int
+//    {
+//        if (index == 0)
+//        {
+//            setupPropertyList();
+//        }
+//        
+//        if (index < propertyList.length)
+//        {
+//            return index + 1;
+//        }
+//        else
+//        {
+//            return 0;
+//        }
+//    }
+    
+    /**
+     *  @private
+     */
+//    override flash_proxy function nextValue(index:int):*
+//    {
+//        return _item[propertyList[index -1]];
+//    }
+
+    /**
+     *  Updates the specified property on the proxied object
+     *  and sends notification of the update to the handler.
+     *
+     *  @param name Object containing the name of the property that
+     *  should be updated on the proxied object.
+     *
+     *  @param value Value that should be set on the proxied object.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+//    override flash_proxy function setProperty(name:*, value:*):void
+//    {
+//        var oldVal:* = _item[name];
+//        if (oldVal !== value)
+//        {
+//            // Update item.
+//            _item[name] = value;
+//
+//            // Stop listening for events on old item if we currently are.
+//            var notifier:IPropertyChangeNotifier =
+//                IPropertyChangeNotifier(notifiers[name]);
+//            if (notifier)
+//            {
+//                notifier.removeEventListener(
+//                    PropertyChangeEvent.PROPERTY_CHANGE,
+//                    propertyChangeHandler);
+//                delete notifiers[name];
+//            }
+//
+//            // Notify anyone interested.
+//            if 
(dispatcher.hasEventListener(PropertyChangeEvent.PROPERTY_CHANGE))
+//            {
+//                if (name is QName)
+//                    name = QName(name).localName;
+//                var event:PropertyChangeEvent =
+//                    PropertyChangeEvent.createUpdateEvent(
+//                        this, name.toString(), oldVal, value);
+//                dispatcher.dispatchEvent(event);
+//            } 
+//        }
+//    }
+
+    
//--------------------------------------------------------------------------
+    //
+    //  object_proxy methods
+    //
+    
//--------------------------------------------------------------------------
+
+    /**
+     *  Provides a place for subclasses to override how a complex property that
+     *  needs to be either proxied or daisy chained for event bubbling is 
managed.
+     * 
+     *  @param name Typically a string containing the name of the property,
+     *  or possibly a QName where the property name is found by 
+     *  inspecting the <code>localName</code> property.
+     *
+     *  @param value The property value.
+     *
+     *  @return The property value or an instance of <code>ObjectProxy</code>.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */  
+//    object_proxy function getComplexProperty(name:*, value:*):*
+//    {
+//        if (value is IPropertyChangeNotifier)
+//        {
+//            value.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE,
+//                                   propertyChangeHandler);
+//            notifiers[name] = value;
+//            return value;
+//        }
+//        
+//        if (getQualifiedClassName(value) == "Object")
+//        {
+//            value = new proxyClass(_item[name], null,
+//                _proxyLevel > 0 ? _proxyLevel - 1 : _proxyLevel);
+//            value.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE,
+//                                   propertyChangeHandler);
+//            notifiers[name] = value;
+//            return value;
+//        }
+//
+//        return value;
+//    }
+    
+    
//--------------------------------------------------------------------------
+    //
+    //  IExternalizable Methods
+    //
+    
//--------------------------------------------------------------------------
+
+    /**
+     *  Since Flex only uses ObjectProxy to wrap anonymous objects,
+     *  the server flex.messaging.io.ObjectProxy instance serializes itself
+     *  as a Map that will be returned as a plain ActionScript object. 
+     *  You can then set the object_proxy object property to this value.
+     *
+     *  @param input The source object from which the ObjectProxy is
+     *  deserialized. 
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+//    public function readExternal(input:IDataInput):void
+//    {
+//        var value:Object = input.readObject();
+//        _item = value;
+//    }
+
+    /**
+     *  Since Flex only serializes the inner ActionScript object that it wraps,
+     *  the server flex.messaging.io.ObjectProxy populates itself
+     *  with this anonymous object's contents and appears to the user
+     *  as a Map.
+     *
+     *  @param output The source object from which the ObjectProxy is
+     *  deserialized.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+//    public function writeExternal(output:IDataOutput):void
+//    {
+//        output.writeObject(_item);
+//    }
+
+    
//--------------------------------------------------------------------------
+    //
+    //  Methods
+    //
+    
//--------------------------------------------------------------------------
+
+    /**
+     *  Registers an event listener object  
+     *  so that the listener receives notification of an event. 
+     *  For more information, including descriptions of the parameters see 
+     *  <code>addEventListener()</code> in the 
+     *  flash.events.EventDispatcher class.
+     *
+     *  @param type The type of event.
+     *  
+     *  @param listener The listener function that processes the event. This 
function must accept
+     *  an Event object as its only parameter and must return nothing.
+     *  
+     *  @param useCapture Determines whether the listener works in the capture 
phase or the 
+     *  target and bubbling phases. If <code>useCapture</code> is set to 
<code>true</code>, 
+     *  the listener processes the event only during the capture phase and not 
in the 
+     *  target or bubbling phase. If <code>useCapture</code> is 
<code>false</code>, the
+     *  listener processes the event only during the target or bubbling phase. 
To listen for
+     *  the event in all three phases, call <code>addEventListener</code> 
twice, once with 
+     *  <code>useCapture</code> set to <code>true</code>, then again with
+     *  <code>useCapture</code> set to <code>false</code>.
+     * 
+     *  @param priority The priority level of the event listener. 
+     * 
+     *  @param useWeakReference Determines whether the reference to the 
listener is strong or
+     *  weak. A strong reference (the default) prevents your listener from 
being garbage-collected.
+     *  A weak reference does not. 
+     *
+     *  @see flash.events.EventDispatcher#addEventListener()
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+//    public function addEventListener(type:String, listener:Function,
+//                                     useCapture:Boolean = false,
+//                                     priority:int = 0,
+//                                     useWeakReference:Boolean = false):void
+//    {
+//        dispatcher.addEventListener(type, listener, useCapture,
+//                                    priority, useWeakReference);
+//    }
+
+    /**
+     *  Removes an event listener. 
+     *  If there is no matching listener registered with the EventDispatcher 
object, 
+     *  a call to this method has no effect.
+     *  For more information, see 
+     *  the flash.events.EventDispatcher class.
+     *  
+     *  @param type The type of event.
+     * 
+     *  @param listener The listener object to remove.
+     *
+     *  @param useCapture Specifies whether the listener was registered for 
the capture 
+     *  phase or the target and bubbling phases. If the listener was 
registered for both 
+     *  the capture phase and the target and bubbling phases, two calls to 
+     *  <code>removeEventListener()</code> are required to remove both, one 
call with 
+     *  <code>useCapture</code> 
+     *  set to <code>true</code>, and another call with <code>useCapture</code>
+     *  set to <code>false</code>.
+     *
+     *  @see flash.events.EventDispatcher#removeEventListener()
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+//    public function removeEventListener(type:String, listener:Function,
+//                                        useCapture:Boolean = false):void
+//    {
+//        dispatcher.removeEventListener(type, listener, useCapture);
+//    }
+
+    /**
+     *  Dispatches an event into the event flow. 
+     *  For more information, see
+     *  the flash.events.EventDispatcher class.
+     *  
+     *  @param event The Event object that is dispatched into the event flow. 
If the 
+     *  event is being redispatched, a clone of the event is created 
automatically. 
+     *  After an event is dispatched, its target property cannot be changed, 
so you 
+     *  must create a new copy of the event for redispatching to work.
+     *
+     *  @return Returns <code>true</code> if the event was successfully 
dispatched. 
+     *  A value 
+     *  of <code>false</code> indicates failure or that 
<code>preventDefault()</code>
+     *  was called on the event.
+     *
+     *  @see flash.events.EventDispatcher#dispatchEvent()
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+//    public function dispatchEvent(event:Event):Boolean
+//    {
+//        return dispatcher.dispatchEvent(event);
+//    }
+    
+    /**
+     *  Checks whether there are any event listeners registered 
+     *  for a specific type of event. 
+     *  This allows you to determine where an object has altered handling 
+     *  of an event type in the event flow hierarchy. 
+     *  For more information, see
+     *  the flash.events.EventDispatcher class.
+     *
+     *  @param type The type of event
+     *
+     *  @return Returns <code>true</code> if a listener of the specified type 
is 
+     *  registered; <code>false</code> otherwise.
+     *
+     *  @see flash.events.EventDispatcher#hasEventListener()
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+//    public function hasEventListener(type:String):Boolean
+//    {
+//        return dispatcher.hasEventListener(type);
+//    }
+    
+    /**
+     *  Checks whether an event listener is registered with this object 
+     *  or any of its ancestors for the specified event type. 
+     *  This method returns <code>true</code> if an event listener is 
triggered 
+     *  during any phase of the event flow when an event of the specified 
+     *  type is dispatched to this object or any of its descendants.
+     *  For more information, see the flash.events.EventDispatcher class.
+     *
+     *  @param type The type of event.
+     *
+     *  @return Returns <code>true</code> if a listener of the specified type 
will 
+     *  be triggered; <code>false</code> otherwise.
+     *
+     *  @see flash.events.EventDispatcher#willTrigger()
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+//    public function willTrigger(type:String):Boolean
+//    {
+//        return dispatcher.willTrigger(type);
+//    }
+
+    /**
+     *  Called when a complex property is updated.
+     *
+     *  @param event An event object that has changed.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+//    public function propertyChangeHandler(event:PropertyChangeEvent):void
+//    {
+//        dispatcher.dispatchEvent(event);
+//    }
+    
+    
//--------------------------------------------------------------------------
+    //
+    //  Protected Methods
+    //
+    
//--------------------------------------------------------------------------
+
+    /**
+     *  This method creates an array of all of the property names for the 
+     *  proxied object.
+     *  Descendants must override this method if they wish to add more 
+     *  properties to this list.
+     *  Be sure to call <code>super.setupPropertyList</code> before making any
+     *  changes to the <code>propertyList</code> property.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+//    protected function setupPropertyList():void
+//    {
+//        if (getQualifiedClassName(_item) == "Object")
+//        {
+//            propertyList = [];
+//            for (var prop:String in _item)
+//                propertyList.push(prop);
+//        }
+//        else
+//        {
+//            propertyList = ObjectUtil.getClassInfo(_item, null, 
{includeReadOnly:true, uris:["*"]}).properties;
+//        }
+//    }
+}
+
+}
diff --git 
a/frameworks/projects/MXRoyale/src/main/royale/mx/utils/ObjectUtil.as 
b/frameworks/projects/MXRoyale/src/main/royale/mx/utils/ObjectUtil.as
new file mode 100644
index 0000000..c46249f
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/utils/ObjectUtil.as
@@ -0,0 +1,1130 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.utils
+{
+COMPILE::JS {
+       import goog.DEBUG;
+}
+/*
+import flash.utils.ByteArray;
+import flash.utils.Dictionary;
+import flash.utils.getQualifiedClassName;
+import flash.xml.XMLNode;
+*/
+import mx.collections.IList;
+
+/**
+ *  The ObjectUtil class is an all-static class with methods for
+ *  working with Objects within Flex.
+ *  You do not create instances of ObjectUtil;
+ *  instead you simply call static methods such as the 
+ *  <code>ObjectUtil.isSimple()</code> method.
+ *  
+ *  @langversion 3.0
+ *  @playerversion Flash 9
+ *  @playerversion AIR 1.1
+ *  @productversion Flex 3
+ */
+public class ObjectUtil
+{    
+    /**
+    *  Array of properties to exclude from debugging output.
+    *  
+    *  @langversion 3.0
+    *  @playerversion Flash 9
+    *  @playerversion AIR 1.1
+    *  @productversion Flex 3
+    */
+    private static var defaultToStringExcludes:Array = ["password", 
"credentials"];
+
+    
//--------------------------------------------------------------------------
+    //
+    //  Class methods
+    //
+    
//--------------------------------------------------------------------------
+
+    /**
+     *  Compares the Objects and returns an integer value 
+     *  indicating if the first item is less than, greater than, or equal to
+     *  the second item.
+     *  This method will recursively compare properties on nested objects and
+     *  will return as soon as a non-zero result is found.
+     *  By default this method will recurse to the deepest level of any 
property.
+     *  To change the depth for comparison specify a non-negative value for
+     *  the <code>depth</code> parameter.
+     *
+     *  @param a Object.
+     *
+     *  @param b Object.
+     *
+     *  @param depth Indicates how many levels should be 
+     *  recursed when performing the comparison.
+     *  Set this value to 0 for a shallow comparison of only the primitive 
+     *  representation of each property.
+     *  For example:<pre>
+     *  var a:Object = {name:"Bob", info:[1,2,3]};
+     *  var b:Object = {name:"Alice", info:[5,6,7]};
+     *  var c:int = ObjectUtil.compare(a, b, 0);</pre>
+     *
+     *  <p>In the above example the complex properties of <code>a</code> and 
+     *  <code>b</code> will be flattened by a call to <code>toString()</code>
+     *  when doing the comparison.
+     *  In this case the <code>info</code> property will be turned into a 
string
+     *  when performing the comparison.</p>
+     *
+     *  @return Return 0 if a and b are equal, or both null or NaN.
+     *  Return 1 if a is null or greater than b. 
+     *  Return -1 if b is null or greater than a. 
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static function compare(a:Object, b:Object, depth:int = -1):int
+    {
+               if (GOOG::DEBUG)
+                       trace("compare not implemented");
+               return 0;
+        //return internalCompare(a, b, 0, depth, new Dictionary(true));
+    }
+    
+    /**
+     *  Copies the specified Object and returns a reference to the copy.
+     *  The copy is made using a native serialization technique. 
+     *  This means that custom serialization will be respected during the copy.
+     *
+     *  <p>This method is designed for copying data objects, 
+     *  such as elements of a collection. It is not intended for copying 
+     *  a UIComponent object, such as a TextInput control. If you want to 
create copies 
+     *  of specific UIComponent objects, you can create a subclass of the 
component and implement 
+     *  a <code>clone()</code> method, or other method to perform the copy.</p>
+     * 
+     *  @param value Object that should be copied.
+     * 
+     *  @return Copy of the specified Object.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */ 
+    public static function copy(value:Object):Object
+    {
+               if (GOOG::DEBUG)
+                       trace("copy not implemented");
+               return null;
+//        var buffer:ByteArray = new ByteArray();
+//        buffer.writeObject(value);
+//        buffer.position = 0;
+//        var result:Object = buffer.readObject();
+//        return result;
+    }
+
+    /**
+     *  Clones the specified Object and returns a reference to the clone.
+     *  The clone is made using a native serialization technique. 
+     *  This means that custom serialization will be respected during the
+     *  cloning.  clone() differs from copy() in that the uid property of
+     *  each object instance is retained.
+     *
+     *  <p>This method is designed for cloning data objects, 
+     *  such as elements of a collection. It is not intended for cloning 
+     *  a UIComponent object, such as a TextInput control. If you want to clone
+     *  specific UIComponent objects, you can create a subclass of the 
component
+     *  and implement a <code>clone()</code> method.</p>
+     * 
+     *  @param value Object that should be cloned.
+     * 
+     *  @return Clone of the specified Object.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 4
+     */ 
+    public static function clone(value:Object):Object
+    {
+               if (GOOG::DEBUG)
+                       trace("clone not implemented");
+               return null;
+//        var result:Object = copy(value);
+//        cloneInternal(result, value);
+//        return result;
+    }
+
+    /**
+     *  Recursive helper used by the public clone method. 
+     *  @private
+     */    
+    private static function cloneInternal(result:Object, value:Object):void
+    {
+               if (GOOG::DEBUG)
+                       trace("cloneInternal not implemented");
+//        if (value && value.hasOwnProperty("uid"))
+//            result.uid = value.uid;
+//
+//        var classInfo:Object = getClassInfo(value);
+//        var v:Object;
+//        for each (var p:* in classInfo.properties) 
+//        {
+//            v = value[p];
+//            if (v && v.hasOwnProperty("uid")) 
+//                cloneInternal(result[p], v);
+//        }
+    }
+   
+    /**
+     *  Returns <code>true</code> if the object reference specified
+     *  is a simple data type. The simple data types include the following:
+     *  <ul>
+     *    <li><code>String</code></li>
+     *    <li><code>Number</code></li>
+     *    <li><code>uint</code></li>
+     *    <li><code>int</code></li>
+     *    <li><code>Boolean</code></li>
+     *    <li><code>Date</code></li>
+     *    <li><code>Array</code></li>
+     *  </ul>
+     *
+     *  @param value Object inspected.
+     *
+     *  @return <code>true</code> if the object specified
+     *  is one of the types above; <code>false</code> otherwise.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static function isSimple(value:Object):Boolean
+    {
+        var objectType:String = typeof(value);
+        switch (objectType)
+        {
+            case "number":
+            case "string":
+            case "boolean":
+            {
+                return true;
+            }
+
+            case "object":
+            {
+                return (value is Date) || (value is Array);
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     *  Compares two numeric values.
+     * 
+     *  @param a First number.
+     * 
+     *  @param b Second number.
+     *
+     *  @return 0 is both numbers are NaN. 
+     *  1 if only <code>a</code> is a NaN.
+     *  -1 if only <code>b</code> is a NaN.
+     *  -1 if <code>a</code> is less than <code>b</code>.
+     *  1 if <code>a</code> is greater than <code>b</code>.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static function numericCompare(a:Number, b:Number):int
+    {
+        if (isNaN(a) && isNaN(b))
+            return 0;
+
+        if (isNaN(a))
+            return 1;
+
+        if (isNaN(b))
+           return -1;
+
+        if (a < b)
+            return -1;
+
+        if (a > b)
+            return 1;
+
+        return 0;
+    }
+
+    /**
+     *  Compares two String values.
+     * 
+     *  @param a First String value.
+     * 
+     *  @param b Second String value.
+     *
+     *  @param caseInsensitive Specifies to perform a case insensitive 
compare, 
+     *  <code>true</code>, or not, <code>false</code>.
+     *
+     *  @return 0 is both Strings are null. 
+     *  1 if only <code>a</code> is null.
+     *  -1 if only <code>b</code> is null.
+     *  -1 if <code>a</code> precedes <code>b</code>.
+     *  1 if <code>b</code> precedes <code>a</code>.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static function stringCompare(a:String, b:String,
+                                         caseInsensitive:Boolean = false):int
+    {
+        if (a == null && b == null)
+            return 0;
+
+        if (a == null)
+          return 1;
+
+        if (b == null)
+           return -1;
+
+        // Convert to lowercase if we are case insensitive.
+        if (caseInsensitive)
+        {
+            a = a.toLocaleLowerCase();
+            b = b.toLocaleLowerCase();
+        }
+
+        var result:int = a.localeCompare(b);
+        
+        if (result < -1)
+            result = -1;
+        else if (result > 1)
+            result = 1;
+
+        return result;
+    }
+
+    /**
+     *  Compares the two Date objects and returns an integer value 
+     *  indicating if the first Date object is before, equal to, 
+     *  or after the second item.
+     *
+     *  @param a Date object.
+     *
+     *  @param b Date object.
+     *
+     *  @return 0 if <code>a</code> and <code>b</code> are equal
+     *  (or both are <code>null</code>);
+     *  -1 if <code>a</code> is before <code>b</code>
+     *  (or <code>b</code> is <code>null</code>);
+     *  1 if <code>a</code> is after <code>b</code>
+     *  (or <code>a</code> is <code>null</code>);
+        *  0 is both dates getTime's are NaN;
+     *  1 if only <code>a</code> getTime is a NaN;
+     *  -1 if only <code>b</code> getTime is a NaN.    
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static function dateCompare(a:Date, b:Date):int
+    {
+        if (a == null && b == null)
+            return 0;
+
+        if (a == null)
+          return 1;
+
+        if (b == null)
+           return -1;
+
+        var na:Number = a.getTime();
+        var nb:Number = b.getTime();
+        
+        if (na < nb)
+            return -1;
+
+        if (na > nb)
+            return 1;
+               
+               if (isNaN(na) && isNaN(nb))
+                       return 0;
+               
+               if (isNaN(na))
+                       return 1;
+               
+               if (isNaN(nb))
+                       return -1;
+
+        return 0;
+    }
+        
+    /**
+     *  Pretty-prints the specified Object into a String.
+     *  All properties will be in alpha ordering.
+     *  Each object will be assigned an id during printing;
+     *  this value will be displayed next to the object type token
+     *  preceded by a '#', for example:
+     *
+     *  <pre>
+     *  (mx.messaging.messages::AsyncMessage)#2.</pre>
+     *
+     *  <p>This id is used to indicate when a circular reference occurs.
+     *  Properties of an object that are of the <code>Class</code> type will
+     *  appear only as the assigned type.
+     *  For example a custom definition like the following:</p>
+     *
+     *  <pre>
+     *    public class MyCustomClass {
+     *      public var clazz:Class;
+     *    }</pre>
+     * 
+     *  <p>With the <code>clazz</code> property assigned to <code>Date</code>
+     *  will display as shown below:</p>
+     * 
+     *  <pre>
+     *   (somepackage::MyCustomClass)#0
+     *      clazz = (Date)</pre>
+     *
+     *  @param value Object to be pretty printed.
+     * 
+     *  @param namespaceURIs Array of namespace URIs for properties 
+     *  that should be included in the output.
+     *  By default only properties in the public namespace will be included in
+     *  the output.
+     *  To get all properties regardless of namespace pass an array with a 
+     *  single element of "*".
+     * 
+     *  @param exclude Array of the property names that should be 
+     *  excluded from the output.
+     *  Use this to remove data from the formatted string.
+     * 
+     *  @return String containing the formatted version
+     *  of the specified object.
+     *
+     *  @example
+     *  <pre>
+     *  // example 1
+     *  var obj:AsyncMessage = new AsyncMessage();
+     *  obj.body = [];
+     *  obj.body.push(new AsyncMessage());
+     *  obj.headers["1"] = { name: "myName", num: 15.3};
+     *  obj.headers["2"] = { name: "myName", num: 15.3};
+     *  obj.headers["10"] = { name: "myName", num: 15.3};
+     *  obj.headers["11"] = { name: "myName", num: 15.3};
+     *  trace(ObjectUtil.toString(obj));
+     *
+     *  // will output to flashlog.txt
+     *  (mx.messaging.messages::AsyncMessage)#0
+     *    body = (Array)#1
+     *      [0] (mx.messaging.messages::AsyncMessage)#2
+     *        body = (Object)#3
+     *        clientId = (Null)
+     *        correlationId = ""
+     *        destination = ""
+     *        headers = (Object)#4
+     *        messageId = "378CE96A-68DB-BC1B-BCF7FFFFFFFFB525"
+     *        sequenceId = (Null)
+     *        sequencePosition = 0
+     *        sequenceSize = 0
+     *        timeToLive = 0
+     *        timestamp = 0
+     *    clientId = (Null)
+     *    correlationId = ""
+     *    destination = ""
+     *    headers = (Object)#5
+     *      1 = (Object)#6
+     *        name = "myName"
+     *        num = 15.3
+     *      10 = (Object)#7
+     *        name = "myName"
+     *        num = 15.3
+     *      11 = (Object)#8
+     *        name = "myName"
+     *        num = 15.3
+     *      2 = (Object)#9
+     *        name = "myName"
+     *        num = 15.3
+     *    messageId = "1D3E6E96-AC2D-BD11-6A39FFFFFFFF517E"
+     *    sequenceId = (Null)
+     *    sequencePosition = 0
+     *    sequenceSize = 0
+     *    timeToLive = 0
+     *    timestamp = 0
+     *
+     *  // example 2 with circular references
+     *  obj = {};
+     *  obj.prop1 = new Date();
+     *  obj.prop2 = [];
+     *  obj.prop2.push(15.2);
+     *  obj.prop2.push("testing");
+     *  obj.prop2.push(true);
+     *  obj.prop3 = {};
+     *  obj.prop3.circular = obj;
+     *  obj.prop3.deeper = new ErrorMessage();
+     *  obj.prop3.deeper.rootCause = obj.prop3.deeper;
+     *  obj.prop3.deeper2 = {};
+     *  obj.prop3.deeper2.deeperStill = {};
+     *  obj.prop3.deeper2.deeperStill.yetDeeper = obj;
+     *  trace(ObjectUtil.toString(obj));
+     *
+     *  // will output to flashlog.txt
+     *  (Object)#0
+     *    prop1 = Tue Apr 26 13:59:17 GMT-0700 2005
+     *    prop2 = (Array)#1
+     *      [0] 15.2
+     *      [1] "testing"
+     *      [2] true
+     *    prop3 = (Object)#2
+     *      circular = (Object)#0
+     *      deeper = (mx.messaging.messages::ErrorMessage)#3
+     *        body = (Object)#4
+     *        clientId = (Null)
+     *        code = (Null)
+     *        correlationId = ""
+     *        destination = ""
+     *        details = (Null)
+     *        headers = (Object)#5
+     *        level = (Null)
+     *        message = (Null)
+     *        messageId = "14039376-2BBA-0D0E-22A3FFFFFFFF140A"
+     *        rootCause = (mx.messaging.messages::ErrorMessage)#3
+     *        sequenceId = (Null)
+     *        sequencePosition = 0
+     *        sequenceSize = 0
+     *        timeToLive = 0
+     *        timestamp = 0
+     *      deeper2 = (Object)#6
+     *        deeperStill = (Object)#7
+     *          yetDeeper = (Object)#0
+     * 
+     * // example 3 with Dictionary
+     * var point:Point = new Point(100, 100);
+     * var point2:Point = new Point(100, 100);
+     * var obj:Dictionary = new Dictionary();
+     * obj[point] = "point";
+     * obj[point2] = "point2";
+     * obj["1"] = { name: "one", num: 1};
+     * obj["two"] = { name: "2", num: 2};
+     * obj[3] = 3;
+     * trace(ObjectUtil.toString(obj));
+     * 
+     * // will output to flashlog.txt
+     * (flash.utils::Dictionary)#0
+     *   {(flash.geom::Point)#1
+     *     length = 141.4213562373095
+     *     x = 100
+     *     y = 100} = "point2"
+     *   {(flash.geom::Point)#2
+     *     length = 141.4213562373095
+     *     x = 100
+     *     y = 100} = "point"
+     *   {1} = (Object)#3
+     *     name = "one"
+     *     num = 1
+     *   {3} = 3
+     *   {"two"} = (Object)#4
+     *     name = "2"
+     *     num = 2
+     * 
+     * </pre>
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static function toString(value:Object, 
+                                    namespaceURIs:Array = null, 
+                                    exclude:Array = null):String
+    {
+        if (exclude == null)
+        {
+            exclude = defaultToStringExcludes;
+        }
+        
+        refCount = 0;
+        return internalToString(value, 0, null, namespaceURIs, exclude);
+    }
+    
+    /**
+     *  This method cleans up all of the additional parameters that show up in 
AsDoc
+     *  code hinting tools that developers shouldn't ever see.
+     *  @private
+     */
+    private static function internalToString(value:Object, 
+                                             indent:int = 0,
+                                                                               
         refs:Object = null,
+                                             namespaceURIs:Array = null, 
+                                             exclude:Array = null):String
+    {
+        if (GOOG::DEBUG)
+                       trace("internalToString not implemented");
+        
+        return "(unknown)";
+    }
+
+    /**
+     *  @private
+     *  This method will append a newline and the specified number of spaces
+     *  to the given string.
+     */
+    private static function newline(str:String, n:int = 0):String
+    {
+        var result:String = str;
+        result += "\n";
+        
+        for (var i:int = 0; i < n; i++)
+        {
+            result += " ";
+        }
+        return result;
+    }
+    
+    private static function internalCompare(a:Object, b:Object,
+                                            currentDepth:int, desiredDepth:int,
+                                            /*refs:Dictionary*/ 
refs:Object):int
+    {
+        if (a == null && b == null)
+            return 0;
+    
+        if (a == null)
+            return 1;
+    
+        if (b == null)
+            return -1;
+           
+//        if (a is ObjectProxy)
+//            a = ObjectProxy(a).object_proxy::object;
+//            
+//        if (b is ObjectProxy)
+//            b = ObjectProxy(b).object_proxy::object;
+            
+        var typeOfA:String = typeof(a);
+        var typeOfB:String = typeof(b);
+        
+        var result:int = 0;
+        
+        if (typeOfA == typeOfB)
+        {
+            switch(typeOfA)
+            {
+                case "boolean":
+                    result = numericCompare(Number(a), Number(b));
+                       break;
+                
+                case "number":
+                    result = numericCompare(a as Number, b as Number);
+                    break;
+                
+                case "string":
+                    result = stringCompare(a as String, b as String);
+                    break;
+                
+                case "object":
+                    var newDepth:int = desiredDepth > 0 ? desiredDepth -1 : 
desiredDepth;
+                    
+                    // refs help us avoid circular reference infinite 
recursion.
+                    var aRef:Object = getRef(a,refs);
+                    var bRef:Object = getRef(b,refs);
+                    
+                    if (aRef == bRef)
+                        return 0;
+                    // the cool thing about our dictionary is that if 
+                    // we've seen objects and determined that they are 
unequal, then
+                    // we would've already exited out of this compare() call.  
So the 
+                    // only info in the dictionary are sets of equal items
+                    
+                    // let's first define them as equal
+                    // this stops an "infinite loop" problem where A.i = B and 
B.i = A
+                    // if we later find that an object (one of the subobjects) 
is in fact unequal, 
+                    // then we will return false and quit out of everything.  
These refs are thrown away
+                    // so it doesn't matter if it's correct.
+                    refs[bRef] = aRef;
+                    
+                    if (desiredDepth != -1 && (currentDepth > desiredDepth))
+                    {
+                        // once we try to go beyond the desired depth we 
should 
+                        // toString() our way out
+                        result = stringCompare(a.toString(), b.toString());
+                    }
+                    else if ((a is Array) && (b is Array))
+                    {
+                        result = arrayCompare(a as Array, b as Array, 
currentDepth, desiredDepth, refs);
+                    }
+                    else if ((a is Date) && (b is Date))
+                    {
+                        result = dateCompare(a as Date, b as Date);
+                    }
+                    else if ((a is IList) && (b is IList))
+                    {
+                        result = listCompare(a as IList, b as IList, 
currentDepth, desiredDepth, refs);
+                    }
+                    else
+                    {
+                        // We must be unequal, so return 1
+                        return 1;
+                    }
+                    break;
+                               
+                               default:
+                                       break;
+            }
+        }
+        else // be consistent with the order we return here
+        {
+            return stringCompare(typeOfA, typeOfB);
+        }
+
+        return result;
+    }
+    
+    /**
+     *  Returns information about the class, and properties of the class, for
+     *  the specified Object.
+     *
+     *  @param obj The Object to inspect.
+     *
+     *  @param excludes Array of Strings specifying the property names that 
should be
+     *  excluded from the returned result. For example, you could specify 
+     *  <code>["currentTarget", "target"]</code> for an Event object since 
these properties 
+     *  can cause the returned result to become large.
+     *
+     *  @param options An Object containing one or more properties 
+     *  that control the information returned by this method. 
+     *  The properties include the following:
+     *
+     *  <ul>
+     *    <li><code>includeReadOnly</code>: If <code>false</code>, 
+     *      exclude Object properties that are read-only. 
+     *      The default value is <code>true</code>.</li>
+     *  <li><code>includeTransient</code>: If <code>false</code>, 
+     *      exclude Object properties and variables that have 
<code>[Transient]</code> metadata.
+     *      The default value is <code>true</code>.</li>
+     *  <li><code>uris</code>: Array of Strings of all namespaces that should 
be included in the output.
+     *      It does allow for a wildcard of "~~". 
+     *      By default, it is null, meaning no namespaces should be included. 
+     *      For example, you could specify <code>["mx_internal", 
"mx_object"]</code> 
+     *      or <code>["~~"]</code>.</li>
+     *  </ul>
+     * 
+     *  @return An Object containing the following properties:
+     *  <ul>
+     *    <li><code>name</code>: String containing the name of the class.</li>
+     *    <li><code>properties</code>: Sorted list of the property names of 
the specified object,
+     *    or references to the original key if the specified object is a 
Dictionary. The individual
+     *    array elements are QName instances, which contain both the local 
name of the property as well as the URI.</li>
+     *  </ul>
+    *  
+    *  @langversion 3.0
+    *  @playerversion Flash 9
+    *  @playerversion AIR 1.1
+    *  @productversion Flex 3
+    */
+    public static function getClassInfo(obj:Object,
+                                        excludes:Array = null,
+                                        options:Object = null):Object
+    {   
+               if (GOOG::DEBUG)
+                       trace("getClassInfo not implemented");
+               return null;
+    }
+
+    /**
+     * Uses <code>getClassInfo</code> and examines the metadata information to
+     * determine whether a property on a given object has the specified 
+     * metadata.
+     * 
+     * @param obj The object holding the property.
+     * @param propName The property to check for metadata.
+     * @param metadataName The name of the metadata to check on the property.
+     * @param excludes If any properties need to be excluded when generating 
class info. (Optional)
+     * @param options If any options flags need to changed when generating 
class info. (Optional)
+     * @return true if the property has the specified metadata.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static function hasMetadata(obj:Object, 
+                propName:String, 
+                metadataName:String, 
+                excludes:Array = null,
+                options:Object = null):Boolean
+    {
+               if (GOOG::DEBUG)
+                       trace("hasMetadata not implemented");
+               return false;
+//        var classInfo:Object = getClassInfo(obj, excludes, options);
+//        var metadataInfo:Object = classInfo["metadata"];
+//        return internalHasMetadata(metadataInfo, propName, metadataName);
+    }
+
+    /**
+     *  Returns <code>true</code> if the object is an instance of a dynamic 
class.
+     *
+     *  @param object The object.
+     *
+     *  @return <code>true</code> if the object is an instance of a dynamic 
class.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static function isDynamicObject(object:Object):Boolean
+    {
+        try
+        {
+            // this test for checking whether an object is dynamic or not is 
+            // pretty hacky, but it assumes that no-one actually has a 
+            // property defined called "wootHackwoot"
+            object["wootHackwoot"];
+        }
+        catch (e:Error)
+        {
+            // our object isn't an instance of a dynamic class
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     *  Returns all the properties defined dynamically on an object.
+     *
+     *  @param object The object to inspect.
+     *
+     *  @return an <code>Array</code> of the enumerable properties of the 
object.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static function getEnumerableProperties(object:Object):Array
+    {
+        var result:Array = [];
+
+        if(!isDynamicObject(object))
+            return result;
+
+        for (var property:Object in object)
+            result.push(property);
+
+        return result;
+    }
+
+
+    /**
+     *  Verifies if the first object is dynamic and is a subset of the second 
object.
+     *
+     *  @param values The values which need to be shared by <code>object</code>
+     *  @param object The object to verify against.
+     *
+     *  @return true if and only if the objects are the same, or if 
<code>values</code>
+     *  is dynamic and <code>object</code> shares all its properties and 
values.
+     *  (Even if <code>object</code> contains other properties and values, we 
still
+     *  consider it a match).
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static function valuesAreSubsetOfObject(values:Object, 
object:Object):Boolean
+    {
+               if (GOOG::DEBUG)
+                       trace("valuesAresubsetOfObject not implemented");
+               return false;
+//        if(!object && !values)
+//            return true;
+//
+//        if(!object || !values)
+//            return false;
+//
+//        if(object === values)
+//            return true;
+//
+//        var enumerableProperties:Array = 
ObjectUtil.getEnumerableProperties(values);
+//        var matches:Boolean = enumerableProperties.length > 0 || 
ObjectUtil.isDynamicObject(values);
+//
+//        for each(var property:String in enumerableProperties)
+//        {
+//            if (!object.hasOwnProperty(property) || object[property] != 
values[property])
+//            {
+//                matches = false;
+//                break;
+//            }
+//        }
+//
+//        return matches;
+    }
+
+    /**
+     *  Returns the value at the end of the property chain <code>path</code>.
+     *  If the value cannot be reached due to null links on the chain,
+     *  <code>undefined</code> is returned.
+     *
+     *  @param obj The object at the beginning of the property chain
+     *  @param path The path to inspect (e.g. "address.street")
+     *
+     *  @return the value at the end of the property chain, 
<code>undefined</code>
+     *  if it cannot be reached, or the object itself when <code>path</code> 
is empty.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static function getValue(obj:Object, path:Array):*
+    {
+        if(!obj)
+            return undefined;
+
+        if(!path || !path.length)
+            return obj;
+
+        var result:* = obj;
+        var i:int = -1;
+        while(++i < path.length && result)
+            result = result.hasOwnProperty(path[i]) ? result[path[i]] : 
undefined;
+
+        return result;
+    }
+
+
+    /**
+     *  Sets a new value at the end of the property chain <code>path</code>.
+     *  If the value cannot be reached due to null links on the chain,
+     *  <code>false</code> is returned.
+     *
+     *  @param obj The object at the beginning of the property chain
+     *  @param path The path to traverse (e.g. "address.street")
+     *  @param newValue The value to set (e.g. "Fleet Street")
+     *
+     *  @return <code>true</code> if the value is successfully set,
+     *  <code>false</code> otherwise. Note that the function does not
+     *  use a try/catch block. You can implement one in the calling
+     *  function if there's a risk of type mismatch or other errors during
+     *  the assignment.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static function setValue(obj:Object, path:Array, newValue:*):Boolean
+    {
+        if(!obj || !path || !path.length)
+            return false;
+
+        var secondToLastLink:* = getValue(obj, path.slice(0, -1));
+        if(secondToLastLink && 
secondToLastLink.hasOwnProperty(path[path.length - 1]))
+        {
+            secondToLastLink[path[path.length - 1]] = newValue;
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     *  @private
+     */
+    private static function internalHasMetadata(metadataInfo:Object, 
propName:String, metadataName:String):Boolean
+    {
+        if (metadataInfo != null)
+        {
+            var metadata:Object = metadataInfo[propName];
+            if (metadata != null)
+            {
+                if (metadata[metadataName] != null)
+                    return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     *  @private
+     */
+//    private static function recordMetadata(properties:XMLList):Object
+//    {
+//             if (GOOG::DEBUG)
+//                     trace("recordMetadata not implemented");
+//             return null;
+//    }
+
+
+    /**
+     *  @private
+     */
+    private static function getCacheKey(o:Object, excludes:Array = null, 
options:Object = null):String
+    {
+        if (GOOG::DEBUG)
+                       trace("getCacheKey not implemented");
+               return null;
+    }
+
+    /**
+     *  @private
+     */
+    private static function arrayCompare(a:Array, b:Array,
+                                         currentDepth:int, desiredDepth:int,
+                                         /*refs:Dictionary*/ refs:Object):int
+    {
+        var result:int = 0;
+
+        if (a.length != b.length)
+        {
+            if (a.length < b.length)
+                result = -1;
+            else
+                result = 1;
+        }
+        else
+        {
+            var key:Object;
+            for (key in a)
+            {
+                if (b.hasOwnProperty(key))
+                {
+                    result = internalCompare(a[key], b[key], currentDepth,
+                                         desiredDepth, refs);
+
+                    if (result != 0)
+                        return result;
+                }
+                else
+                {
+                    return -1;
+                }
+            }
+
+            for (key in b)
+            {
+                if (!a.hasOwnProperty(key))
+                {
+                    return 1;
+                }
+            }
+        }
+
+        return result;
+    }
+    
+    /**
+     * @private
+     */
+//    private static function byteArrayCompare(a:ByteArray, b:ByteArray):int
+//    {
+//        var result:int = 0;
+//        
+//        if (a == b)
+//            return result;
+//            
+//        if (a.length != b.length)
+//        {
+//            if (a.length < b.length)
+//                result = -1;
+//            else
+//                result = 1;
+//        }
+//        else
+//        {
+//            for (var i:int = 0; i < a.length; i++)
+//            {
+//                result = numericCompare(a[i], b[i]);
+//                if (result != 0)
+//                {
+//                    i = a.length;
+//                }
+//            }
+//        }
+//        return result;
+//    }
+
+    /**
+     *  @private
+     */
+    private static function listCompare(a:IList, b:IList, currentDepth:int, 
+                                        desiredDepth:int, /*refs:Dictionary*/ 
refs:Object):int
+    {
+        var result:int = 0;
+
+        if (a.length != b.length)
+        {
+            if (a.length < b.length)
+                result = -1;
+            else
+                result = 1;
+        }
+        else
+        {
+            for (var i:int = 0; i < a.length; i++)
+            {
+                result = internalCompare(a.getItemAt(i), b.getItemAt(i), 
+                                         currentDepth+1, desiredDepth, refs);
+                if (result != 0)
+                {
+                    i = a.length;
+                }
+            }
+        }
+
+        return result;
+    }
+    
+    /**
+     * @private
+     * This is the "find" for our union-find algorithm when doing object 
searches.
+     * The dictionary keeps track of sets of equal objects
+     */
+    private static function getRef(o:Object, /*refs:Dictionary*/ 
refs:Object):Object
+    {
+        var oRef:Object = refs[o]; 
+        while (oRef && oRef != refs[oRef])
+        {
+            oRef = refs[oRef];
+        }
+        if (!oRef)
+            oRef = o;
+        if (oRef != refs[o])
+            refs[o] = oRef;
+        
+        return oRef;
+    }
+    
+    /**
+     * @private
+     */
+    private static var refCount:int = 0;
+
+    /**
+     * @private
+     */ 
+    private static var CLASS_INFO_CACHE:Object = {};
+}
+
+}

-- 
To stop receiving notification emails like this one, please contact
[email protected].

Reply via email to