In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

JSON Tests

FlashPlayer v11.0.1.60 (beta) required to run Native JSON tests
Get Adobe Flash player
by skyboy 20 Jul 2011

    Talk

    9re at 20 Jul 2011 06:35
    Escaping unicode characters will be unnecessary in the future. (The JSON specification does not require escaping.) I reported the problem here: http://bugs.adobe.com/jira/browse/FP-7369
    skyboy at 21 Jul 2011 14:33
    It's not required in JSON, but some transport protocols don't permit non-ASCII values. While uncommon, better to have it and not need than need it and not have it. Most text won't have any escaping anyway, and I've reimplemented both parsing and encoding them such that the time taken is trivial since creating this.
    Embed
/**
 * Copyright skyboy ( http://wonderfl.net/user/skyboy )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/zcNl
 */

package {
    import flash.display.*
    import flash.events.*;
    import flash.geom.*
    import flash.globalization.*;
    import flash.media.*;
    import flash.net.*;
    import flash.system.*;
    import flash.text.*;
    import flash.utils.*;
    [SWF(width='465', height='465', backgroundColor='#333333', frameRate='60')]
    public class FlashTest extends Sprite {
        public static const WIDTH:Number = 465;
        public static const HEIGHT:Number = 465;
        public static const hw:Number = WIDTH / 2;
        public static const hy:Number = HEIGHT / 2;
        private var logger:TextField;

        public function FlashTest() {
            graphics.beginFill(0xEEEEEE);
            graphics.drawRoundRect(0, 0, WIDTH, HEIGHT, 30);
            graphics.endFill();
            logger = new TextField();
            logger.autoSize = TextFieldAutoSize.LEFT;
            logger.defaultTextFormat = new TextFormat("Monaco");
            addChild(logger);
            var b:Sprite = new Sprite;
            var c:Graphics = b.graphics;
            c.beginFill(0x666666);
            c.drawRoundRect(0, 0, 100, 50, 30);
            c.endFill();
            (b.addChild(new TextField) as TextField).appendText("Save");
            var a:SimpleButton = new SimpleButton(b, b, b, b);
            addChild(a).x = WIDTH - 100;
            a.y = HEIGHT - 50;
            a.addEventListener(MouseEvent.CLICK, saveFile);
            Wonderfl.disable_capture();
            if (stage) onAS(null); else addEventListener(Event.ADDED_TO_STAGE, onAS);
        }
        private function onAS(evt:Event):void {
            removeEventListener(Event.ADDED_TO_STAGE, onAS);
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP;
            log("                                     Click to test.");
            addEventListener(MouseEvent.CLICK, onCC);
        }
        
        private function onCC(e:MouseEvent):void {
            if (json) {
                setVersionString();
                log("\nParsing...");
                log("JSON Length:", numberDelimiter2(json.length, ",", 3, 0), '\n');
                jsonobj = skyJSON.decode(json);
                var a:* = jsonobj;
                var Ado:String = json;
                if (this.JSON) Ado = this.JSON.stringify(a); 
                json = Ado;
                start = getTimer();
                addEventListener(Event.ENTER_FRAME, skyboy_AS3JSON);
            } else {
                var b:URLRequest = new URLRequest("http://api.kongregate.com/badges.json?");
                var c:URLLoader = new URLLoader();
                c.addEventListener(SecurityErrorEvent.SECURITY_ERROR, trace);
                c.addEventListener(IOErrorEvent.IO_ERROR, trace);
                c.addEventListener(Event.COMPLETE, loadUserComplete);
                c.addEventListener(ProgressEvent.PROGRESS, onProgress);
                c.load(b);
                setVersionString();
                log("\nLoading... http://api.kongregate.com/badges.json\n");
                try{this.JSON = getDefinitionByName("JSON");}catch(e:*){}
            }
        }
        private var json:String, JSON:Object;
        private var start:int, inputName:String, jsonobj:*;
        private function skyboy_AS3JSON(e:Event):void {
            removeEventListener(e.type, skyboy_AS3JSON);
            addEventListener(e.type, Adobe_nativeJSON);
            var q:int, a:String = json;
            try {
                log("skyboy (AS3) \t", ((q = getTimer()), skyJSON.decode(a), getTimer() - q));
                log("skyboy (AS3) \t", ((q = getTimer()), skyJSON.decode(a), getTimer() - q));
                log("skyboy (AS3) \t", ((q = getTimer()), skyJSON.decode(a), getTimer() - q));
                log("skyboy (AS3) \t", ((q = getTimer()), skyJSON.decode(a), getTimer() - q));
                log("skyboy (AS3) \t", ((q = getTimer()), skyJSON.decode(a), getTimer() - q), '\n');
            } catch (e:Error) {
                log("skyboy (AS3) \t", e.name + "(" + e.errorID + "):", e.message, '\n'); 
            }
        }
        private function Adobe_nativeJSON(e:Event):void {
            removeEventListener(e.type, Adobe_nativeJSON);
            //addEventListener(e.type, blooddycryptoJSON);
            addEventListener(e.type, JSONParsersEnd);
            var q:int, a:String = json, i:int;
            try {
                var JSON:Object = getDefinitionByName("JSON");
                log("Adobe Native JSON \t", ((q = getTimer()), JSON.parse(a), getTimer() - q));++i
                log("Adobe Native JSON \t", ((q = getTimer()), JSON.parse(a), getTimer() - q));++i
                log("Adobe Native JSON \t", ((q = getTimer()), JSON.parse(a), getTimer() - q));++i
                log("Adobe Native JSON \t", ((q = getTimer()), JSON.parse(a), getTimer() - q));++i
                log("Adobe Native JSON \t", ((q = getTimer()), JSON.parse(a), getTimer() - q), '\n');
            } catch (e:Error) {
                log("Adobe Native JSON \t", e.name + "(" + e.errorID + "):", e.message);
                while (++i < 5) log("Adobe Native JSON \t", 0);
                log('');
            }
        }/*
        private function blooddycryptoJSON(e:Event):void {
            removeEventListener(e.type, blooddycryptoJSON);
            addEventListener(e.type, brokenfunctionJSON);
            var q:int, a:String = json;
            try {
                log("blooddy.crypto \t", ((q = getTimer()), by.blooddy.crypto.serialization.JSON.decode(a), getTimer() - q));
                log("blooddy.crypto \t", ((q = getTimer()), by.blooddy.crypto.serialization.JSON.decode(a), getTimer() - q));
                log("blooddy.crypto \t", ((q = getTimer()), by.blooddy.crypto.serialization.JSON.decode(a), getTimer() - q));
                log("blooddy.crypto \t", ((q = getTimer()), by.blooddy.crypto.serialization.JSON.decode(a), getTimer() - q));
                log("blooddy.crypto \t", ((q = getTimer()), by.blooddy.crypto.serialization.JSON.decode(a), getTimer() - q), '\n');
            } catch (e:Error) {
                log("blooddy.crypto \t", e.name + "(" + e.errorID + "):", e.message, '\n');
            }
        }
        private function brokenfunctionJSON(e:Event):void {
            removeEventListener(e.type, brokenfunctionJSON);
            addEventListener(e.type, vegasSerializerJSON);
            var q:int, a:String = json;
            try {
                log("actionJson \t", ((q = getTimer()), com.brokenfunction.json.decodeJson(a), getTimer() - q));
                log("actionJson \t", ((q = getTimer()), com.brokenfunction.json.decodeJson(a), getTimer() - q));
                log("actionJson \t", ((q = getTimer()), com.brokenfunction.json.decodeJson(a), getTimer() - q));
                log("actionJson \t", ((q = getTimer()), com.brokenfunction.json.decodeJson(a), getTimer() - q));
                log("actionJson \t", ((q = getTimer()), com.brokenfunction.json.decodeJson(a), getTimer() - q), '\n');
            } catch (e:Error) {
                log("actionJson \t", e.name + "(" + e.errorID + "):", e.message, '\n');
            }
        }
        private function vegasSerializerJSON(e:Event):void {
            removeEventListener(e.type, vegasSerializerJSON);
            addEventListener(e.type, comserializationJSON);
            var q:int, a:String = json;
            try {
                var J:JSONSerializer = new JSONSerializer();
                log("vegas \t", ((q = getTimer()), J.deserialize(a), getTimer() - q));
                log("vegas \t", ((q = getTimer()), J.deserialize(a), getTimer() - q));
                log("vegas \t", ((q = getTimer()), J.deserialize(a), getTimer() - q));
                log("vegas \t", ((q = getTimer()), J.deserialize(a), getTimer() - q));
                log("vegas \t", ((q = getTimer()), J.deserialize(a), getTimer() - q), '\n');
            } catch (e:Error) {
                log("vegas \t", e.name + "(" + e.errorID + "):", e.message, '\n');
            }
        }
        private function comserializationJSON(e:Event):void {
            removeEventListener(e.type, comserializationJSON);
            addEventListener(e.type, AdobeActionScriptJSON);
            var q:int, a:String = json;
            try {
                log("ekameleon JSON \t", ((q = getTimer()), com.serialization.json.JSON.deserialize(a), getTimer() - q));
                log("ekameleon JSON \t", ((q = getTimer()), com.serialization.json.JSON.deserialize(a), getTimer() - q));
                log("ekameleon JSON \t", ((q = getTimer()), com.serialization.json.JSON.deserialize(a), getTimer() - q));
                log("ekameleon JSON \t", ((q = getTimer()), com.serialization.json.JSON.deserialize(a), getTimer() - q));
                log("ekameleon JSON \t", ((q = getTimer()), com.serialization.json.JSON.deserialize(a), getTimer() - q), '\n');
            } catch (e:Error) {
                log("ekameleon JSON \t", e.name + "(" + e.errorID + "):", e.message, '\n');
            }
        }
        private function AdobeActionScriptJSON(e:Event):void {
            removeEventListener(e.type, AdobeActionScriptJSON);
            addEventListener(e.type, JSONParsersEnd);
            var q:int, a:String = json;
            try {
                log("as3corelib \t", ((q = getTimer()), com.adobe.serialization.json.JSON.decode(a), getTimer() - q));
                log("as3corelib \t", ((q = getTimer()), com.adobe.serialization.json.JSON.decode(a), getTimer() - q));
                log("as3corelib \t", ((q = getTimer()), com.adobe.serialization.json.JSON.decode(a), getTimer() - q));
                log("as3corelib \t", ((q = getTimer()), com.adobe.serialization.json.JSON.decode(a), getTimer() - q));
                log("as3corelib \t", ((q = getTimer()), com.adobe.serialization.json.JSON.decode(a), getTimer() - q), '\n');
            } catch (e:Error) {
                log("as3corelib \t", e.name + "(" + e.errorID + "):", e.message, '\n');
            }
        }//*/
        private function skyboy_AS3JSON2(e:Event):void {
            removeEventListener(e.type, skyboy_AS3JSON2);
            addEventListener(e.type, Adobe_nativeJSON2);
            var q:int, a:* = jsonobj;
            try {
                log("skyboy (AS3) \t", ((q = getTimer()), skyJSON.encode(a), getTimer() - q));
                log("skyboy (AS3) \t", ((q = getTimer()), skyJSON.encode(a), getTimer() - q));
                log("skyboy (AS3) \t", ((q = getTimer()), skyJSON.encode(a), getTimer() - q));
                log("skyboy (AS3) \t", ((q = getTimer()), skyJSON.encode(a), getTimer() - q));
                log("skyboy (AS3) \t", ((q = getTimer()), skyJSON.encode(a), getTimer() - q), '\n');
            } catch (e:Error) {
                log("skyboy (AS3) \t", e.name + "(" + e.errorID + "):", e.message, '\n');
            }
        }
        private function Adobe_nativeJSON2(e:Event):void {
            removeEventListener(e.type, Adobe_nativeJSON2);
            //addEventListener(e.type, blooddycryptoJSON2);
            addEventListener(e.type, JSONParsersEnd2);
            var q:int, a:* = jsonobj, i:int;
            try {
                var JSON:Object = getDefinitionByName("JSON");
                log("Adobe Native JSON \t", ((q = getTimer()), JSON.stringify(a), getTimer() - q));++i
                log("Adobe Native JSON \t", ((q = getTimer()), JSON.stringify(a), getTimer() - q));++i
                log("Adobe Native JSON \t", ((q = getTimer()), JSON.stringify(a), getTimer() - q));++i
                log("Adobe Native JSON \t", ((q = getTimer()), JSON.stringify(a), getTimer() - q));++i
                log("Adobe Native JSON \t", ((q = getTimer()), JSON.stringify(a), getTimer() - q), '\n');
            } catch (e:Error) {
                log("Adobe Native JSON \t", e.name + "(" + e.errorID + "):", e.message);
                while (++i < 5) log("Adobe Native JSON \t", 0);
                log('');
            }
        }/*
        private function blooddycryptoJSON2(e:Event):void {
            removeEventListener(e.type, blooddycryptoJSON2);
            addEventListener(e.type, brokenfunctionJSON2);
            var q:int, a:* = jsonobj;
            try {
                log("blooddy.crypto \t", ((q = getTimer()), by.blooddy.crypto.serialization.JSON.encode(a), getTimer() - q));
                log("blooddy.crypto \t", ((q = getTimer()), by.blooddy.crypto.serialization.JSON.encode(a), getTimer() - q));
                log("blooddy.crypto \t", ((q = getTimer()), by.blooddy.crypto.serialization.JSON.encode(a), getTimer() - q));
                log("blooddy.crypto \t", ((q = getTimer()), by.blooddy.crypto.serialization.JSON.encode(a), getTimer() - q));
                log("blooddy.crypto \t", ((q = getTimer()), by.blooddy.crypto.serialization.JSON.encode(a), getTimer() - q), '\n');
            } catch (e:Error) {
                log("blooddy.crypto \t", e.name + "(" + e.errorID + "):", e.message, '\n');
            }
        }
        private function brokenfunctionJSON2(e:Event):void {
            removeEventListener(e.type, brokenfunctionJSON2);
            addEventListener(e.type, vegasSerializerJSON2);
            var q:int, a:* = jsonobj;
            try {
                log("actionJson \t", ((q = getTimer()), com.brokenfunction.json.encodeJson(a), getTimer() - q));
                log("actionJson \t", ((q = getTimer()), com.brokenfunction.json.encodeJson(a), getTimer() - q));
                log("actionJson \t", ((q = getTimer()), com.brokenfunction.json.encodeJson(a), getTimer() - q));
                log("actionJson \t", ((q = getTimer()), com.brokenfunction.json.encodeJson(a), getTimer() - q));
                log("actionJson \t", ((q = getTimer()), com.brokenfunction.json.encodeJson(a), getTimer() - q), '\n');
            } catch (e:Error) {
                log("actionJson \t", e.name + "(" + e.errorID + "):", e.message, '\n');
            }
        }
        private function vegasSerializerJSON2(e:Event):void {
            removeEventListener(e.type, vegasSerializerJSON2);
            addEventListener(e.type, comserializationJSON2);
            var q:int, a:* = jsonobj;
            try {
                var J:JSONSerializer = new JSONSerializer();
                log("vegas \t", ((q = getTimer()), J.serialize(a), getTimer() - q));
                log("vegas \t", ((q = getTimer()), J.serialize(a), getTimer() - q));
                log("vegas \t", ((q = getTimer()), J.serialize(a), getTimer() - q));
                log("vegas \t", ((q = getTimer()), J.serialize(a), getTimer() - q));
                log("vegas \t", ((q = getTimer()), J.serialize(a), getTimer() - q), '\n');
            } catch (e:Error) {
                log("vegas \r", e.name + "(" + e.errorID + "):", e.message, '\n');
            }
        }
        private function comserializationJSON2(e:Event):void {
            removeEventListener(e.type, comserializationJSON2);
            addEventListener(e.type, AdobeActionScriptJSON2);
            var q:int, a:* = jsonobj;
            try {
                log("ekameleon JSON \t", ((q = getTimer()), com.serialization.json.JSON.serialize(a), getTimer() - q));
                log("ekameleon JSON \t", ((q = getTimer()), com.serialization.json.JSON.serialize(a), getTimer() - q));
                log("ekameleon JSON \t", ((q = getTimer()), com.serialization.json.JSON.serialize(a), getTimer() - q));
                log("ekameleon JSON \t", ((q = getTimer()), com.serialization.json.JSON.serialize(a), getTimer() - q));
                log("ekameleon JSON \t", ((q = getTimer()), com.serialization.json.JSON.serialize(a), getTimer() - q), '\n');
            } catch (e:Error) {
                log("ekameleon JSON \t", e.name + "(" + e.errorID + "):", e.message, '\n');
            }
        }
        private function AdobeActionScriptJSON2(e:Event):void {
            removeEventListener(e.type, AdobeActionScriptJSON2);
            addEventListener(e.type, JSONParsersEnd2);
            var q:int, a:* = jsonobj;
            try {
                log("as3corelib \t", ((q = getTimer()), com.adobe.serialization.json.JSON.encode(a), getTimer() - q));
                log("as3corelib \t", ((q = getTimer()), com.adobe.serialization.json.JSON.encode(a), getTimer() - q));
                log("as3corelib \t", ((q = getTimer()), com.adobe.serialization.json.JSON.encode(a), getTimer() - q));
                log("as3corelib \t", ((q = getTimer()), com.adobe.serialization.json.JSON.encode(a), getTimer() - q));
                log("as3corelib \t", ((q = getTimer()), com.adobe.serialization.json.JSON.encode(a), getTimer() - q), '\n');
            } catch (e:Error) {
                log("as3corelib \t", e.name + "(" + e.errorID + "):", e.message, '\n');
            }
        }//*/
        private function JSONParsersEnd(e:Event):void {
            removeEventListener(e.type, JSONParsersEnd);
            addEventListener(e.type, skyboy_AS3JSON2);
            log("\nEncoding...");
        }
        private function JSONParsersEnd2(e:Event):void {
            removeEventListener(e.type, JSONParsersEnd2);
            log("\nTotal time:", getTimer() - start);
            log("Input:", inputName);
            Wonderfl.capture(stage);
        }
        private function loadUserComplete(e:Event):void {
            var a:String = String(e.target.data).valueOf();
            /*
            json = a;
            inputName = "Kongregate badge list";
            //*/
            //*
            json = "[" + a + "," + a + "," + a + "," + a + "," + a + "," + a + "," + a + "," + a + "," + a + "," + a + "]";
            inputName = "Kongregate badge list Array (x10)";
            //*/
            /*
            a = "[" + a + "," + a + "," + a + "," + a + "," + a + "," + a + "," + a + "," + a + "," + a + "," + a + "]";
            json = "{'listA1':" + a + ", 'lsatA2':" + a + "}";
            inputName = "Kongregate badge list Array Object (listx10 Arrayx2)";
            //*/
            /*
            json = "[" + a + "," + a + "]";
            inputName = "Kongregate badge list Array (x2)";
            //*/
            setTimeout(function():void{onCC(null)}, 4000)
        }
        private var b:int
        private function onProgress(e:ProgressEvent):void {
            var a:Number = (e.bytesLoaded / e.bytesTotal);
            if (int(a * 10) != b) {
                b = a * 10;
                log(int(a*100) + "% loaded...");
            }
        }
        private function log(...args):void {
            logger.appendText(args.join(" ") + "\n");
            logger.scrollV = logger.numLines;
        }
        private function setVersionString():void {
            logger.text = "  ";
            logger.appendText((Capabilities.supports64BitProcesses ? "64" : Capabilities.supports32BitProcesses ? "32" : "16") + " bit ");
            logger.appendText(Capabilities.os + " ");
            logger.appendText(Capabilities.cpuArchitecture + " ");
            logger.appendText(Capabilities.version.split(",").join(".").split(" ")[1] + " ");
            logger.appendText(Capabilities.isDebugger ? "Debug " : "Release ");
            logger.appendText(Capabilities.playerType);
            logger.appendText("\n");
        }
        
        private function dup(a:String, b:int):String {
            var r:String = "";
            while (b--) {
                r += a;
            }
            return r;
        }

        private var bytes:ByteArray;
        private const file:FileReference = new FileReference();
        
        private function saveFile(e:MouseEvent):void {
            try {
                var a:String;
                try {
                    a = file.name;
                } catch (b:*) {
                    a = "file.swf";
                }
                bytes = loaderInfo.bytes;
                file.save(bytes, a);
            } catch (er:Error) {
                //log(e)
            }
            e.stopImmediatePropagation();
            e.stopPropagation();
            e.preventDefault();
        }
public function numberDelimiter2(num:Number, delimiter:String = ",", charGroup:uint = 3, decimalPrecision:int = 2):String {
    var d:String = num.toFixed(decimalPrecision);
    if (int(charGroup == 0) | charGroup >> 31) return d;
    var n:int = int(num < 0), len:int = d.length - n - (int(decimalPrecision > 0) * (decimalPrecision + 1));;
    if (len <= charGroup) return d;
    if (len % charGroup) {
        var c:int = n + len % charGroup, o:String = d.substring(0, c);
        while (~(((len -= charGroup) >> 31))) {
            o = o + delimiter + d.substring(c, c += charGroup);
        }
        return o + d.substring(c);
    }
    var count:int = n + charGroup, out:String = d.substring(0, count);
    while (len -= charGroup) {
        out = out + delimiter + d.substring(count, count += charGroup);
    }
    return out + d.substring(count);
}
    }
}
// original can be found here: https://github.com/skyboy/AS3-Utilities/blob/master/skyboy/serialization/JSON.as
import flash.utils.ByteArray;
    import flash.utils.getQualifiedClassName;
    import flash.utils.Dictionary;
