You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by ah...@apache.org on 2014/03/12 05:36:36 UTC

[2/7] more legacy classes need to make mustella happy. Some are stripped down to eliminate undesirable dependencies

http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/dec3558f/frameworks/as/projects/MXMLCClasses/src/mx/utils/ObjectUtil.as
----------------------------------------------------------------------
diff --git a/frameworks/as/projects/MXMLCClasses/src/mx/utils/ObjectUtil.as b/frameworks/as/projects/MXMLCClasses/src/mx/utils/ObjectUtil.as
new file mode 100644
index 0000000..bdf69ab
--- /dev/null
+++ b/frameworks/as/projects/MXMLCClasses/src/mx/utils/ObjectUtil.as
@@ -0,0 +1,1424 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 flash.utils.ByteArray;
+import flash.utils.Dictionary;
+import flash.utils.getQualifiedClassName;
+import flash.xml.XMLNode;
+
+/**
+ *  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 null, NaN, or equal. 
+     *  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
+    {
+        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
+    {
+        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
+    {
+        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 (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 type:String = typeof(value);
+        switch (type)
+        {
+            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 obj 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:Dictionary= null, 
+                                             namespaceURIs:Array = null, 
+                                             exclude:Array = null):String
+    {
+        var str:String;
+        var type:String = value == null ? "null" : typeof(value);
+        switch (type)
+        {
+            case "boolean":
+            case "number":
+            {
+                return value.toString();
+            }
+
+            case "string":
+            {
+                return "\"" + value.toString() + "\"";
+            }
+
+            case "object":
+            {
+                if (value is Date)
+                {
+                    return value.toString();
+                }
+                else if (value is XMLNode)
+                {
+                    return value.toString();
+                }
+                else if (value is Class)
+                {
+                    return "(" + getQualifiedClassName(value) + ")";
+                }
+                else
+                {
+                    var classInfo:Object = getClassInfo(value, exclude,
+                        { includeReadOnly: true, uris: namespaceURIs });
+                        
+                    var properties:Array = classInfo.properties;
+                    
+                    str = "(" + classInfo.name + ")";
+                    
+                    // refs help us avoid circular reference infinite recursion.
+                    // Each time an object is encoumtered it is pushed onto the
+                    // refs stack so that we can determine if we have visited
+                    // this object already.
+                    if (refs == null)
+                        refs = new Dictionary(true);
+
+                    // Check to be sure we haven't processed this object before
+                    // Dictionary has some bugs, so we want to work around them as best we can
+                    try
+                    {
+                        var id:Object = refs[value];
+                        if (id != null)
+                        {
+                            str += "#" + int(id);
+                            return str;
+                        }
+                    }
+                    catch (e:Error)
+                    {
+                        //Since we can't test for infinite loop, we simply return toString.
+                        return String(value);
+                    }
+                    
+                    if (value != null)
+                    {
+                        str += "#" + refCount.toString();
+                        refs[value] = refCount;
+                        refCount++;
+                    }
+
+                    var isArray:Boolean = value is Array;
+                    var isDict:Boolean = value is Dictionary;
+                    var prop:*;
+                    indent += 2;
+                    
+                    // Print all of the variable values.
+                    for (var j:int = 0; j < properties.length; j++)
+                    {
+                        str = newline(str, indent);
+                        prop = properties[j];
+                        
+                        if (isArray)
+                            str += "[";
+                        else if (isDict)
+                            str += "{";
+
+                    
+                        if (isDict)
+                        {
+                            // in dictionaries, recurse on the key, because it can be a complex object
+                            str += internalToString(prop, indent, refs,
+                                                    namespaceURIs, exclude);
+                        }
+                        else
+                        {
+                            str += prop.toString();
+                        }
+                        
+                        if (isArray)
+                            str += "] ";
+                        else if (isDict)
+                            str += "} = ";
+                        else
+                            str += " = ";
+                        
+                        try
+                        {
+                            // print the value
+                            str += internalToString(value[prop], indent, refs,
+                                                    namespaceURIs, exclude);
+                        }
+                        catch(e:Error)
+                        {
+                            // value[prop] can cause an RTE
+                            // for certain properties of certain objects.
+                            // For example, accessing the properties
+                            //   actionScriptVersion
+                            //   childAllowsParent
+                            //   frameRate
+                            //   height
+                            //   loader
+                            //   parentAllowsChild
+                            //   sameDomain
+                            //   swfVersion
+                            //   width
+                            // of a Stage's loaderInfo causes
+                            //   Error #2099: The loading object is not
+                            //   sufficiently loaded to provide this information
+                            // In this case, we simply output ? for the value.
+                            str += "?";
+                        }
+                    }
+                    indent -= 2;
+                    return str;
+                }
+                break;
+            }
+
+            case "xml":
+            {
+                return value.toXMLString();
+            }
+
+            default:
+            {
+                return "(" + type + ")";
+            }
+        }
+        
+        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):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 inequal, 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 ByteArray) && (b is ByteArray))
+                    {
+                        result = byteArrayCompare(a as ByteArray, b as ByteArray);
+                    }
+                    else if (getQualifiedClassName(a) == getQualifiedClassName(b))
+                    {
+                        var aProps:Array = getClassInfo(a).properties;
+                        var bProps:Array;
+                        
+                        // if the objects are dynamic they could have different 
+                        // # of properties and should be treated on that basis first
+                        var isDynamicObject:Boolean = isDynamicObject(a);
+                        
+                        // if it's dynamic, check to see that they have all the same properties
+                        if (isDynamicObject)
+                        {
+                            bProps = getClassInfo(b).properties;
+                            result = arrayCompare(aProps, bProps, currentDepth, newDepth, refs);
+                            if (result != 0)
+                                return result;
+                        }
+                        
+                        // now that we know we have the same properties, let's compare the values
+                        var propName:QName;
+                        var aProp:Object;
+                        var bProp:Object;
+                        for (var i:int = 0; i < aProps.length; i++)
+                        {
+                            propName = aProps[i];
+                            aProp = a[propName];
+                            bProp = b[propName];
+                            result = internalCompare(aProp, bProp, currentDepth+1, newDepth, refs);
+                            if (result != 0)
+                            {
+                                return result;
+                            }
+                        }
+                    }
+                    else
+                    {
+                        // We must be inequal, so return 1
+                        return 1;
+                    }
+                    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 exclude 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
+    {   
+        var n:int;
+        var i:int;
+
+        if (obj is ObjectProxy)
+            obj = ObjectProxy(obj).object_proxy::object;
+
+        if (options == null)
+            options = { includeReadOnly: true, uris: null, includeTransient: true };
+
+        var result:Object;
+        var propertyNames:Array = [];
+        var cacheKey:String;
+
+        var className:String;
+        var classAlias:String;
+        var properties:XMLList;
+        var prop:XML;
+        var dynamic:Boolean = false;
+        var metadataInfo:Object;
+
+        if (typeof(obj) == "xml")
+        {
+            className = "XML";
+            properties = obj.text();
+            if (properties.length())
+                propertyNames.push("*");
+            properties = obj.attributes();
+        }
+        else
+        {
+            var classInfo:XML = DescribeTypeCache.describeType(obj).typeDescription;
+            className = classInfo.@name.toString();
+            classAlias = classInfo.@alias.toString();
+            dynamic = (classInfo.@isDynamic.toString() == "true");
+
+            if (options.includeReadOnly)
+                properties = classInfo..accessor.(@access != "writeonly") + classInfo..variable;
+            else
+                properties = classInfo..accessor.(@access == "readwrite") + classInfo..variable;
+
+            var numericIndex:Boolean = false;
+        }
+
+        // If type is not dynamic, check our cache for class info...
+        if (!dynamic)
+        {
+            cacheKey = getCacheKey(obj, excludes, options);
+            result = CLASS_INFO_CACHE[cacheKey];
+            if (result != null)
+                return result;
+        }
+
+        result = {};
+        result["name"] = className;
+        result["alias"] = classAlias;
+        result["properties"] = propertyNames;
+        result["dynamic"] = dynamic;
+        result["metadata"] = metadataInfo = recordMetadata(properties);
+        
+        var excludeObject:Object = {};
+        if (excludes)
+        {
+            n = excludes.length;
+            for (i = 0; i < n; i++)
+            {
+                excludeObject[excludes[i]] = 1;
+            }
+        }
+
+        var isArray:Boolean = (obj is Array);
+        var isDict:Boolean  = (obj is Dictionary);
+        
+        if (isDict)
+        {
+            // dictionaries can have multiple keys of the same type,
+            // (they can index by reference rather than QName, String, or number),
+            // which cannot be looked up by QName, so use references to the actual key
+            for (var key:* in obj)
+            {
+                propertyNames.push(key);
+            }
+        }
+        else if (dynamic)
+        {
+            for (var p:String in obj)
+            {
+                if (excludeObject[p] != 1)
+                {
+                    if (isArray)
+                    {
+                         var pi:Number = parseInt(p);
+                         if (isNaN(pi))
+                            propertyNames.push(new QName("", p));
+                         else
+                            propertyNames.push(pi);
+                    }
+                    else
+                    {
+                        propertyNames.push(new QName("", p));
+                    }
+                }
+            }
+            numericIndex = isArray && !isNaN(Number(p));
+        }
+
+        if (isArray || isDict || className == "Object")
+        {
+            // Do nothing since we've already got the dynamic members
+        }
+        else if (className == "XML")
+        {
+            n = properties.length();
+            for (i = 0; i < n; i++)
+            {
+                p = properties[i].name();
+                if (excludeObject[p] != 1)
+                    propertyNames.push(new QName("", "@" + p));
+            }
+        }
+        else
+        {
+            n = properties.length();
+            var uris:Array = options.uris;
+            var uri:String;
+            var qName:QName;
+            for (i = 0; i < n; i++)
+            {
+                prop = properties[i];
+                p = prop.@name.toString();
+                uri = prop.@uri.toString();
+                
+                if (excludeObject[p] == 1)
+                    continue;
+                    
+                if (!options.includeTransient && internalHasMetadata(metadataInfo, p, "Transient"))
+                    continue;
+                
+                if (uris != null)
+                {
+                    if (uris.length == 1 && uris[0] == "*")
+                    {   
+                        qName = new QName(uri, p);
+                        try
+                        {
+                            obj[qName]; // access the property to ensure it is supported
+                            propertyNames.push();
+                        }
+                        catch(e:Error)
+                        {
+                            // don't keep property name 
+                        }
+                    }
+                    else
+                    {
+                        for (var j:int = 0; j < uris.length; j++)
+                        {
+                            uri = uris[j];
+                            if (prop.@uri.toString() == uri)
+                            {
+                                qName = new QName(uri, p);
+                                try
+                                {
+                                    obj[qName];
+                                    propertyNames.push(qName);
+                                }
+                                catch(e:Error)
+                                {
+                                    // don't keep property name 
+                                }
+                            }
+                        }
+                    }
+                }
+                else if (uri.length == 0)
+                {
+                    qName = new QName(uri, p);
+                    try
+                    {
+                        obj[qName];
+                        propertyNames.push(qName);
+                    }
+                    catch(e:Error)
+                    {
+                        // don't keep property name 
+                    }
+                }
+            }
+        }
+
+        propertyNames.sort(Array.CASEINSENSITIVE |
+                           (numericIndex ? Array.NUMERIC : 0));
+
+        // dictionary keys can be indexed by an object reference
+        // there's a possibility that two keys will have the same toString()
+        // so we don't want to remove dupes
+        if (!isDict)
+        {
+            // for Arrays, etc., on the other hand...
+            // remove any duplicates, i.e. any items that can't be distingushed by toString()
+            for (i = 0; i < propertyNames.length - 1; i++)
+            {
+                // the list is sorted so any duplicates should be adjacent
+                // two properties are only equal if both the uri and local name are identical
+                if (propertyNames[i].toString() == propertyNames[i + 1].toString())
+                {
+                    propertyNames.splice(i, 1);
+                    i--; // back up
+                }
+            }
+        }
+
+        // For normal, non-dynamic classes we cache the class info
+		// Don't cache XML as it can be dynamic
+        if (!dynamic && className != "XML")
+        {
+            cacheKey = getCacheKey(obj, excludes, options);
+            CLASS_INFO_CACHE[cacheKey] = result;
+        }
+
+        return result;
+    }
+
+    /**
+     * 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
+    {
+        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 obj 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(obj: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"
+            obj["wootHackwoot"];
+        }
+        catch (e:Error)
+        {
+            // our object isn't from a dynamic class
+            return false;
+        }
+        return true;
+    }
+    
+    /**
+     *  @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
+    {
+        var result:Object = null;
+
+        try
+        {
+            for each (var prop:XML in properties)
+            {
+                var propName:String = prop.attribute("name").toString();
+                var metadataList:XMLList = prop.metadata;
+
+                if (metadataList.length() > 0)
+                {
+                    if (result == null)
+                        result = {};
+
+                    var metadata:Object = {};
+                    result[propName] = metadata;
+
+                    for each (var md:XML in metadataList)
+                    {
+                        var mdName:String = md.attribute("name").toString();
+                        
+                        var argsList:XMLList = md.arg;
+                        var value:Object = {};
+
+                        for each (var arg:XML in argsList)
+                        {
+                            var argKey:String = arg.attribute("key").toString();
+                            if (argKey != null)
+                            {
+                                var argValue:String = arg.attribute("value").toString();
+                                value[argKey] = argValue;
+                            }
+                        }
+
+                        var existing:Object = metadata[mdName];
+                        if (existing != null)
+                        {
+                            var existingArray:Array;
+                            if (existing is Array)
+                                existingArray = existing as Array;
+                            else
+                            {
+                                existingArray = [existing];
+                                delete metadata[mdName];
+                            }
+                            existingArray.push(value);
+                            existing = existingArray;
+                        }
+                        else
+                        {
+                            existing = value;
+                        }
+                        metadata[mdName] = existing;
+                    }
+                }
+            }
+        }
+        catch(e:Error)
+        {
+        }
+        
+        return result;
+    }
+
+
+    /**
+     *  @private
+     */
+    private static function getCacheKey(o:Object, excludes:Array = null, options:Object = null):String
+    {
+        var key:String = getQualifiedClassName(o);
+		
+        if (excludes != null)
+        {
+			var length:int = excludes.length;
+            for (var i:uint = 0; i < length; i++)
+            {
+                var excl:String = excludes[i] as String;
+                if (excl != null)
+                    key += excl;
+            }
+        }
+
+        if (options != null)
+        {
+            for (var flag:String in options)
+            {
+                key += flag;
+				var value:String = options[flag];
+				if (value != null)
+					key += value.toString();
+			}
+        }
+        return key;
+    }
+
+    /**
+     *  @private
+     */
+    private static function arrayCompare(a:Array, b:Array,
+                                         currentDepth:int, desiredDepth:int,
+                                         refs:Dictionary):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
+     * 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):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 = {};
+}
+
+}

http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/dec3558f/frameworks/as/projects/MXMLCClasses/src/mx/utils/StringUtil.as
----------------------------------------------------------------------
diff --git a/frameworks/as/projects/MXMLCClasses/src/mx/utils/StringUtil.as b/frameworks/as/projects/MXMLCClasses/src/mx/utils/StringUtil.as
new file mode 100644
index 0000000..ee6a6d0
--- /dev/null
+++ b/frameworks/as/projects/MXMLCClasses/src/mx/utils/StringUtil.as
@@ -0,0 +1,364 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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
+{
+
+/**
+ *  The StringUtil utility class is an all-static class with methods for
+ *  working with String objects within Flex.
+ *  You do not create instances of StringUtil;
+ *  instead you call methods such as 
+ *  the <code>StringUtil.substitute()</code> method.  
+ *  
+ *  @langversion 3.0
+ *  @playerversion Flash 9
+ *  @playerversion AIR 1.1
+ *  @productversion Flex 3
+ */
+public class StringUtil
+{
+
+    //--------------------------------------------------------------------------
+    //
+    //  Class methods
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  Removes all whitespace characters from the beginning and end
+     *  of the specified string.
+     *
+     *  @param str The String whose whitespace should be trimmed. 
+     *
+     *  @return Updated String where whitespace was removed from the 
+     *  beginning and end. 
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static function trim(str:String):String
+    {
+        if (str == null) return '';
+        
+        var startIndex:int = 0;
+        while (isWhitespace(str.charAt(startIndex)))
+            ++startIndex;
+
+        var endIndex:int = str.length - 1;
+        while (isWhitespace(str.charAt(endIndex)))
+            --endIndex;
+
+        if (endIndex >= startIndex)
+            return str.slice(startIndex, endIndex + 1);
+        else
+            return "";
+    }
+    
+    /**
+     *  Removes all whitespace characters from the beginning and end
+     *  of each element in an Array, where the Array is stored as a String. 
+     *
+     *  @param value The String whose whitespace should be trimmed. 
+     *
+     *  @param separator The String that delimits each Array element in the string.
+     *
+     *  @return Updated String where whitespace was removed from the 
+     *  beginning and end of each element. 
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static function trimArrayElements(value:String, delimiter:String):String
+    {
+        if (value != "" && value != null)
+        {
+            var items:Array = value.split(delimiter);
+            
+            var len:int = items.length;
+            for (var i:int = 0; i < len; i++)
+            {
+                items[i] = StringUtil.trim(items[i]);
+            }
+            
+            if (len > 0)
+            {
+                value = items.join(delimiter);
+            }
+        }
+        
+        return value;
+    }
+
+    /**
+     *  Returns <code>true</code> if the specified string is
+     *  a single space, tab, carriage return, newline, or formfeed character.
+     *
+     *  @param str The String that is is being queried. 
+     *
+     *  @return <code>true</code> if the specified string is
+     *  a single space, tab, carriage return, newline, or formfeed character.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static function isWhitespace(character:String):Boolean
+    {
+        switch (character)
+        {
+            case " ":
+            case "\t":
+            case "\r":
+            case "\n":
+            case "\f":
+			// non breaking space
+			case "\u00A0":
+			// line seperator
+			case "\u2028":
+			// paragraph seperator
+			case "\u2029":
+			// ideographic space
+			case "\u3000":
+                return true;
+
+            default:
+                return false;
+        }
+    }
+
+    /**
+     *  Substitutes "{n}" tokens within the specified string
+     *  with the respective arguments passed in.
+	 * 
+	 *  Note that this uses String.replace and "$" can have special
+	 *  meaning in the argument strings escape by using "$$".
+     *
+     *  @param str The string to make substitutions in.
+     *  This string can contain special tokens of the form
+     *  <code>{n}</code>, where <code>n</code> is a zero based index,
+     *  that will be replaced with the additional parameters
+     *  found at that index if specified.
+     *
+     *  @param rest Additional parameters that can be substituted
+     *  in the <code>str</code> parameter at each <code>{n}</code>
+     *  location, where <code>n</code> is an integer (zero based)
+     *  index value into the array of values specified.
+     *  If the first parameter is an array this array will be used as
+     *  a parameter list.
+     *  This allows reuse of this routine in other methods that want to
+     *  use the ... rest signature.
+     *  For example <pre>
+     *     public function myTracer(str:String, ... rest):void
+     *     { 
+     *         label.text += StringUtil.substitute(str, rest) + "\n";
+     *     } </pre>
+     *
+     *  @return New string with all of the <code>{n}</code> tokens
+     *  replaced with the respective arguments specified.
+     *
+     *  @example
+     *
+     *  var str:String = "here is some info '{0}' and {1}";
+     *  trace(StringUtil.substitute(str, 15.4, true));
+     *
+     *  // this will output the following string:
+     *  // "here is some info '15.4' and true"
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static function substitute(str:String, ... rest):String
+    {
+        if (str == null) return '';
+        
+        // Replace all of the parameters in the msg string.
+        var len:uint = rest.length;
+        var args:Array;
+        if (len == 1 && rest[0] is Array)
+        {
+            args = rest[0] as Array;
+            len = args.length;
+        }
+        else
+        {
+            args = rest;
+        }
+        
+        for (var i:int = 0; i < len; i++)
+        {
+            str = str.replace(new RegExp("\\{"+i+"\\}", "g"), args[i]);
+        }
+
+        return str;
+    }
+
+    /**
+     *  Returns a string consisting of a specified string
+     *  concatenated with itself a specified number of times.
+     *
+     *  @param str The string to be repeated.
+     *
+     *  @param n The repeat count.
+     *
+     *  @return The repeated string.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 1.5
+     *  @productversion Flex 4.1
+     */
+    public static function repeat(str:String, n:int):String
+    {
+        if (n == 0)
+            return "";
+
+        var s:String = str;
+        for (var i:int = 1; i < n; i++)
+        {
+            s += str;
+        }
+        return s;
+    }
+
+    /**
+     *  Removes "unallowed" characters from a string.
+     *  A "restriction string" such as <code>"A-Z0-9"</code>
+     *  is used to specify which characters are allowed.
+     *  This method uses the same logic as the <code>restrict</code>
+     *  property of TextField.
+     *
+     *  @param str The input string.
+     *
+     *  @param restrict The restriction string.
+     *
+     *  @return The input string, minus any characters
+     *  that are not allowed by the restriction string.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 1.5
+     *  @productversion Flex 4.1
+     */
+    public static function restrict(str:String, restrict:String):String
+    {
+        // A null 'restrict' string means all characters are allowed.
+        if (restrict == null)
+            return str;
+            
+        // An empty 'restrict' string means no characters are allowed.
+        if (restrict == "")
+            return "";
+            
+        // Otherwise, we need to test each character in 'str'
+        // to determine whether the 'restrict' string allows it.
+        var charCodes:Array = [];
+        
+        var n:int = str.length;
+        for (var i:int = 0; i < n; i++)
+        {
+            var charCode:uint = str.charCodeAt(i);
+            if (testCharacter(charCode, restrict))
+                charCodes.push(charCode);
+        }
+        
+        return String.fromCharCode.apply(null, charCodes);
+    }
+                            
+    /**
+     *  @private
+     *  Helper method used by restrict() to test each character
+     *  in the input string against the restriction string.
+     *  The logic in this method implements the same algorithm
+     *  as in TextField's 'restrict' property (which is quirky,
+     *  such as how it handles a '-' at the beginning of the
+     *  restriction string).
+     */
+    private static function testCharacter(charCode:uint,
+                                          restrict:String):Boolean
+    {
+        var allowIt:Boolean = false;
+        
+        var inBackSlash:Boolean = false;
+        var inRange:Boolean = false;
+        var setFlag:Boolean = true;
+        var lastCode:uint = 0;
+                        
+        var n:int = restrict.length;
+        var code:uint;
+        
+        if (n > 0)
+        {
+            code = restrict.charCodeAt(0);
+            if (code == 94) // caret
+                allowIt = true;
+        }
+        
+        for (var i:int = 0; i < n; i++)
+        {
+            code = restrict.charCodeAt(i)
+            
+            var acceptCode:Boolean = false;
+            if (!inBackSlash)
+            {
+                if (code == 45) // hyphen
+                    inRange = true;
+                else if (code == 94) // caret
+                    setFlag = !setFlag;
+                else if (code == 92) // backslash
+                    inBackSlash = true;
+                else
+                    acceptCode = true;
+            }
+            else
+            {
+                acceptCode = true;
+                inBackSlash = false;
+            }
+            
+            if (acceptCode)
+            {
+                if (inRange)
+                {
+                    if (lastCode <= charCode && charCode <= code)
+                        allowIt = setFlag;
+                    inRange = false;
+                    lastCode = 0;
+                }
+                else
+                {
+                    if (charCode == code)
+                        allowIt = setFlag;
+                    lastCode = code;
+                }
+            }
+        }
+        
+        return allowIt;
+    }
+}
+
+}