class skyJSON {
        public function skyJSON() {
            throw new Error("This class has no instance methods.")
        }
        private static const preArrs:Vector.<Array> = new Vector.<Array>();
        private static const preObjs:Vector.<Object> = new Vector.<Object>();
        private static const strArr:ByteArray = new ByteArray(); strArr.length = 0xFFFF;
        private static const strArrE:ByteArray = new ByteArray(); strArrE.length = 0xFFFF;
        private static var i:int;
        
        public static const errorID:int = 0x4A534F4E;
        
        public static function decode(data:String):* {
            if (data == null) {
                return null;
            }
            data = data.valueOf();
            var e:int = data.length;
            if (e == 0) return null;
            var temp:int, objs:int = -preObjs.length;
            while ((temp = data.indexOf("}", temp + 1)) !== -1) ++objs;
            if (objs > 0) {
                preObjs.length = objs;
                while (objs-- > 0) preObjs[objs] = new Object;
            }
            objs = temp = 0;
            while ((temp = data.indexOf("]", temp + 1)) !== -1) ++objs;
            preArrs.length = objs;
            while (objs-- > 0) preArrs[objs] = new Array(e);
            var c:int = data.charCodeAt(i = 0);
            if (isSpace(c)) {
                do {
                    c = data.charCodeAt(++i);
                } while (isSpace(c) && i != e);
            }
            var rtn:*;
            if (isObject(c)) {
                rtn = handleObject(data, e);
            } else if (isArray(c)) {
                rtn = handleArray(data, e);
            } else if (isString(c)) {
                rtn = handleString(data, e);
            } else if (isNumber(c)) {
                rtn = handleNumber2(data, e);
            } else if (isLit(c)) {
                return handleLit(data, e);
            }
            if (rtn === undefined) error(data, i);
            return rtn;
        }
        public static function parse(data:String):* {
            return decode(data);
        }
        public static function get index():int {
            return i;
        }
        
        
        private static function tryToJSON(data:*):String {
            try {
                return data.toJSON() as String;
            } catch (e:ArgumentError) {
                if (e.errorID != 1063) throw e;
            }
            return null;
        }
        private static function encode2(data:*):void {
            var ret:ByteArray = strArrE, c:String;
            if (data == null) {
                ret.writeUTFBytes("null");
                return;
            }
            if ("toJSON" in data) if (data.toJSON is Function) {
                c = tryToJSON(data);
                if (c != null) {
                    handleStringE2(c, ret);
                    return;
                }
            }
            if (data is Function) ret.writeUTFBytes("null");
            else if (data is String) {
                handleStringE2(data, ret, false);
            } else if (data is Number) {
                if ((data * 0) != 0) data = 0;
                ret.writeUTFBytes(String(data));
            } else if (data is Boolean) {
                ret.writeUTFBytes(String(data));
            } else if (data is Date) {
                ret.writeUTFBytes(String(data.getTime()));
            } else if (data is Array || getQualifiedClassName(data).indexOf("__AS3__.vec::Vector.<") == 0) {
                var i:int, e:int = data.length - 1;
                ret.writeByte(0x5B); // [
                if (e > 0) {
                    if (e & 1) encode2(data[i++]), ret.writeByte(0x2C); // ,
                    e >>>= 1;
                    while (e--) {
                        encode2(data[i++]);
                        ret.writeByte(0x2C); // ,
                        encode2(data[i++]);
                        ret.writeByte(0x2C); // ,
                    }
                    encode2(data[i]);
                } else if (!e) {
                    encode2(data[i]);
                }
                ret.writeByte(0x5D); // ]
            } else if (data is Dictionary) {
                ret.writeByte(0x7B); // {
                for (var b:* in data) {
                    if (b is String) handleStringE2(b, ret), encode2(data[b]), ret.writeByte(0x2C);
                    else if (b is Number) handleStringE2(String(b), ret), encode2(data[b]), ret.writeByte(0x2C);
                    else if (b is Date) handleStringE2(String(b.getTime()), ret), encode2(data[b]), ret.writeByte(0x2C);
                    else if (b is XML) handleStringE2(b.toXMLString(), ret), encode2(data[b]), ret.writeByte(0x2C);
                    else if (b is Boolean) handleStringE2(String(b), ret), encode2(data[b]), ret.writeByte(0x2C);
                }
                if (b !== undefined) ret.position--;
                ret.writeByte(0x7D); // }
            } else if (data is XML) {
                handleStringE2(data.toXMLString(), ret, false);
            } else if (data is Object) {
                ret.writeByte(0x7B); // {
                for (c in data) {
                    handleStringE2(c, ret), encode2(data[c]), ret.writeByte(0x2C);
                }
                if (c != null) ret.position--;
                ret.writeByte(0x7D); // }
            } else ret.writeUTFBytes("null");
        }
        public static function encode(data:*):String {
            if (data == null) return "null";
            var ret:ByteArray = strArrE, c:String;
            ret.position = 0;
            if ("toJSON" in data) if (data.toJSON is Function) {
                c = tryToJSON(data);
                if (c != null) return handleStringE(c, false);
            }
            if (data is Function) return "null";
            if (data is String) {
                handleStringE2(data, ret, false);
            } else if (data is Number) {
                if ((data * 0) != 0) data = 0;
                ret.writeUTFBytes(String(data));
            } else if (data is Boolean) {
                ret.writeUTFBytes(String(data));
            } else if (data is Date) {
                ret.writeUTFBytes(String(data.getTime()));
            } else if (data is Array || getQualifiedClassName(data).indexOf("__AS3__.vec::Vector.<") == 0) {
                var i:int, e:int = data.length - 1;
                ret.writeByte(0x5B); // [
                if (e > 0) {
                    if (e & 1) encode2(data[i++]), ret.writeByte(0x2C); // ,
                    e >>>= 1;
                    while (e--) {
                        encode2(data[i++]);
                        ret.writeByte(0x2C); // ,
                        encode2(data[i++]);
                        ret.writeByte(0x2C); // ,
                    }
                    encode2(data[i]);
                } else if (!e) {
                    encode2(data[i]);
                }
                ret.writeByte(0x5D); // ]
            } else if (data is Dictionary) {
                ret.writeByte(0x7B); // {
                for (var b:* in data) {
                    if (b is String) handleStringE2(b, ret), encode2(data[b]), ret.writeByte(0x2C);
                    else if (b is Number) handleStringE2(String(b), ret), encode2(data[b]), ret.writeByte(0x2C);
                    else if (b is Date) handleStringE2(String(b.getTime()), ret), encode2(data[b]), ret.writeByte(0x2C);
                    else if (b is XML) handleStringE2(b.toXMLString(), ret), encode2(data[b]), ret.writeByte(0x2C);
                    else if (b is Boolean) handleStringE2(String(b), ret), encode2(data[b]), ret.writeByte(0x2C);
                }
                if (b !== undefined) ret.position--;
                ret.writeByte(0x7D); // }
            } else if (data is XML) {
                handleStringE2(data.toXMLString(), ret, false);
            } else if (data is Object) {
                ret.writeByte(0x7B); // {
                for (c in data) {
                    handleStringE2(c, ret), encode2(data[c]), ret.writeByte(0x2C);
                }
                if (c != null) ret.position--;
                ret.writeByte(0x7D); // }
            } else return "null";
            i = ret.position;
            ret.position = 0;
            c = ret.readUTFBytes(i);
            ret.length = 0;
            return c;
        }
        public static function stringify(data:*):String {
            return encode(data);
        }
        public static function toJSON(data:* = null):String {
            return encode(data);
        }
        