http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/dec3558f/frameworks/as/projects/MXMLCClasses/src/mx/utils/UIDUtil.as
----------------------------------------------------------------------
diff --git a/frameworks/as/projects/MXMLCClasses/src/mx/utils/UIDUtil.as b/frameworks/as/projects/MXMLCClasses/src/mx/utils/UIDUtil.as
new file mode 100644
index 0000000..f6cf737
--- /dev/null
+++ b/frameworks/as/projects/MXMLCClasses/src/mx/utils/UIDUtil.as
@@ -0,0 +1,296 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 flash.utils.ByteArray;
+import flash.utils.Dictionary;
+
+import mx.core.mx_internal;
+
+use namespace mx_internal;
+
+/**
+ *  The UIDUtil class is an all-static class
+ *  with methods for working with UIDs (unique identifiers) within Flex.
+ *  You do not create instances of UIDUtil;
+ *  instead you simply call static methods such as the
+ *  <code>UIDUtil.createUID()</code> method.
+ * 
+ *  <p><b>Note</b>: If you have a dynamic object that has no [Bindable] properties 
+ *  (which force the object to implement the IUID interface), Flex  adds an 
+ *  <code>mx_internal_uid</code> property that contains a UID to the object. 
+ *  To avoid having this field 
+ *  in your dynamic object, make it [Bindable], implement the IUID interface
+ *  in the object class, or set a <coded>uid</coded> property with a value.</p>
+ *  
+ *  @langversion 3.0
+ *  @playerversion Flash 9
+ *  @playerversion AIR 1.1
+ *  @productversion Flex 3
+ */
+public class UIDUtil
+{
+
+    //--------------------------------------------------------------------------
+    //
+    //  Class constants
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  @private
+     *  Char codes for 0123456789ABCDEF
+     */
+	private static const ALPHA_CHAR_CODES:Array = [48, 49, 50, 51, 52, 53, 54, 
+		55, 56, 57, 65, 66, 67, 68, 69, 70];
+
+    private static const DASH:int = 45;       // dash ascii
+    private static const UIDBuffer:ByteArray = new ByteArray();       // static ByteArray used for UID generation to save memory allocation cost
+
+    //--------------------------------------------------------------------------
+    //
+    //  Class variables
+    //
+    //--------------------------------------------------------------------------
+
+    /** 
+     *  This Dictionary records all generated uids for all existing items.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    private static var uidDictionary:Dictionary = new Dictionary(true);
+
+    //--------------------------------------------------------------------------
+    //
+    //  Class methods
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  Generates a UID (unique identifier) based on ActionScript's
+     *  pseudo-random number generator and the current time.
+     *
+     *  <p>The UID has the form
+     *  <code>"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"</code>
+     *  where X is a hexadecimal digit (0-9, A-F).</p>
+     *
+     *  <p>This UID will not be truly globally unique; but it is the best
+     *  we can do without player support for UID generation.</p>
+     *
+     *  @return The newly-generated UID.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+	public static function createUID():String
+    {
+        UIDBuffer.position = 0;
+
+        var i:int;
+        var j:int;
+
+        for (i = 0; i < 8; i++)
+        {
+            UIDBuffer.writeByte(ALPHA_CHAR_CODES[int(Math.random() * 16)]);
+        }
+
+        for (i = 0; i < 3; i++)
+        {
+            UIDBuffer.writeByte(DASH);
+            for (j = 0; j < 4; j++)
+            {
+                UIDBuffer.writeByte(ALPHA_CHAR_CODES[int(Math.random() * 16)]);
+            }
+        }
+
+        UIDBuffer.writeByte(DASH);
+
+        var time:uint = new Date().getTime(); // extract last 8 digits
+        var timeString:String = time.toString(16).toUpperCase();
+        // 0xFFFFFFFF milliseconds ~= 3 days, so timeString may have between 1 and 8 digits, hence we need to pad with 0s to 8 digits
+        for (i = 8; i > timeString.length; i--)
+            UIDBuffer.writeByte(48);
+        UIDBuffer.writeUTFBytes(timeString);
+
+        for (i = 0; i < 4; i++)
+        {
+            UIDBuffer.writeByte(ALPHA_CHAR_CODES[int(Math.random() * 16)]);
+        }
+
+        return UIDBuffer.toString();
+    }
+
+    /**
+     * Converts a 128-bit UID encoded as a ByteArray to a String representation.
+     * The format matches that generated by createUID. If a suitable ByteArray
+     * is not provided, null is returned.
+     * 
+     * @param ba ByteArray 16 bytes in length representing a 128-bit UID.
+     * 
+     * @return String representation of the UID, or null if an invalid
+     * ByteArray is provided.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static function fromByteArray(ba:ByteArray):String
+    {
+        if (ba != null && ba.length >= 16 && ba.bytesAvailable >= 16)
+        {
+            UIDBuffer.position = 0;
+            var index:uint = 0;
+            for (var i:uint = 0; i < 16; i++)
+            {
+                if (i == 4 || i == 6 || i == 8 || i == 10)
+                    UIDBuffer.writeByte(DASH); // Hyphen char code
+
+                var b:int = ba.readByte();
+                UIDBuffer.writeByte(ALPHA_CHAR_CODES[(b & 0xF0) >>> 4]);
+                UIDBuffer.writeByte(ALPHA_CHAR_CODES[(b & 0x0F)]);
+            }
+            return UIDBuffer.toString();
+        }
+
+        return null;
+    }
+
+    /**
+     * A utility method to check whether a String value represents a 
+     * correctly formatted UID value. UID values are expected to be 
+     * in the format generated by createUID(), implying that only
+     * capitalized A-F characters in addition to 0-9 digits are
+     * supported.
+     * 
+     * @param uid The value to test whether it is formatted as a UID.
+     * 
+     * @return Returns true if the value is formatted as a UID.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static function isUID(uid:String):Boolean
+    {
+        if (uid != null && uid.length == 36)
+        {
+            for (var i:uint = 0; i < 36; i++)
+            {
+                var c:Number = uid.charCodeAt(i);
+
+                // Check for correctly placed hyphens
+                if (i == 8 || i == 13 || i == 18 || i == 23)
+                {
+                    if (c != DASH)
+                    {
+                        return false;
+                    }
+                }
+                // We allow capital alpha-numeric hex digits only
+                else if (c < 48 || c > 70 || (c > 57 && c < 65))
+                {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Converts a UID formatted String to a ByteArray. The UID must be in the
+     * format generated by createUID, otherwise null is returned.
+     * 
+     * @param String representing a 128-bit UID
+     * 
+     * @return ByteArray 16 bytes in length representing the 128-bits of the
+     * UID or null if the uid could not be converted.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static function toByteArray(uid:String):ByteArray
+    {
+        if (isUID(uid))
+        {
+            var result:ByteArray = new ByteArray();
+
+            for (var i:uint = 0; i < uid.length; i++)
+            {
+                var c:String = uid.charAt(i);
+                if (c == "-")
+                    continue;
+                var h1:uint = getDigit(c);
+                i++;
+                var h2:uint = getDigit(uid.charAt(i));
+                result.writeByte(((h1 << 4) | h2) & 0xFF);
+            }
+            result.position = 0;
+            return result;
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns the decimal representation of a hex digit.
+     * @private
+     */
+    private static function getDigit(hex:String):uint
+    {
+        switch (hex) 
+        {
+            case "A": 
+            case "a":           
+                return 10;
+            case "B":
+            case "b":
+                return 11;
+            case "C":
+            case "c":
+                return 12;
+            case "D":
+            case "d":
+                return 13;
+            case "E":
+            case "e":
+                return 14;                
+            case "F":
+            case "f":
+                return 15;
+            default:
+                return new uint(hex);
+        }    
+    }
+}
+
+}

http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/dec3558f/frameworks/as/projects/MXMLCClasses/src/mx/utils/object_proxy.as
----------------------------------------------------------------------
diff --git a/frameworks/as/projects/MXMLCClasses/src/mx/utils/object_proxy.as b/frameworks/as/projects/MXMLCClasses/src/mx/utils/object_proxy.as
new file mode 100644
index 0000000..5aea911
--- /dev/null
+++ b/frameworks/as/projects/MXMLCClasses/src/mx/utils/object_proxy.as
@@ -0,0 +1,34 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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
+{
+
+/**
+ *  Documentation is not currently available.
+ *  
+ *  @langversion 3.0
+ *  @playerversion Flash 9
+ *  @playerversion AIR 1.1
+ *  @productversion Flex 3
+ */
+public namespace object_proxy =
+	"http://www.adobe.com/2006/actionscript/flash/objectproxy";
+
+}