        private static function isSpace(i:int):Boolean {
            return Boolean(int(i == 0x20) | int(i == 0x09));
        }
        private static function isString(i:int):Boolean {
            return Boolean(int(i == 0x22) | int(i == 0x27));
        }
        private static function isObject(i:int):Boolean {
            return i == 0x7B;
        }
        private static function isArray(i:int):Boolean {
            return i == 0x5B;
        }
        private static function isNumber(i:int):Boolean {
            return Boolean(int(i == 0x2D) | int(i == 0x2E) | (int(i > 0x2F) & int(i < 0x3A)) | int(i == 0x2B));
        }
        private static function isNumeric(i:int):Boolean {
            return Boolean(int(i > 0x2F) & int(i < 0x3A));
        }
        private static function isLit(i:int):Boolean {
            i |= 0x20;
            return Boolean(int(i == 0x74) | int(i == 0x66) | int(i == 0x6E));
        }
        
        private static function min(a:Number, b:Number):Number {
            var c:int = int(a < b);
            return (c * a) + ((1 - c) * b); // fast a < b ? a : b;
        }
        private static function handleStringE(data:String, colon:Boolean = true):String {
            var rtn:ByteArray = strArr, inx:int, c:int, i:int;
            var e:int = data.length, t:int;
            if (e == 0) return "";
            rtn.length = min(e * 5 + 3, 0xFFFFFF);
            rtn[inx++] = 0x22;
            while (i != e) {
                c = data.charCodeAt(i++);
                if (int(c < 32) | int(c > 127)) {
                    if (c > 0xFFFF) c = 0xFFFF;
                    rtn[inx++] = 0x5C;
                    rtn[inx++] = 0x75;
                    t = ((c & 0xF000) >> 12) + 0x30;
                    t += 7 * int(t > 0x39);
                    rtn[inx++] = t;
                    t = ((c & 0xF00) >> 8) + 0x30;
                    t += 7 * int(t > 0x39);
                    rtn[inx++] = t;
                    t = ((c & 0xF0) >> 4) + 0x30;
                    t += 7 * int(t > 0x39);
                    rtn[inx++] = t;
                    t = (c & 15) + 0x30;
                    t += 7 * int(t > 0x39);
                    rtn[inx++] = t;
                    continue;
                } else if (int(c == 0x22) | int(c == 0x5C)) {
                    rtn[inx++] = 0x5C;
                    rtn[inx++] = c;
                    continue;
                }
                rtn[inx++] = c;
            }
            rtn[inx++] = 0x22;
            if (colon) rtn[inx++] = 0x3A;
            rtn.position = 0;
            data = rtn.readUTFBytes(inx);
            return data;
        }
        private static function handleStringE2(data:String, rtn:ByteArray, colon:Boolean = true):void {
            if (!rtn) return;
            var inx:int = rtn.position, c:int, i:int;
            var e:int = data.length, t:int;
            if (e == 0) return;
            rtn.length = inx + min(e * 5 + 3, 0xFFFFFF);
            rtn[inx++] = 0x22;
            while (i != e) {
                c = data.charCodeAt(i++);
                if (int(c < 32) | int(c > 127)) {
                    if (c > 0xFFFF) c = 0xFFFF;
                    rtn[inx++] = 0x5C;
                    rtn[inx++] = 0x75;
                    t = ((c & 0xF000) >> 12) + 0x30;
                    t += 7 * int(t > 0x39);
                    rtn[inx++] = t;
                    t = ((c & 0xF00) >> 8) + 0x30;
                    t += 7 * int(t > 0x39);
                    rtn[inx++] = t;
                    t = ((c & 0xF0) >> 4) + 0x30;
                    t += 7 * int(t > 0x39);
                    rtn[inx++] = t;
                    t = (c & 15) + 0x30;
                    t += 7 * int(t > 0x39);
                    rtn[inx++] = t;
                    continue;
                } else if (int(c == 0x22) | int(c == 0x5C)) {
                    rtn[inx++] = 0x5C;
                    rtn[inx++] = c;
                    continue;
                }
                rtn[inx++] = c;
            }
            rtn[inx++] = 0x22;
            if (colon) rtn[inx++] = 0x3A;
            rtn.position = inx;
        }
        private static function handleString(data:String, e:int):String {
            var rtn:ByteArray = strArr, inx:int, t:int, a:int = i;
            var iN:Boolean, c:int, end:int = data.charCodeAt(i), p:int;
            rtn.length = e;
            while (a != e) {
                c = data.charCodeAt(++a);
                if (c == 0x5C) {
                    c = data.charCodeAt(++a);
                    t = 0;
                    switch (c) {
                    case 0x72:
                        c = 13;
                        break;
                    case 0x6E:
                        c = 10;
                        break;
                    case 0x74:
                        c = 9;
                        break;
                    case 0x66:
                        c = 12;
                        break;
                    case 0x62:
                        c = 8;
                        break;
                    case 0x75:
                        p = data.charCodeAt(++a) - 0x30;
                        if (p > 9) {
                            p -= 7;
                            if (p > 15) {
                                p -= 0x20;
                            }
                        }
                        if (p < 0 || p > 15) {
                            error(data, a, "Expected 0-F");
                        }
                        t = p << 4;
                    case 0x30:case 0x31:case 0x32:case 0x33:
                    case 0x34:case 0x35:case 0x36:case 0x37:
                        if (c == 0x75) {
                            p = data.charCodeAt(++a) - 0x30;
                        } else {
                            t = (c == 0x30 ? data.charCodeAt(++a) : c) - 0x30;
                            if (t > 7) {
                                if (c != 0x30) {
                                    break;
                                }
                                c = 0;
                                --a;
                                break;
                            }
                            p = data.charCodeAt(++a) - 0x30;
                            if (p > 7) {
                                --a;
                                if (c != 0x30) {
                                    break;
                                }
                                c = 0;
                                --a;
                                break;
                            }
                            c = (t << 3) | p;
                            break;
                        }
                        if (p > 9) {
                            p -= 7;
                            if (p > 15) {
                                p -= 0x20;
                            }
                        }
                        if (p < 0 || p > 15) {
                            error(data, a, "Expected 0-F");
                        }
                        t = (t | p) << 4;
                    case 0x78:
                        p = data.charCodeAt(++a) - 0x30;
                        if (p > 9) {
                            p -= 7;
                            if (p > 15) {
                                p -= 0x20;
                            }
                        }
                        if (p < 0 || p > 15) {
                            error(data, a, "Expected 0-F");
                        }
                        t = (t | p) << 4;
                        p = data.charCodeAt(++a) - 0x30;
                        if (p > 9) {
                            p -= 7;
                            if (p > 15) {
                                p -= 0x20;
                            }
                        }
                        if (p < 0 || p > 15) {
                            error(data, a, "Expected 0-F");
                        }
                        c = t | p;
                        break;
                    }
                    rtn[inx++] = c;
                    continue;
                } else if (c == end) {
                    break;
                }
                rtn[inx++] = c;
            }
            i = a;
            rtn.position = 0;
            return rtn.readUTFBytes(inx);
        }
        private static function handleNumber2(data:String, e:int):Number {
            var a:int = i, c:int = data.charCodeAt(a), r:Number = 0, t:int = 1;
            var n:Boolean;
            if (isSpace(c)) {
                do {
                    c = data.charCodeAt(++a);
                } while (isSpace(c) && i != e);
            }
            if (c == 0x2D) {
                c = data.charCodeAt(++a);
                n = true;
            } else if (c == 0x2B) {
                c = data.charCodeAt(++a);
            }
            if (isNumeric(c)) {
                r = c - 0x30;
                while (a != e) {
                    c = data.charCodeAt(++a);
                    if (isNumeric(c)) {
                        r = (r * 10) + (c - 0x30);
                    }
                }
            }
            if (c == 0x2E) {
                while (a != e) {
                    c = data.charCodeAt(++a);
                    if (isNumeric(c)) {
                        r += (c - 0x30) / (t *= 10);
                    }
                }
            }
            if (a != e) {
                if (isSpace(c)) {
                    do {
                        c = data.charCodeAt(++i);
                    } while (isSpace(c) && a < e);
                }
                if (a != e) {
                    error(data, a, "Expected 0-9 or .");
                }
            }
            return n ? r * -1.0 : r;
        }
        private static function handleNumber(data:String, e:int):Number {
            var a:int = i, c:int = data.charCodeAt(a), r:Number = 0, t:int = 1;
            var n:Boolean;
            if (isSpace(c)) {
                do {
                    c = data.charCodeAt(++a);
                } while (isSpace(c));
            }
            if (c == 0x2D) {
                c = data.charCodeAt(++a);
                n = true;
            } else if (c == 0x2B) {
                c = data.charCodeAt(++a);
            }
            if (isNumeric(c)) {
                r = c - 0x30;
                while (a != e) {
                    c = data.charCodeAt(++a);
                    if (isNumeric(c)) {
                        r = (r * 10) + (c - 0x30);
                        continue;
                    } else if (int(isSpace(c)) | int(c == 0x2C) | int(c == 0x5D) | int(c == 0x7D)) {
                        i = a - 1;
                        return n ? r * -1.0 : r;
                    }
                    break;
                }
            }
            if (c == 0x2E) {
                while (a != e) {
                    c = data.charCodeAt(++a);
                    if (isNumeric(c)) {
                        r += (c - 0x30) / (t *= 10);
                        continue;
                    } else if (int(isSpace(c)) | int(c == 0x2C) | int(c == 0x5D) | int(c == 0x7D)) {
                        i = a - 1;
                        return n ? r * -1.0 : r;
                    }
                    break;
                }
            }
            error(data, a, "Expected 0-9 or .");
            return NaN;
        }
        private static function handleLit(data:String, e:int):* {
            var a:int = data.charCodeAt(i++) | 0x20, b:int = data.charCodeAt(i++) | 0x20;
            var c:int = data.charCodeAt(i++) | 0x20, d:int = data.charCodeAt(i) | 0x20;
            if (a == 0x6E) {
                if (b == 0x75) {
                    if (c == 0x6C) {
                        if (d == 0x6C) {
                            return null;
                        }
                        error(data, i-1, "Expected 'l' after nul.");
                    }
                    error(data, i-2, "Expected 'l' after nu.");
                }
                error(data, i-3, "Expected 'u' after n.");
            } else if (a == 0x74) {
                if (b == 0x72) {
                    if (c == 0x75) {
                        if (d == 0x65) {
                            return true
                        }
                        error(data, i-1, "Expected 'e' after tur.");
                    }
                    error(data, i-2, "Expected 'r' after tu.");
                }
                error(data, i-3, "Expected 'u' after t.");
            } else if (a == 0x66) {
                if (b == 0x61) {
                    if (c == 0x6C) {
                        if (d == 0x73) {
                            if ((data.charCodeAt(++i) | 0x20) == 0x65) {
                                return false;
                            }
                            error(data, i-1, "Expected 'e' after fals.");
                        }
                        error(data, i-1, "Expected 's' after fal.");
                    }
                    error(data, i-2, "Expected 'l' after fa.");
                }
                error(data, i-3, "Expected 'a' after f.");
            }
        }
        private static function handleArray(data:String, e:int):Array {
            var rtn:Array = preArrs.pop(), c:int, inx:int, p:Boolean = true;
            while (i != e) {
                c = data.charCodeAt(++i);
                if (isSpace(c)) {
                    continue;
                } else if (c == 0x5D) {
                    break;
                } else if (p) {
                    p = false;
                    if (isObject(c)) {
                        rtn[inx++] = handleObject(data, e);
                        continue;
                    } else if (isArray(c)) {
                        rtn[inx++] = handleArray(data, e);
                        continue;
                    } else if (isString(c)) {
                        rtn[inx++] = handleString(data, e);
                        continue;
                    } else if (isNumber(c)) {
                        rtn[inx++] = handleNumber(data, e);
                        continue;
                    } else if (isLit(c)) {
                        rtn[inx++] = handleLit(data, e);
                        continue;
                    }
                    error(data, i);
                } else if (c == 0x2C) {
                    p = true;
                    continue;
                }
                error(data, i, "Expected , or ]");
            }
            rtn.length = inx;
            return rtn;
        }
        private static function handleObject(data:String, e:int):Object {
            var rtn:Object = preObjs.pop(), c:int, inx:String, p:Boolean = true;
            while (i != e) {
                c = data.charCodeAt(++i);
                if (isSpace(c)) {
                    continue;
                } else if (c == 0x7D) {
                    break;
                } else if (p) {
                    p = false;
                    if (isString(c)) {
                        inx = handleString(data, e);
                    } else {
                        // handle number?
                        error(data, i, "Expected \" or '");
                    }
                    c = data.charCodeAt(++i);
                    if (isSpace(c)) {
                        do {
                            c = data.charCodeAt(++i);
                        } while (isSpace(c) && i != e);
                    }
                    if (c == 0x3A) {
                        c = data.charCodeAt(++i);
                        if (isSpace(c)) {
                            do {
                                c = data.charCodeAt(++i);
                            } while (isSpace(c) && i != e);
                        }
                        if (isString(c)) {
                            rtn[inx] = handleString(data, e);
                            continue;
                        } else if (isNumber(c)) {
                            rtn[inx] = handleNumber(data, e);
                            continue;
                        } else if (isArray(c)) {
                            rtn[inx] = handleArray(data, e);
                            continue;
                        } else  if (isLit(c)) {
                            rtn[inx] = handleLit(data, e);
                            continue;
                        } else if (isObject(c)) {
                            rtn[inx] = handleObject(data, e);
                            continue;
                        }
                        error(data, i);
                    }
                    error(data, i, "Expected :");
                } else if (c == 0x2C) {
                    p = true;
                    continue;
                }
                error(data, i, "Expected , or }");
            }
            return rtn;
        }
        private static function error(data:String, i:int, e:String = null):void {
            throw new Error("Malformed JSON at char: " + i + ", " + data.charAt(i) + (e ? ". " + e : '.'), errorID);
        }
    }