[
  {
    "path": ".gitignore",
    "content": "dist/\n"
  },
  {
    "path": "MIT-LICENSE",
    "content": "Copyright (c) 2010 Tobias Schneider\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "Gordon\n======\n\n#### An open source Flash™ runtime written in pure JavaScript ####\n\nVisit the GitHub Wiki for more information: <http://wiki.github.com/tobeytailor/gordon/>\n"
  },
  {
    "path": "Rakefile",
    "content": "src_dir = 'src'\nrenderer_dir = File.join(src_dir, 'renderer')\ndist_dir = 'dist'\nbuild_dir = 'build'\nbase_files = [ 'base', 'stream', 'parser', 'movie' ].map { |file| File.join(src_dir, file + '.js') }\nrenderer_files = [ 'svg' ].map { |file| File.join(renderer_dir, file + '.js') }\nbuild_files = base_files + renderer_files\nintro = File.join(src_dir, 'intro.js')\noutro = File.join(src_dir, 'outro.js')\noutput_file = File.join(dist_dir, 'gordon.js')\noutput_file_min = File.join(dist_dir, 'gordon.min.js')\ncompiler = File.join(build_dir, 'compiler.jar')\n\ntask :default => :min\n\ntask :gordon do\n  sh 'mkdir -p ' + dist_dir\n  sh 'cat ' + intro + ' > ' + output_file\n  sh 'for file in ' + build_files.join(' ') + \"; do echo | cat $file - | sed 's/^/    /' >> \" + output_file + '; done'\n  sh 'cat ' + outro + ' >> ' + output_file\nend\n\ntask :min => :gordon do\n  sh 'head -6 ' + output_file + ' > ' + output_file_min\n  sh 'java -jar ' + compiler + ' --warning_level QUIET --js=' + output_file + ' >> ' + output_file_min\nend\n\ntask :clean do\n  sh 'rm -rf ' + dist_dir\nend\n"
  },
  {
    "path": "src/base.js",
    "content": "var win = window,\n    doc = win.document,\n    fromCharCode = String.fromCharCode,\n    push = Array.prototype.push,\n    min = Math.min,\n    max = Math.max;\n\nGordon = {\n    debug: false,\n    qualityValues: {\n        LOW: \"low\",\n        AUTO_LOW: \"autolow\",\n        AUTO_HIGH: \"autohigh\",\n        MEDIUM: \"medium\",\n        HIGH: \"high\",\n        BEST: \"best\"\n    },\n    scaleValues: {\n        SHOW_ALL: \"showall\",\n        NO_ORDER: \"noorder\",\n        EXACT_FIT: \"exactfit\"\n    },\n    validSignatures: {\n        SWF: \"FWS\",\n        COMPRESSED_SWF: \"CWS\"\n    },\n    readyStates: {\n        LOADING: 0,\n        UNINITIALIZED: 1,\n        LOADED: 2,\n        INTERACTIVE: 3,\n        COMPLETE: 4\n    },\n    tagCodes: {\n        END: 0,\n        SHOW_FRAME: 1,\n        DEFINE_SHAPE: 2,\n        PLACE_OBJECT: 4,\n        REMOVE_OBJECT: 5,\n        DEFINE_BITS: 6,\n        DEFINE_BUTTON: 7,\n        JPEG_TABLES: 8,\n        SET_BACKGROUND_COLOR: 9,\n        DEFINE_FONT: 10,\n        DEFINE_TEXT: 11,\n        DO_ACTION: 12,\n        DEFINE_FONT_INFO: 13,\n        DEFINE_SOUND: 14,\n        START_SOUND: 15,\n        DEFINE_BUTTON_SOUND: 17,\n        SOUND_STREAM_HEAD: 18,\n        SOUND_STREAM_BLOCK: 19,\n        DEFINE_BITS_LOSSLESS: 20,\n        DEFINE_BITS_JPEG2: 21,\n        DEFINE_SHAPE2: 22,\n        DEFINE_BUTTON_CXFORM: 23,\n        PROTECT: 24,\n        PLACE_OBJECT2: 26,\n        REMOVE_OBJECT2: 28,\n        DEFINE_SHAPE3: 32,\n        DEFINE_TEXT2: 33,\n        DEFINE_BUTTON2: 34,\n        DEFINE_BITS_JPEG3: 35,\n        DEFINE_BITS_LOSSLESS2: 36,\n        DEFINE_EDIT_TEXT: 37,\n        DEFINE_SPRITE: 39,\n        FRAME_LABEL: 43,\n        SOUND_STREAM_HEAD2: 45,\n        DEFINE_MORPH_SHAPE: 46,\n        DEFINE_FONT2: 48,\n        EXPORT_ASSETS: 56,\n        IMPORT_ASSETS: 57,\n        ENABLE_DEBUGGER: 58,\n        DO_INIT_ACTION: 59,\n        DEFINE_VIDEO_STREAM: 60,\n        VIDEO_FRAME: 61,\n        DEFINE_FONT_INFO2: 62,\n        ENABLE_DEBUGGER2: 64,\n        SCRIPT_LIMITS: 65,\n        SET_TAB_INDEX: 66,\n        FILE_ATTRIBUTES: 69,\n        PLACE_OBJECT3: 70,\n        IMPORT_ASSETS2: 71,\n        DEFINE_FONT_ALIGN_ZONES: 73,\n        CSM_TEXT_SETTINGS: 74,\n        DEFINE_FONT3: 75,\n        SYMBOL_CLASS: 76,\n        METADATA: 77,\n        DEFINE_SCALING_GRID: 78,\n        DO_ABC: 82,\n        DEFINE_SHAPE4: 83,\n        DEFINE_MORPH_SHAPE2: 84,\n        DEFINE_SCENE_AND_FRAME_LABEL_DATA: 86,\n        DEFINE_BINARY_DATA: 87,\n        DEFINE_FONT_NAME: 88,\n        START_SOUND2: 89,\n        DEFINE_BITS_JPEG4: 90,\n        DEFINE_FONT4: 91\n    },\n    controlTags: [0, 1, 4, 5, 15, 18, 19, 26, 28, 43, 45],\n    tagNames: {},\n    tagHandlers: {},\n    fillStyleTypes: {\n        SOLID: 0x00, \n        LINEAR_GRADIENT: 0x10, \n        RADIAL_GRADIENT: 0x12,\n        FOCAL_RADIAL_GRADIENT: 0x13,\n        REPEATING_BITMAP: 0x40, \n        CLIPPED_BITMAP: 0x41, \n        NON_SMOOTHED_REPEATING_BITMAP: 0x42,\n        NON_SMOOTHED_CLIPPED_BITMAP: 0x43\n    },\n    spreadModes: {\n        PAD: 0,\n        REFLECT: 1,\n        REPEAT: 2\n    },\n    interpolationModes: {\n        RGB: 0,\n        LINEAR_RGB: 1\n    },\n    styleChangeStates: {\n        MOVE_TO: 0x01,\n        LEFT_FILL_STYLE: 0x02,\n        RIGHT_FILL_STYLE: 0x04,\n        LINE_STYLE: 0x08,\n        NEW_STYLES: 0x10\n    },\n    buttonStates: {\n        UP: 0x01,\n        OVER: 0x02,\n        DOWN: 0x04,\n        HIT: 0x08\n    },\n    mouseButtons: {\n        LEFT: 1,\n        RIGHT: 2,\n        MIDDLE: 3\n    },\n    textStyleFlags: {\n        HAS_FONT: 0x08,\n        HAS_COLOR: 0x04,\n        HAS_XOFFSET: 0x01,\n        HAS_YOFFSET: 0x02\n    },\n    actionCodes: {\n        NEXT_FRAME: 0x04,\n        PREVIOUS_FRAME: 0x05,\n        PLAY: 0x06,\n        STOP: 0x07,\n        TOGGLE_QUALITY: 0x08,\n        STOP_SOUNDS: 0x09,\n        ADD: 0x0a,\n        SUBTRACT: 0x0b,\n        MULTIPLY: 0x0c,\n        DIVIDE: 0x0d,\n        EQUALS: 0x0e,\n        LESS: 0x0f,\n        AND: 0x10,\n        OR: 0x11,\n        NOT: 0x12,\n        STRING_EQUALS: 0x13,\n        STRING_LENGTH: 0x14,\n        STRING_EXTRACT: 0x15,\n        POP: 0x17,\n        TO_INTEGER: 0x18,\n        GET_VARIABLE: 0x1c,\n        SET_VARIABLE: 0x1d,\n        SET_TARGET2: 0x20,\n        STRING_ADD: 0x21,\n        GET_PROPERTY: 0x22,\n        SET_PROPERTY: 0x23,\n        CLONE_SPRITE: 0x24,\n        REMOVE_SPRITE: 0x25,\n        TRACE: 0x26,\n        START_DRAG: 0x27,\n        END_DRAG: 0x28,\n        STRING_LESS: 0x29,\n        THROW: 0x2a,\n        CAST_OP: 0x2b,\n        IMPLEMENTS_OP: 0x2c,\n        FS_COMMAND2: 0x2d,\n        RANDOM_NUMBER: 0x30,\n        MBSTRING_LENGTH: 0x31,\n        CHAR_TO_ASCII: 0x32,\n        ASCII_TO_CHAR: 0x33,\n        GET_TIME: 0x34,\n        MBSTRING_EXTRACT: 0x35,\n        MBCHAR_TO_ASCII: 0x36,\n        MBASCII_TO_CHAR: 0x37,\n        DELETE: 0x3a,\n        DELETE2: 0x3b,\n        DEFINE_LOCAL: 0x3c,\n        CALL_FUNCTION: 0x3d,\n        RETURN: 0x3e,\n        MODULO: 0x3f,\n        NEW_OBJECT: 0x40,\n        DEFINE_LOCAL2: 0x41,\n        INIT_ARRAY: 0x42,\n        INIT_OBJECT: 0x43,\n        TYPE_OF: 0x44,\n        TARGET_PATH: 0x45,\n        ENUMERATE: 0x46,\n        ADD2: 0x47,\n        LESS2: 0x48,\n        EQUALS2: 0x49,\n        TO_NUMBER: 0x4a,\n        TO_STRING: 0x4b,\n        PUSH_DUPLICATE: 0x4c,\n        STACK_SWAP: 0x4d,\n        GET_MEMBER: 0x4e,\n        SET_MEMBER: 0x4f,\n        INCREMENT: 0x50,\n        DECREMENT: 0x51,\n        CALL_METHOD: 0x52,\n        NEW_METHOD: 0x53,\n        INSTANCE_OF: 0x54,\n        ENUMERATE2: 0x55,\n        DO_INIT_ACTION: 0x59,\n        BIT_AND: 0x60,\n        BIT_OR: 0x61,\n        BIT_XOR: 0x62,\n        BIT_LSHIFT: 0x63,\n        BIT_RSHIFT: 0x64,\n        BIT_URSHIFT: 0x65,\n        STRICT_EQUALS: 0x66,\n        GREATER: 0x67,\n        STRING_GREATER: 0x68,\n        EXTENDS: 0x69,\n        GOTO_FRAME: 0x81,\n        DO_ABC: 0x82,\n        GET_URL: 0x83,\n        STORE_REGISTER: 0x87,\n        CONSTANT_POOL: 0x88,\n        WAIT_FOR_FRAME: 0x8a,\n        SET_TARGET: 0x8b,\n        SET_GO_TO_LABEL: 0x8c,\n        WAIT_FOR_FRAME2: 0x8d,\n        DEFINE_FUNCTION2: 0x8e,\n        TRY: 0x8f,\n        WITH: 0x94,\n        PUSH: 0x96,\n        JUMP: 0x99,\n        GET_URL2: 0x9a,\n        DEFINE_FUNCTION: 0x9b,\n        IF: 0x9d,\n        CALL: 0x9e,\n        GOTO_FRAME2: 0x9f\n    },\n    valueTypes: {\n        STRING: 0,\n        FLOATING_POINT: 1,\n        NULL: 2,\n        UNDEFINED: 3,\n        REGISTER: 4,\n        BOOLEAN: 5,\n        DOUBLE: 6,\n        INTEGER: 7,\n        CONSTANT8: 8,\n        SWIFF_CONSTANT16: 9\n    },\n    urlTargets: {\n        SELF: \"_self\",\n        BLANK: \"_blank\",\n        PARENT: \"_parent\",\n        TOP: \"_top\"\n    },\n    bitmapFormats: {\n        COLORMAPPED: 3,\n        RGB15: 4,\n        RGB24: 5\n    },\n    placeFlags: {\n        MOVE: 0x01,\n        HAS_CHARACTER: 0x02,\n        HAS_MATRIX: 0x04,\n        HAS_CXFORM: 0x08,\n        HAS_RATIO: 0x10,\n        HAS_NAME: 0x20,\n        HAS_CLIP_DEPTH: 0x40,\n        HAS_CLIP_ACTIONS: 0x80\n    },\n    defaultRenderer: null\n};\n\n(function(){\n    var t = Gordon.tagCodes,\n        n = Gordon.tagNames,\n        h = Gordon.tagHandlers;\n    for(var name in t){\n        var code = t[name];\n        n[code] = name;\n        h[code] = \"_handle\" + name.toLowerCase().replace(/(^|_)([a-z])/g, function(match, p1, p2){\n            return p2.toUpperCase();\n        });\n    }\n})();\n\nvar console = window.console || {\n    log: function(){}\n}\n\nfunction trace(){\n    if(Gordon.debug){ console.log.apply(console, arguments); }\n}\n"
  },
  {
    "path": "src/intro.js",
    "content": "/*\n *    Gordon: An open source Flash™ runtime written in pure JavaScript\n *\n *    Copyright (c) 2010 Tobias Schneider\n *    Gordon is freely distributable under the terms of the MIT license.\n */\n\n(function(window, undefined){\n"
  },
  {
    "path": "src/movie.js",
    "content": "(function(){\n    var LOCATION_DIRNAME = win.location.href.replace(/[^\\/]*$/, ''),\n        defaults = {\n            id: '',\n            width: 0,\n            height: 0,\n            autoplay: true,\n            loop: true,\n            quality: Gordon.qualityValues.HIGH,\n            scale: Gordon.scaleValues.SHOW_ALL,\n            bgcolor: '',\n            poster: '',\n            renderer: null,\n            onprogress: function(percent){},\n            onreadystatechange: function(state){}\n        };\n        \n    Gordon.Movie = function(url, options){\n        var t = this,\n            s = Gordon.readyStates;\n        t.url = url;\n        for(var prop in defaults){ t[prop] = prop in options ? options[prop] : defaults[prop]; }\n        if(!url){ throw new Error(\"URL of a SWF movie file must be passed as first argument\"); }\n        t._startTime = +new Date;\n        t.framesLoaded = 0;\n        t.isPlaying = false;\n        t.currentFrame = 0;\n        t.currentLabel = undefined;\n        t._readyState = s.UNINITIALIZED;\n        t._changeReadyState(t._readyState);\n        var d = t._dictionary = {},\n            l = t._timeline = [];\n        t._changeReadyState(s.LOADING);\n        new Gordon.Parser((/^\\w:\\/\\//.test(url) ? '' : LOCATION_DIRNAME) + url, function(obj){\n            var action = obj.action;\n            if(action){ eval(\"obj.action = function(){ \" + action + \"; }\"); }\n            switch(obj.type){\n                case \"header\":\n                    for(var prop in obj){ t['_' + prop] = obj[prop]; }\n                    var f = t._frameSize,\n                        r = t.renderer = t.renderer || Gordon.SvgRenderer,\n                        id = t.id;\n                    if(!(t.width && t.height)){\n                        t.width = (f.right - f.left) / 20;\n                        t.height = (f.bottom - f.top) / 20;\n                    };\n                    t._renderer = new r(t.width, t.height, f, t.quality, t.scale, t.bgcolor);\n                    t.totalFrames = t._frameCount;\n                    if(id){\n                        var stage = t._stage = doc.getElementById(id),\n                            bgcolor = t.bgcolor,\n                            bgParts = [],\n                            poster = t.poster;\n                        stage.innerHTML = '';\n                        if(t.bgcolor){ bgParts.push(bgcolor); }\n                        if(poster){ bgParts.push(poster, \"center center\"); }\n                        if(bgParts.length){ stage.setAttribute(\"style\", \"background: \" + bgParts.join(' ')); }\n                    }\n                    t._changeReadyState(s.LOADED);\n                    break;\n                case \"frame\":\n                    t._renderer.frame(obj);\n                    l.push(obj);\n                    var lbl = obj.label,\n                        n = ++t.framesLoaded;\n                    if(lbl){ t._labeledFrameNums[lbl] = n; }\n                    t.onprogress(~~((n * 100) / t.totalFrames));\n                    if(1 == n){\n                        var stage = t._stage;\n                        if(stage){\n                            stage.appendChild(t._renderer.node);\n                            t._changeReadyState(s.INTERACTIVE);\n                        }\n                        if(t.autoplay){ t.play(); }\n                        else{ t.goTo(1); }\n                    }\n                    if(n == t.totalFrames){ t._changeReadyState(s.COMPLETE); }\n                    break;\n                default:\n                    t._renderer.define(obj);\n                    d[obj.id] = obj;\n            }\n        });\n    };\n    Gordon.Movie.prototype = {\n        _changeReadyState: function(state){\n            this._readyState = state;\n            this.onreadystatechange(state);\n            return this;\n        },\n        \n        play: function(){\n            var t = this,\n                c = t.currentFrame,\n                timeout = 1000 / t._frameRate;\n            t.isPlaying = true;\n            if(c < t.totalFrames){\n                if(t.framesLoaded > c){ t.goTo(c + 1); }\n                else{ timeout = 0; }\n            }else{\n                if(!t.loop){ return t.stop(); }\n                else{ t.goTo(1); }\n            }\n            setTimeout(function(){\n                if(t.isPlaying){ t.play() };\n            }, timeout);\n            return t;\n        },\n        \n        next: function(){\n            var t = this,\n                c = t.currentFrame;\n            t.goTo(c < t.totalFrames ? c + 1 : 1);\n            return t;\n        },\n        \n        goTo: function gf(frmNumOrLabel){\n            var t = this,\n                c = t.currentFrame,\n                r = t._renderer;\n            if(gf.caller !== t.play){ t.stop(); }\n            if(isNaN(frmNumOrLabel)){\n                var frmNum = t._labeledFrameNums[frmNumOrLabel];\n                if(frmNum){ t.goTo(frmNum); }\n            }else if(frmNumOrLabel != c){\n                if(frmNumOrLabel < c){ c = t.currentFrame = 0; }\n                var l = t._timeline;\n                while(c != frmNumOrLabel){\n                    c = ++t.currentFrame;\n                    var idx = c - 1,\n                        frm = l[idx],\n                        action = frm.action;\n                    r.show(idx);\n                    t.currentLabel = frm.lbl;\n                    if(action){ action.call(this); }\n                }\n            }\n            return t;\n        },\n        \n        stop: function(){\n            this.isPlaying = false;\n            return this;\n        },\n        \n        prev: function(){\n            var t = this,\n                c = t.currentFrame;\n            t.goTo(c > 1 ? c - 1 : t.totalFrames);\n            return t;\n        },\n        \n        rewind: function(){\n            this.goTo(1);\n            return this;\n        },\n        \n        getURL: function(url, target){\n            var u = Gordon.urlTargets;\n            switch(target){\n                case u.BLANK:\n                    win.open(url);\n                    break;\n                case u.PARENT:\n                    win.parent.location.href = url;\n                    break;\n                case u.TOP:\n                    win.top.location.href = url;\n                    break;\n                default:\n                    win.location.href = url;\n            }\n            return this;\n        },\n        \n        toggleQuality: function thq(){\n            var o = thq._quality,\n                t = this,\n                q = t.quality;\n            if(o){\n                q = t.quality = o;\n                thq._quality = null;\n            }else{ t.quality = thq._quality = q; }\n            t._renderer.setQuality(q);\n            return t;\n        },\n        \n        getTime: function(){\n            return this._startTime;\n        }\n    };\n})();\n"
  },
  {
    "path": "src/outro.js",
    "content": "    win.Gordon = Gordon;\n})(self);\n"
  },
  {
    "path": "src/parser.js",
    "content": "(function(){\n    if(doc && window.Worker){\n        var REGEXP_SCRIPT_SRC = /(^|.*\\/)gordon.(min\\.)?js$/,\n            scripts = doc.getElementsByTagName(\"script\"),\n            src = '',\n            i = scripts.length;\n        while(i--){\n            var path = scripts[i].src;\n            if(REGEXP_SCRIPT_SRC.test(path)){\n                src = path;\n                break;\n            }\n        }\n        worker = new Worker(src);\n        \n        Gordon.Parser = function(data, ondata){\n            var t = this,\n                w = t._worker = worker;\n            t.data = data;\n            t.ondata = ondata;\n            \n            w.onmessage = function(e){\n                t.ondata(e.data);\n            };\n            \n            w.postMessage(data);\n        };\n    }else{\n        Gordon.Parser = function(url, ondata){\n            var xhr = new XMLHttpRequest(),\n                t = this;\n            xhr.open(\"GET\", url, false);\n            xhr.overrideMimeType(\"text/plain; charset=x-user-defined\");\n            xhr.send();\n            if(200 != xhr.status){ throw new Error(\"Unable to load \" + url + \" status: \" + xhr.status); }\n            if(ondata) { t.ondata = ondata; }\n            var s = t._stream = new Gordon.Stream(xhr.responseText),\n                sign = s.readString(3),\n                v = Gordon.validSignatures,\n                version = s.readUI8(),\n                fileLen = s.readUI32(),\n                h = Gordon.tagHandlers,\n                f = Gordon.tagCodes.SHOW_FRAME;\n            if(sign == v.COMPRESSED_SWF){ s.decompress(); }\n            else if(sign != v.SWF){ throw new Error(url + \" is not a SWF movie file\"); }\n            this.ondata({\n                type: \"header\",\n                version: version,\n                fileLength: fileLen,\n                frameSize: s.readRect(),\n                frameRate: s.readUI16() / 256,\n                frameCount: s.readUI16()\n            });\n            t._dictionary = {};\n            t._jpegTables = null;\n            do{\n                var frm = {\n                    type: \"frame\",\n                    displayList: {}\n                };\n                do{\n                    var hdr = s.readUI16(),\n                        code = hdr >> 6,\n                        len = hdr & 0x3f,\n                        handl = h[code];\n                    if(0x3f == len){ len = s.readUI32(); }\n                    var offset = s.offset;\n                    if(code){\n                        if(code == f){\n                            t.ondata(frm);\n                            break;\n                        }\n                        if(t[handl]){ t[handl](s, offset, len, frm); }\n                        else{ s.seek(len); }\n                    }\n                }while(code && code != f);\n            }while(code);\n        };\n        Gordon.Parser.prototype = {\n            ondata: function(data){\n                postMessage(data);\n            },\n            \n            _handleDefineShape: function(s, offset, len, frm, withAlpha){\n                var id = s.readUI16(),\n                    shape = {\n                        type: \"shape\",\n                        id: id,\n                        bounds: s.readRect()\n                    }\n                    t = this,\n                    fillStyles = t._readFillStyles(s, withAlpha),\n                    lineStyles = t._readLineStyles(s, withAlpha),\n                    edges = t._readEdges(s, fillStyles, lineStyles, withAlpha);\n                if(edges instanceof Array){\n                    var segments = shape.segments = [];\n                    for(var i = 0, seg = edges[0]; seg; seg = edges[++i]){ segments.push({\n                        type: \"shape\",\n                        id: id + '-' + (i + 1),\n                        commands: edges2cmds(seg.records, !!seg.line),\n                        fill: seg.fill,\n                        line: seg.line\n                    }); }\n                }else{\n                    shape.commands = edges2cmds(edges.records, !!edges.line),\n                    shape.fill = edges.fill,\n                    shape.line = edges.line\n                }\n                t.ondata(shape);\n                t._dictionary[id] = shape;\n                return t;\n            },\n            \n            _readEdges: function(s, fillStyles, lineStyles, withAlpha, morph){\n                var numFillBits = s.readUB(4),\n                    numLineBits = s.readUB(4),\n                    x1 = 0,\n                    y1 = 0,\n                    x2 = 0,\n                    y2 = 0,\n                    seg = [],\n                    i = 0,\n                    isFirst = true,\n                    edges = [],\n                    leftFill = 0,\n                    rightFill = 0,\n                    fsOffset = 0,\n                    lsOffset = 0,\n                    leftFillEdges = {},\n                    rightFillEdges = {},\n                    line = 0,\n                    lineEdges = {},\n                    c = Gordon.styleChangeStates,\n                    countFChanges = 0,\n                    countLChanges = 0,\n                    useSinglePath = true;\n                do{\n                    var type = s.readUB(1),\n                        flags = null;\n                    if(type){\n                        var isStraight = s.readBool(),\n                            numBits = s.readUB(4) + 2,\n                            cx = null,\n                            cy = null;\n                        x1 = x2;\n                        y1 = y2;\n                        if(isStraight){\n                            var isGeneral = s.readBool();\n                            if(isGeneral){\n                                x2 += s.readSB(numBits);\n                                y2 += s.readSB(numBits);\n                            }else{\n                                var isVertical = s.readBool();\n                                    if(isVertical){ y2 += s.readSB(numBits); }\n                                    else{ x2 += s.readSB(numBits); }\n                                }\n                        }else{\n                            cx = x1 + s.readSB(numBits);\n                            cy = y1 + s.readSB(numBits);\n                            x2 = cx + s.readSB(numBits);\n                            y2 = cy + s.readSB(numBits);\n                        }\n                        seg.push({\n                            i: i++,\n                            f: isFirst,\n                            x1: x1, y1: y1,\n                            cx: cx, cy: cy,\n                            x2: x2, y2: y2\n                        });\n                        isFirst = false;\n                    }else{\n                        if(seg.length){\n                            push.apply(edges, seg);\n                            if(leftFill){\n                                var idx = fsOffset + leftFill,\n                                    list = leftFillEdges[idx] || (leftFillEdges[idx] = []);\n                                for(var j = 0, edge = seg[0]; edge; edge = seg[++j]){\n                                    var e = cloneEdge(edge),\n                                        tx1 = e.x1,\n                                        ty1 = e.y1;\n                                    e.i = i++;\n                                    e.x1 = e.x2;\n                                    e.y1 = e.y2;\n                                    e.x2 = tx1;\n                                    e.y2 = ty1;\n                                    list.push(e);\n                                }\n                            }\n                            if(rightFill){\n                                var idx = fsOffset + rightFill,\n                                    list = rightFillEdges[idx] || (rightFillEdges[idx] = []);\n                                push.apply(list, seg);\n                            }\n                            if(line){\n                                var idx = lsOffset + line,\n                                    list = lineEdges[idx] || (lineEdges[idx] = []);\n                                push.apply(list, seg);\n                            }\n                            seg = [];\n                            isFirst = true;\n                        }\n                        var flags = s.readUB(5);\n                        if(flags){\n                            if(flags & c.MOVE_TO){\n                                var numBits = s.readUB(5);\n                                x2 = s.readSB(numBits);\n                                y2 = s.readSB(numBits);\n                            }\n                            if(flags & c.LEFT_FILL_STYLE){\n                                leftFill = s.readUB(numFillBits);\n                                countFChanges++;\n                            }\n                            if(flags & c.RIGHT_FILL_STYLE){\n                                rightFill = s.readUB(numFillBits);\n                                countFChanges++;\n                            }\n                            if(flags & c.LINE_STYLE){\n                                line = s.readUB(numLineBits);\n                                countLChanges++;\n                            }\n                            if((leftFill && rightFill) || countFChanges + countLChanges > 2){ useSinglePath = false; }\n                            if(flags & c.NEW_STYLES){\n                                fsOffset = fillStyles.length;\n                                lsOffset = lineStyles.length;\n                                push.apply(fillStyles, t._readFillStyles(s, withAlpha || morph));\n                                push.apply(lineStyles, t._readLineStyles(s, withAlpha || morph));\n                                numFillBits = s.readUB(4);\n                                numLineBits = s.readUB(4);\n                                useSinglePath = false;\n                            }\n                        }\n                    }\n                }while(type || flags);\n                s.align();\n                if(useSinglePath){\n                    var fill = leftFill || rightFill;\n                    return {\n                        records: edges,\n                        fill: fill ? fillStyles[fsOffset + fill - 1] : null,\n                        line: lineStyles[lsOffset + line - 1]\n                    };\n                }else{\n                    var segments = [];\n                    for(var i = 0; fillStyles[i]; i++){\n                        var fill = i + 1,\n                            list = leftFillEdges[fill],\n                            fillEdges = [],\n                            edgeMap = {};\n                        if(list){ push.apply(fillEdges, list); }\n                        list = rightFillEdges[fill];\n                        if(list){ push.apply(fillEdges, list); }\n                        for(var j = 0, edge = fillEdges[0]; edge; edge = fillEdges[++j]){\n                            var key = pt2key(edge.x1, edge.y1),\n                                list = edgeMap[key] || (edgeMap[key] = []);\n                            list.push(edge);\n                        }\n                        var recs = [],\n                            countFillEdges = fillEdges.length,\n                            l = countFillEdges - 1;\n                        for(var j = 0; j < countFillEdges && !recs[l]; j++){\n                            var edge = fillEdges[j];\n                            if(!edge.c){\n                                var seg = [],\n                                    firstKey = pt2key(edge.x1, edge.y1),\n                                    usedMap = {};\n                                do{\n                                    seg.push(edge);\n                                    usedMap[edge.i] = true;\n                                    var key = pt2key(edge.x2, edge.y2),\n                                        list = edgeMap[key],\n                                        favEdge = fillEdges[j + 1],\n                                        nextEdge = null;\n                                    if(key == firstKey){\n                                        var k = seg.length;\n                                        while(k--){ seg[k].c = true; }\n                                        push.apply(recs, seg);\n                                        break;\n                                    }\n                                    if (!(list && list.length)){ break; }\n                                    for(var k = 0; list[k]; k++){\n                                        var entry = list[k];\n                                        if(entry == favEdge && !entry.c){\n                                            list.splice(k, 1);\n                                            nextEdge = entry;\n                                        }\n                                    }\n                                    if(!nextEdge){\n                                        for(var k = 0; list[k]; k++){\n                                            var entry = list[k];\n                                            if(!(entry.c || usedMap[entry.i])){ nextEdge = entry; }\n                                        }\n                                    }\n                                    edge = nextEdge;\n                                }while(edge);\n                            }\n                        }\n                        var l = recs.length;\n                        if(l){ segments.push({\n                            records: recs,\n                            fill: fillStyles[i],\n                            \"_index\": recs[l - 1].i\n                        }); }\n                    }\n                    var i = lineStyles.length;\n                    while(i--){\n                        var recs = lineEdges[i + 1];\n                        if(recs){ segments.push({\n                            records: recs,\n                            line: lineStyles[i],\n                            _index: recs[recs.length - 1].i\n                        }); }\n                    }\n                    segments.sort(function(a, b){\n                        return a._index - b._index;\n                    });\n                    if(segments.length > 1){ return segments; }\n                    else{ return segments[0]; }\n                }\n            },\n            \n            _readFillStyles: function(s, withAlpha, morph){\n                var numStyles = s.readUI8(),\n                    styles = [];\n                if(0xff == numStyles){ numStyles = s.readUI16(); }\n                while(numStyles--){\n                    var type = s.readUI8(),\n                        f = Gordon.fillStyleTypes;\n                    switch(type){\n                        case f.SOLID:\n                            if(morph){ styles.push([s.readRGBA(), s.readRGBA()]); }\n                            else{ styles.push(withAlpha ? s.readRGBA() : s.readRGB()); }\n                            break;\n                        case f.LINEAR_GRADIENT:\n                        case f.RADIAL_GRADIENT:\n                            if(morph){ var matrix = [nlizeMatrix(s.readMatrix()), nlizeMatrix(s.readMatrix())]; }\n                            else{ var matrix = nlizeMatrix(s.readMatrix()); }\n                            var stops = [],\n                                style = {\n                                    type: type == f.LINEAR_GRADIENT ? \"linear\" : \"radial\",\n                                    matrix: matrix,\n                                    spread: morph ? Godon.spreadModes.PAD : s.readUB(2),\n                                    interpolation: morph ? Godon.interpolationModes.RGB : s.readUB(2),\n                                    stops: stops\n                                },\n                                numStops = s.readUB(4);\n                            while(numStops--){\n                                var offset = s.readUI8() / 256,\n                                    color = withAlpha || morph ? s.readRGBA() : s.readRGB();\n                                stops.push({\n                                    offset: morph ? [offset, s.readUI8() / 256] : offset,\n                                    color: morph ? [color, s.readRGBA()] : color\n                                });\n                            }\n                            styles.push(style);\n                            break;\n                        case f.REPEATING_BITMAP:\n                        case f.CLIPPED_BITMAP:\n                            var imgId = s.readUI16(),\n                                img = this._dictionary[imgId],\n                                matrix = morph ? [s.readMatrix(), s.readMatrix()] : s.readMatrix();\n                            if(img){\n                                styles.push({\n                                    type: \"pattern\",\n                                    image: img,\n                                    matrix: matrix,\n                                    repeat: type == f.REPEATING_BITMAP\n                                });\n                            }else{ styles.push(null); }\n                            break;\n                    }\n                }\n                return styles;\n            },\n            \n            _readLineStyles: function(s, withAlpha, morph){\n                var numStyles = s.readUI8(),\n                    styles = [];\n                if(0xff == numStyles){ numStyles = s.readUI16(); }\n                while(numStyles--){\n                    var width = s.readUI16(),\n                        color = withAlpha || morph ? s.readRGBA() : s.readRGB()\n                    styles.push({\n                        width: morph ? [width, s.readUI16()] : width,\n                        color: morph ? [color, s.readRGBA()] : color\n                    });\n                }\n                return styles;\n            },\n            \n            _handlePlaceObject: function(s, offset, len, frm){\n                var objId = s.readUI16(),\n                    depth = s.readUI16(),\n                    t = this,\n                    character = {\n                        object: t._dictionary[objId].id,\n                        depth: depth,\n                        matrix: s.readMatrix()\n                    };\n                if(s.offset - offset != len){ character.cxform = s.readCxform(); }\n                frm.displayList[depth] = character;\n                return t;\n            },\n            \n            _handleRemoveObject: function(s, offset, len, frm){\n                var id = s.readUI16(),\n                    depth = s.readUI16();\n                frm.displayList[depth] = null;\n                return this;\n            },\n            \n            _handleDefineBits: function(s, offset, len, frm, withAlpha){\n                var id = s.readUI16(),\n                    img = {\n                        type: \"image\",\n                        id: id,\n                        width: 0,\n                        height: 0\n                    },\n                    t = this,\n                    h = t._jpegTables;\n                if(withAlpha){\n                    var alphaDataOffset = s.readUI32(),\n                        data = s.readString(alphaDataOffset);\n                    img.alphaData = s.readString(len - (s.offset - offset));\n                }else{ var data = s.readString(len - 2); }\n                for(var i = 0; data[i]; i++){\n                    var word = ((data.charCodeAt(i) & 0xff) << 8) | (data.charCodeAt(++i) & 0xff);\n                    if(0xffd9 == word){\n                        word = ((data.charCodeAt(++i) & 0xff) << 8) | (data.charCodeAt(++i) & 0xff);\n                        if(word == 0xffd8){\n                            data = data.substr(0, i - 4) + data.substr(i);\n                            i -= 4;\n                        }\n                    }else if(0xffc0 == word){\n                        i += 3;\n                        img.height = ((data.charCodeAt(++i) & 0xff) << 8) | (data.charCodeAt(++i) & 0xff);\n                        img.width = ((data.charCodeAt(++i) & 0xff) << 8) | (data.charCodeAt(++i) & 0xff);\n                        break;\n                    }\n                }\n                img.data = h ? h.substr(0, h.length - 2) + data.substr(2) : data;\n                t.ondata(img);\n                t._dictionary[id] = img;\n                return t;\n            },\n            \n            _handleDefineButton: function(s, offset, len, frm, advanced){\n                var id = s.readUI16(),\n                    t = this,\n                    d = t._dictionary,\n                    states = {},\n                    button = {\n                        type: \"button\",\n                        id: id,\n                        states: states,\n                        trackAsMenu: advanced ? s.readBool(8) : false\n                    };\n                    if(advanced){ s.seek(2); }\n                do{\n                    var flags = s.readUI8();\n                    if(flags){\n                        var objId = s.readUI16(),\n                            depth = s.readUI16(),\n                            state = 0x01,\n                            character = {\n                                object: d[objId].id,\n                                depth: depth,\n                                matrix: s.readMatrix()\n                            };\n                            if(advanced){ character.cxform = s.readCxformA(); }\n                        while(state <= 0x08){\n                            if(flags & state){\n                                var list = states[state] || (states[state] = {});\n                                list[depth] = character;\n                            }\n                            state <<= 1;\n                        }\n                    }\n                }while(flags);\n                button.action = t._readAction(s, s.offset, len - (s.offset - offset));\n                t.ondata(button);\n                d[id] = button;\n                return t;\n            },\n            \n            _readAction: function(s, offset, len){\n                s.seek(len - (s.offset - offset));\n                return '';\n            },\n            \n            _handleJpegTables: function(s, offset, len){\n                this._jpegTables = s.readString(len);\n                return this;\n            },\n            \n            _handleSetBackgroundColor: function(s, offset, len, frm){\n                frm.bgcolor = s.readRGB();\n                return this;\n            },\n            \n            _handleDefineFont: function(s){\n                var id = s.readUI16(),\n                    numGlyphs = s.readUI16() / 2,\n                    glyphs = [],\n                    t = this,\n                    font = {\n                        type: \"font\",\n                        id: id,\n                        glyphs: glyphs\n                    };\n                s.seek(numGlyphs * 2 - 2);\n                while(numGlyphs--){ glyphs.push(t._readGlyph(s)); }\n                t.ondata(font);\n                t._dictionary[id] = font;\n                return t;\n            },\n            \n            _readGlyph: function(s){\n                var numFillBits = s.readUB(4),\n                    numLineBits = s.readUB(4),\n                    x = 0,\n                    y = 0,\n                    cmds = [],\n                    c = Gordon.styleChangeStates;\n                do{\n                    var type = s.readUB(1),\n                        flags = null;\n                    if(type){\n                        var isStraight = s.readBool(),\n                            numBits = s.readUB(4) + 2;\n                        if(isStraight){\n                            var isGeneral = s.readBool();\n                            if(isGeneral){\n                                x += s.readSB(numBits);\n                                y += s.readSB(numBits);\n                                cmds.push('L' + x + ',' + y);\n                            }else{\n                                var isVertical = s.readBool();\n                                if(isVertical){\n                                    y += s.readSB(numBits);\n                                    cmds.push('V' + y);\n                                }else{\n                                    x += s.readSB(numBits);\n                                    cmds.push('H' + x);\n                                }\n                            }\n                        }else{\n                            var cx = x + s.readSB(numBits),\n                                cy = y + s.readSB(numBits);\n                            x = cx + s.readSB(numBits);\n                            y = cy + s.readSB(numBits);\n                            cmds.push('Q' + cx + ',' + cy + ',' + x + ',' + y);\n                        }\n                    }else{\n                        var flags = s.readUB(5);\n                        if(flags){\n                            if(flags & c.MOVE_TO){\n                                var numBits = s.readUB(5);\n                                x = s.readSB(numBits);\n                                y = s.readSB(numBits);\n                                cmds.push('M' + x + ',' + y);\n                            }\n                            if(flags & c.LEFT_FILL_STYLE || flags & c.RIGHT_FILL_STYLE){ s.readUB(numFillBits); }\n                        }\n                    }\n                }while(type || flags);\n                s.align();\n                return {commands: cmds.join('')};\n            },\n            \n            _handleDefineText: function(s, offset, length, frm, withAlpha){\n                var id = s.readUI16(),\n                    strings = [],\n                    txt = {\n                        type: \"text\",\n                        id: id,\n                        bounds: s.readRect(),\n                        matrix: s.readMatrix(),\n                        strings: strings\n                    },\n                    numGlyphBits = s.readUI8(),\n                    numAdvBits = s.readUI8(),\n                    fontId = null,\n                    fill = null,\n                    x = 0,\n                    y = 0,\n                    size = 0,\n                    str = null,\n                    d = this._dictionary;\n                do{\n                    var hdr = s.readUB(8);\n                    if(hdr){\n                        var type = hdr >> 7;\n                        if(type){\n                            var flags = hdr & 0x0f;\n                            if(flags){\n                                var f = Gordon.textStyleFlags;\n                                if(flags & f.HAS_FONT){ fontId = s.readUI16(); }\n                                if(flags & f.HAS_COLOR){ fill = withAlpha ? s.readRGBA() : s.readRGB(); }\n                                if(flags & f.HAS_XOFFSET){ x = s.readSI16(); }\n                                if(flags & f.HAS_YOFFSET){ y = s.readSI16(); }\n                                if(flags & f.HAS_FONT){ size = s.readUI16(); }\n                            }\n                            str = {\n                                font: d[fontId].id,\n                                fill: fill,\n                                x: x,\n                                y: y,\n                                size: size,\n                                entries: []\n                            };\n                            strings.push(str);\n                        }else{\n                            var numGlyphs = hdr & 0x7f,\n                                entries = str.entries;\n                            while(numGlyphs--){\n                                var idx = s.readUB(numGlyphBits),\n                                    adv = s.readSB(numAdvBits);\n                                entries.push({\n                                    index: idx,\n                                    advance: adv\n                                });\n                                x += adv;\n                            }\n                            s.align();\n                        }\n                    }\n                }while(hdr);\n                this.ondata(txt);\n                d[id] = txt;\n                return this;\n            },\n            \n            _handleDoAction: function(s, offset, len, frm){\n                frm.action = this._readAction(s, offset, len);\n                return this;\n            },\n            \n            _handleDefineFontInfo: function(s, offset, len){\n                var d = this._dictionary,\n                    fontId = s.readUI16(),\n                    font = d[fontId],\n                    codes = [],\n                    f = font.info = {\n                        name: s.readString(s.readUI8()),\n                        isSmall: s.readBool(3),\n                        isShiftJIS: s.readBool(),\n                        isANSI: s.readBool(),\n                        isItalic: s.readBool(),\n                        isBold: s.readBool(),\n                        codes: codes\n                    },\n                    u = f.isUTF8 = s.readBool(),\n                    i = font.glyphs.length;\n                while(i--){ codes.push(u ? s.readUI16() : s.readUI8()); }\n                this.ondata(font);\n                d[fontId] = font;\n                return this;\n            },\n            \n            _handleDefineBitsLossless: function(s, offset, len, frm, withAlpha){\n                var id = s.readUI16(),\n                    format = s.readUI8(),\n                    img = {\n                        type: \"image\",\n                        id: id,\n                        width: s.readUI16(),\n                        height: s.readUI16(),\n                        withAlpha: withAlpha\n                    };\n                if(format == Gordon.bitmapFormats.COLORMAPPED){ img.colorTableSize = s.readUI8() + 1; }\n                img.colorData = s.readString(len - (s.offset - offset));\n                this.ondata(img);\n                this._dictionary[id] = img;\n                return this;\n            },\n            \n            _handleDefineBitsJpeg2: function(s, offset, len){\n                return this._handleDefineBits(s, offset, len);\n            },\n            \n            _handleDefineShape2: function(s, offset, len){\n                return this._handleDefineShape(s, offset, len);\n            },\n            \n            _handleDefineButtonCxform: function(s){\n                var t = this,\n                    d = t._dictionary,\n                    buttonId = s.readUI16(),\n                    button = d[buttonId];\n                button.cxform = s.readCxform();\n                t.ondata(button);\n                d[buttonId] = button;\n                return t;\n            },\n            \n            _handleProtect: function(s, offset, len){\n                s.seek(len);\n                return this;\n            },\n            \n            _handlePlaceObject2: function(s, offset, len, frm){\n                var flags = s.readUI8(),\n                    depth = s.readUI16(),\n                    f = Gordon.placeFlags,\n                    character = {depth: depth},\n                    t = this;\n                if(flags & f.HAS_CHARACTER){\n                    var objId = s.readUI16();\n                    character.object = t._dictionary[objId].id;\n                }\n                if(flags & f.HAS_MATRIX){ character.matrix = s.readMatrix(); }\n                if(flags & f.HAS_CXFORM){ character.cxform = s.readCxformA(); }\n                if(flags & f.HAS_RATIO){ character.ratio = s.readUI16(); }\n                if(flags & f.HAS_NAME){ character.name = s.readString(); }\n                if(flags & f.HAS_CLIP_DEPTH){ character.clipDepth = s.readUI16(); }\n                if(flags & f.HAS_CLIP_ACTIONS){ s.seek(len - (s.offset - offset)) }\n                frm.displayList[depth] = character;\n                return t;\n            },\n            \n            _handleRemoveObject2: function(s, offset, len, frm){\n                var depth = s.readUI16();\n                frm.displayList[depth] = null;\n                return this;\n            },\n            \n            _handleDefineShape3: function(s, offset, len, frm){\n                return this._handleDefineShape(s, offset, len, frm, true);\n            },\n            \n            _handleDefineText2: function(s, offset, len, frm){\n                return this._handleDefineText(s, offset, len, frm, true);\n            },\n            \n            _handleDefineButton2: function(s, offset, len, frm){\n                return t._handleDefineButton(s, offset, len, frm, true);\n            },\n            \n            _handleDefineBitsJpeg3: function(s, offset, len, frm){\n                return this._handleDefineBits(s, offset, len, frm, true);\n            },\n            \n            _handleDefineBitsLossless2: function(s, offset, len, frm){\n                return this._handleDefineBitsLossless(s, offset, len, frm, true);\n            },\n            \n            _handleDefineSprite: function(s, offset, len){\n                var id = s.readUI16(),\n                    frameCount = s.readUI16(),\n                    h = Gordon.tagHandlers,\n                    f = Gordon.tagCodes.SHOW_FRAME,\n                    c = Gordon.controlTags,\n                    timeline = [],\n                    sprite = {\n                        id: id,\n                        timeline: timeline\n                    },\n                    t = this;\n                do{\n                    var frm = {\n                        type: \"frame\",\n                        displayList: {}\n                    };\n                    do{\n                        var hdr = s.readUI16(),\n                            code = hdr >> 6,\n                            len = hdr & 0x3f,\n                            handl = h[code];\n                        if(0x3f == len){ len = s.readUI32(); }\n                        var offset = s.offset;\n                        if(code){\n                            if(code == f){\n                                timeline.push(c);\n                                break;\n                            }\n                            if(c[code] && t[handl]){ t[handl](s, offset, len, frm); }\n                            else{ s.seek(len); }\n                        }\n                    }while(code);\n                }while(code);\n                t.ondata(sprite);\n                t._dictionary[id] = sprite;\n                return t;\n            },\n            \n            _handleFrameLabel: function(s, offset, len, frm){\n                frm.label = s.readString();\n                return this;\n            },\n            \n            _handleDefineMorphShape: function(s, offset, len){\n                var id = s.readUI16(),\n                    startBounds = s.readRect(),\n                    endBounds = s.readRect(),\n                    endEdgesOffset = s.readUI32(),\n                    t = this,\n                    fillStyles = t._readFillStyles(s, true, true),\n                    lineStyles = t._readLineStyles(s, true, true),\n                    morph = {\n                        type: \"morph\",\n                        id: id,\n                        startEdges: t._readEdges(s, fillStyles, lineStyles, true, true),\n                        endEdges: t._readEdges(s, fillStyles, lineStyles, true, true)\n                    };\n                t.ondata(morph);\n                t._dictionary[id] = morph;\n                return t;\n            },\n            \n            _handleDefineFont2: function(s, offset, len){\n                var id = s.readUI16(),\n                    hasLayout = s.readBool(),\n                    glyphs = [],\n                    font = {\n                        type: \"font\",\n                        id: id,\n                        glyphs: glyphs\n                    },\n                    codes = [],\n                    f = font.info = {\n                        isShiftJIS: s.readBool(),\n                        isSmall: s.readBool(),\n                        isANSI: s.readBool(),\n                        useWideOffsets: s.readBool(),\n                        isUTF8: s.readBool(),\n                        isItalic: s.readBool(),\n                        isBold: s.readBool(),\n                        languageCode: s.readLanguageCode(),\n                        name: s.readString(s.readUI8()),\n                        codes: codes\n                    },\n                    i = numGlyphs = s.readUI16(),\n                    w = f.useWideOffsets,\n                    offsets = [],\n                    tablesOffset = s.offset,\n                    u = f.isUTF8;\n                while(i--){ offsets.push(w ? s.readUI32() : s.readUI16()); }\n                s.seek(w ? 4 : 2);\n                for(var i = 0, o = offsets[0]; o; o = offsets[++i]){\n                    s.seek(tablesOffset + o, true);\n                    glyphs.push(this._readGlyph(s));\n                }\n                var i = numGlyphs;\n                while(i--){ codes.push(u ? s.readUI16() : s.readUI8()); };\n                if(hasLayout){\n                    f.ascent = s.readUI16();\n                    f.descent = s.readUI16();\n                    f.leading = s.readUI16();\n                    var advanceTable = f.advanceTable = [],\n                        boundsTable = f.boundsTable = [],\n                        kerningTable = f.kerningTable = [];\n                    i = numGlyphs;\n                    while(i--){ advanceTable.push(s.readUI16()); };\n                    i = numGlyphs;\n                    while(i--){ boundsTable.push(s.readRect()); };\n                    var kerningCount = s.readUI16();\n                    while(kerningCount--){ kerningTable.push({\n                        code1: u ? s.readUI16() : s.readUI8(),\n                        code2: u ? s.readUI16() : s.readUI8(),\n                        adjustment: s.readUI16()\n                    }); }\n                }\n                this.ondata(font);\n                this._dictionary[id] = font;\n                return this;\n            }\n        };\n        \n        function nlizeMatrix(matrix){\n            return {\n                scaleX: matrix.scaleX * 20, scaleY: matrix.scaleY * 20,\n                skewX: matrix.skewX * 20, skewY: matrix.skewY * 20,\n                moveX: matrix.moveX, moveY: matrix.moveY\n            };\n        }\n        \n        function cloneEdge(edge){\n            return {\n                i: edge.i,\n                f: edge.f,\n                x1: edge.x1, y1: edge.y1,\n                cx: edge.cx, cy: edge.cy,\n                x2: edge.x2, y2: edge.y2\n            };\n        }\n        \n        function edges2cmds(edges, stroke){\n            var firstEdge = edges[0],\n                x1 = 0,\n                y1 = 0,\n                x2 = 0,\n                y2 = 0,\n                cmds = [];\n            for(var i = 0, edge = firstEdge; edge; edge = edges[++i]){\n                x1 = edge.x1;\n                y1 = edge.y1;\n                if(x1 != x2 || y1 != y2 || !i){ cmds.push('M' + x1 + ',' + y1); }\n                x2 = edge.x2;\n                y2 = edge.y2;\n                if(null == edge.cx || null == edge.cy){\n                    if(x2 == x1){ cmds.push('V' + y2); }\n                    else if(y2 == y1){ cmds.push('H' + x2); }\n                    else{ cmds.push('L' + x2 + ',' + y2); }\n                }else{ cmds.push('Q' + edge.cx + ',' + edge.cy + ',' + x2 + ',' + y2); }\n            };\n            if(!stroke && (x2 != firstEdge.x1 || y2 != firstEdge.y1)){ cmds.push('L' + firstEdge.x1 + ',' + firstEdge.y1) }\n            return cmds.join('');\n        }\n        \n        function pt2key(x, y){\n            return (x + 50000) * 100000 + y;\n        }\n        \n        win.onmessage = function(e){\n            new Gordon.Parser(e.data);\n        };\n    }\n})();\n"
  },
  {
    "path": "src/renderer/canvas.js",
    "content": "/* TODO */\n"
  },
  {
    "path": "src/renderer/css.js",
    "content": "/* TODO */\n"
  },
  {
    "path": "src/renderer/svg.js",
    "content": "(function(){\n    var NS_SVG = \"http://www.w3.org/2000/svg\",\n        NS_XLINK = \"http://www.w3.org/1999/xlink\",\n        NS_XHTML = \"http://www.w3.org/1999/xhtml\",\n        b = Gordon.buttonStates,\n        buttonStates = {},\n        buttonMask = 0;\n    for(var state in b){ buttonStates[b[state]] = state.toLowerCase(); }\n    \n    Gordon.SvgRenderer = function(width, height, frmSize, quality, scale, bgcolor){\n        var t = this,\n            n = t.node = t._createElement(\"svg\"),\n            frmLeft = frmSize.left,\n            frmTop = frmSize.top,\n            attrs = {\n                width: width,\n                height: height,\n                viewBox: '' + [frmLeft, frmTop, frmSize.right - frmLeft, frmSize.bottom - frmTop]\n            };\n        t.width = width;\n        t.height = height;\n        t.frmSize = frmSize;\n        t.quality = quality || Gordon.qualityValues.HIGH;\n        t.scale = scale || Gordon.scaleValues.SHOW_ALL;\n        t.bgcolor = bgcolor;\n        if(scale == Gordon.scaleValues.EXACT_FIT){ attrs.preserveAspectRatio = \"none\"; }\n        t._setAttributes(n, attrs);\n        t._defs = n.appendChild(t._createElement(\"defs\"));\n        var s = t._stage = n.appendChild(t._createElement('g'));\n        t._setAttributes(s, {\n            \"fill-rule\": \"evenodd\",\n            \"stroke-linecap\": \"round\",\n            \"stroke-linejoin\": \"round\"\n        });\n        t.setQuality(t.quality);\n        if(bgcolor){ t.setBgcolor(bgcolor); }\n        t._dictionary = {};\n        t._fills = {};\n        t._set = {};\n        t._timeline = [];\n        t._displayList = {};\n        t._eventTarget = null;\n    };\n    Gordon.SvgRenderer.prototype = {\n        _createElement: function(name){\n            return doc.createElementNS(NS_SVG, name);\n        },\n        \n        _setAttributes: function(node, attrs, ns){\n            if(node){\n                for(var name in attrs){\n                    if(ns){ node.setAttributeNS(ns, name, attrs[name]); }\n                    else{ node.setAttribute(name, attrs[name]); }\n                }\n            }\n            return node;\n        },\n        \n        setQuality: function(quality){\n            var q = Gordon.qualityValues,\n                t = this;\n            switch(quality){\n                case q.LOW:\n                    var attrs = {\n                        \"shape-rendering\": \"crispEdges\",\n                        \"image-rendering\": \"optimizeSpeed\",\n                        \"text-rendering\": \"optimizeSpeed\",\n                        \"color-rendering\": \"optimizeSpeed\"\n                    }\n                    break;\n                case q.AUTO_LOW:\n                case q.AUTO_HIGH:\n                    var attrs = {\n                        \"shape-rendering\": \"auto\",\n                        \"image-rendering\": \"auto\",\n                        \"text-rendering\": \"auto\",\n                        \"color-rendering\": \"auto\"\n                    }\n                    break;\n                case q.MEDIUM:\n                    var attrs = {\n                        \"shape-rendering\": \"optimizeSpeed\",\n                        \"image-rendering\": \"optimizeSpeed\",\n                        \"text-rendering\": \"optimizeLegibility\",\n                        \"color-rendering\": \"optimizeSpeed\"\n                    }\n                    break;\n                case q.HIGH:\n                    var attrs = {\n                        \"shape-rendering\": \"geometricPrecision\",\n                        \"image-rendering\": \"auto\",\n                        \"text-rendering\": \"geometricPrecision\",\n                        \"color-rendering\": \"optimizeQuality\"\n                    }\n                    break;\n                case q.BEST:\n                    var attrs = {\n                        \"shape-rendering\": \"geometricPrecision\",\n                        \"image-rendering\": \"optimizeQuality\",\n                        \"text-rendering\": \"geometricPrecision\",\n                        \"color-rendering\": \"optimizeQuality\"\n                    }\n                    break;\n            }\n            t._setAttributes(t._stage, attrs);\n            t.quality = quality;\n            return t;\n        },\n        \n        setBgcolor: function(rgb){\n            var t = this;\n            if(!t.bgcolor){\n                t.node.style.background = color2string(rgb);\n                t.bgcolor = rgb;\n            }\n            return t;\n        },\n        \n        define: function(obj){\n            var t = this,\n                d = t._dictionary,\n                id = obj.id,\n                item = d[id],\n                type = obj.type,\n                node = null,\n                attrs = {id: type[0] + id};\n            if(!item || !item.node){\n                switch(type){\n                    case \"shape\":\n                        var segments = obj.segments,\n                            fill = obj.fill;\n                        if(segments){\n                            var node = t._createElement('g'),\n                                frag = doc.createDocumentFragment();\n                            for(var i = 0, seg = segments[0]; seg; seg = segments[++i]){\n                                var segNode = frag.appendChild(t._createElement(\"path\"));\n                                t._setAttributes(segNode, {id: 's' + seg.id, d: seg.commands});\n                            }\n                            node.appendChild(frag);\n                        }else{\n                            if(fill && \"pattern\" == fill.type && !fill.repeat){\n                                var node = t._createElement(\"use\");\n                                t._setAttributes(node, {href: \"#\" + fill.image.id}, NS_XLINK);\n                                attrs.transform = matrix2string(fill.matrix);\n                            }else{\n                                var node = t._createElement(\"path\");\n                                attrs.d = obj.commands;\n                            }\n                        }\n                        break;\n                    case \"image\":\n                        var node = t._createElement(\"image\"),\n                            colorData = obj.colorData,\n                            width = obj.width,\n                            height = obj.height;\n                        if(colorData){\n                            var colorTableSize = obj.colorTableSize || 0,\n                                bpp = (obj.withAlpha ? 4 : 3),\n                                cmIdx = colorTableSize * bpp,\n                                data = (new Gordon.Stream(colorData)).unzip(true),\n                                withAlpha = obj.withAlpha,\n                                pxIdx = 0,\n                                canvas = doc.createElement(\"canvas\"),\n                                ctx = canvas.getContext(\"2d\"),\n                                imgData = ctx.getImageData(0, 0, width, height),\n                                pxData = imgData.data,\n                                pad = colorTableSize ? ((width + 3) & ~3) - width : 0\n                            canvas.width = width;\n                            canvas.height = height;\n                            for(var y = 0; y < height; y++){\n                                for(var x = 0; x < width; x++){\n                                    var idx = (colorTableSize ? data[cmIdx++] : cmIdx) * bpp,\n                                        alpha = withAlpha ? data[cmIdx + 3] : 255;\n                                    if(alpha){\n                                        pxData[pxIdx] = data[idx];\n                                        pxData[pxIdx + 1] = data[idx + 1];\n                                        pxData[pxIdx + 2] = data[idx + 2];\n                                        pxData[pxIdx + 3] = alpha;\n                                    }\n                                    pxIdx += 4;\n                                }\n                                cmIdx += pad;\n                            }\n                            ctx.putImageData(imgData, 0, 0);\n                            var uri = canvas.toDataURL();\n                        }else{\n                            var alphaData = obj.alphaData,\n                                uri = \"data:image/jpeg;base64,\" + btoa(obj.data);\n                            if(alphaData){\n                                var img = new Image(),\n                                    canvas = doc.createElement(\"canvas\"),\n                                    ctx = canvas.getContext(\"2d\"),\n                                    len = width * height,\n                                    data = (new Gordon.Stream(alphaData)).unzip(true);\n                                img.src = uri;\n                                canvas.width = width;\n                                canvas.height = height;\n                                ctx.drawImage(img, 0, 0);\n                                var imgData = ctx.getImageData(0, 0, width, height),\n                                    pxData = imgData.data,\n                                    pxIdx = 0;\n                                for(var i = 0; i < len; i++){\n                                    pxData[pxIdx + 3] = data[i];\n                                    pxIdx += 4;\n                                }\n                                ctx.putImageData(imgData, 0, 0);\n                                uri = canvas.toDataURL();\n                            }\n                        }\n                        t._setAttributes(node, {href: uri}, NS_XLINK);\n                        attrs.width = width;\n                        attrs.height = height;\n                        break;\n                    case \"font\":\n                        var info = obj.info;\n                        if(info){\n                            var node = t._createElement(\"font\"),\n                                faceNode = node.appendChild(t._createElement(\"font-face\")),\n                                advanceTable = info.advanceTable\n                                glyphs = obj.glyphs,\n                                codes = info.codes,\n                                frag = doc.createDocumentFragment(),\n                                kerningTable = info.kerningTable;\n                            t._setAttributes(faceNode, {\n                                \"font-family\": id,\n                                \"units-per-em\": 20480,\n                                ascent: info.ascent || 20480,\n                                descent: info.ascent || 20480,\n                                \"horiz-adv-x\": advanceTable ? '' + advanceTable : 20480\n                            });\n                            for(var i = 0, glyph = glyphs[0]; glyph; glyph = glyphs[++i]){\n                                var cmds = glyph.commands,\n                                    code = codes[i];\n                                if(cmds && code){\n                                    var glyphNode = frag.appendChild(t._createElement(\"glyph\"));\n                                    t._setAttributes(glyphNode, {\n                                        unicode: fromCharCode(code),\n                                        d: glyph.commands\n                                    });\n                                }\n                            }\n                            if(kerningTable){\n                                for(var i = 0, kern = kerningTable[0]; kern; kern = kerningTable[++i]){\n                                    var kernNode = frag.appendChild(t._createElement(\"hkern\"));\n                                    t._setAttributes(kernNode, {\n                                        g1: kern.code1,\n                                        g2: kern.code2,\n                                        k: kern.adjustment\n                                    });\n                                }\n                            }\n                            node.appendChild(frag);\n                        }\n                        break;\n                    case \"text\":\n                        var frag = doc.createDocumentFragment(),\n                            strings = obj.strings;\n                        for(var i = 0, string = strings[0]; string; string = strings[++i]){\n                            var txtNode = frag.appendChild(t._createElement(\"text\")),\n                                entries = string.entries,\n                                font = t._dictionary[string.font].object,\n                                info = font.info,\n                                codes = info.codes,\n                                advances = [],\n                                chars = [];\n                                x = string.x,\n                                y = string.y * -1;\n                            for(var j = 0, entry = entries[0]; entry; entry = entries[++j]){\n                                var str = fromCharCode(codes[entry.index]);\n                                if(' ' != str || chars.length){\n                                    advances.push(x);\n                                    chars.push(str);\n                                }\n                                x += entry.advance;\n                            }\n                            t._setAttributes(txtNode, {\n                                id: 't' + id + '-' + (i + 1),\n                                \"font-family\": font.id,\n                                \"font-size\": string.size * 20,\n                                x: advances.join(' '),\n                                y: y\n                            });\n                            txtNode.appendChild(doc.createTextNode(chars.join('')));\n                        }\n                        if(strings.length > 1){\n                            var node = t._createElement('g');\n                            node.appendChild(frag);\n                        }else{ var node = frag.firstChild; }\n                        break;\n                }\n                if(node){\n                    t._setAttributes(node, attrs);\n                    t._defs.appendChild(node);\n                }\n                d[id] = {\n                    object: obj,\n                    node: node\n                }\n            }else{ d[id].object = obj; }\n            return t;\n        },\n        \n        frame: function(frm){\n            var bgcolor = frm.bgcolor,\n                t = this,\n                d = frm.displayList;\n            if(bgcolor && !t.bgcolor){\n                t.setBgcolor(bgcolor);\n                t.bgcolor = bgcolor;\n            }\n            for(depth in d){\n                var character = d[depth];\n                if(character){ t._cast(character); }\n            }\n            t._timeline.push(frm);\n            return t;\n        },\n        \n        _cast: function(character, cxform2){\n            var t = this,\n                objId = character.object || t._displayList[character.depth].character.object;\n            if(objId){\n                if(character.clipDepth){\n                    var cpNode = t._defs.appendChild(t._createElement(\"clipPath\")),\n                        useNode = cpNode.appendChild(t._createElement(\"use\")),\n                        attrs = {id: 'p' + objId},\n                        matrix = character.matrix;\n                    t._setAttributes(useNode, {href: '#s' + objId}, NS_XLINK);\n                    if(matrix){ attrs.transform = matrix2string(matrix); }\n                    t._setAttributes(useNode, attrs);\n                }\n                var cxform1 = character.cxform,\n                    cxform = cxform1 && cxform2 ? concatCxform(cxform1, cxform2) : cxform1 || cxform2,\n                    characterId = character._id = objectId({\n                        object: objId,\n                        cxform: cxform\n                    });\n                if(!t._set[characterId]){\n                    var obj = t._dictionary[objId].object,\n                        node = null,\n                        type = obj.type,\n                        t = this,\n                        attrs = {id: 'c' + characterId};\n                    switch(type){\n                        case \"shape\":\n                            var segments = obj.segments;\n                            if(segments){\n                                var node = t._createElement('g'),\n                                    frag = doc.createDocumentFragment();\n                                for(var i = 0, seg = segments[0]; seg; seg = segments[++i]){\n                                    var useNode = frag.appendChild(t._createElement(\"use\"));\n                                    t._setAttributes(useNode, {href: '#s' + objId}, NS_XLINK);\n                                    t._setStyle(useNode, obj.fill, obj.line, cxform);\n                                }\n                                node.appendChild(frag);\n                            }else{\n                                var node = t._createElement(\"use\");\n                                t._setAttributes(node, {href: '#s' + objId}, NS_XLINK);\n                                t._setStyle(node, obj.fill, obj.line, cxform);\n                            }\n                            break;\n                        case \"button\":\n                            var states1 = obj.states,\n                                states2 = character._states = {},\n                                btnCxform = obj.cxform;\n                            for(var state in states1){\n                                var list1 = states1[state],\n                                    list2 = states2[state] || (states2[state] = {});\n                                for(var depth in list1){\n                                    var stateCharacter = list2[depth] = cloneCharacter(list1[depth]);\n                                    t._cast(stateCharacter, cxform1 || btnCxform);\n                                }\n                            }\n                            break;\n                        case \"text\":\n                            var strings = obj.strings,\n                                numStrings = strings.length,\n                                frag = doc.createDocumentFragment(),\n                                matrix = cloneMatrix(obj.matrix);\n                            for(var i = 0; i < numStrings; i++){\n                                var useNode = frag.appendChild(t._createElement(\"use\")),\n                                    id = objId + (numStrings > 1 ? '-' + (i + 1) : ''),\n                                    string = strings[i];\n                                t._setAttributes(useNode, {href: '#t' + id}, NS_XLINK);\n                                t._setStyle(useNode, string.fill, null, cxform);\n                            }\n                            if(strings.length > 1){\n                                var node = t._createElement('g');\n                                node.appendChild(frag);\n                            }else{ var node = frag.firstChild; }\n                            matrix.scaleY *= -1;\n                            attrs.transform = matrix2string(matrix);\n                            break;\n                    }\n                    if(node){\n                        t._setAttributes(node, attrs);\n                        t._defs.appendChild(node);\n                        t._set[characterId] = {\n                            character: character,\n                            node: node\n                        };\n                    }\n                }\n            }\n            return t;\n        },\n        \n        _setStyle: function(node, fill, line, cxform){\n            var t = this,\n                attrs = {};\n            if(fill){\n                var type = fill.type;\n                if(fill.type){\n                    var fillNode = t._defs.appendChild(t._buildFill(fill, cxform));\n                    attrs.fill = \"url(#\" + fillNode.id + ')';\n                }else{\n                    var color = cxform ? transformColor(fill, cxform) : fill,\n                        alpha = color.alpha;\n                    attrs.fill = color2string(color);\n                    if(undefined != alpha && alpha < 1){ attrs[\"fill-opacity\"] = alpha; }\n                }\n            }else{ attrs.fill = \"none\"; }\n            if(line){\n                var color = cxform ? transformColor(line.color, cxform) : line.color,\n                    alpha = color.alpha;\n                attrs.stroke = color2string(color);\n                attrs[\"stroke-width\"] = max(line.width, 20);\n                if(undefined != alpha && alpha < 1){ attr[\"stroke-opacity\"] = alpha; }\n            }\n            t._setAttributes(node, attrs);\n            return t;\n        },\n        \n        _buildFill: function(fill, cxform){\n            var t = this,\n                f = t._fills,\n                id = objectId({\n                    fill: fill,\n                    cxform: cxform\n                }),\n                node = f[id];\n            if(!node){\n                var type = fill.type,\n                    attrs = {id: type[0] + id};\n                switch(type){\n                    case \"linear\":\n                    case \"radial\":\n                        var node = t._createElement(type + \"Gradient\"),\n                            s = Gordon.spreadModes,\n                            i = Gordon.interpolationModes,\n                            stops = fill.stops;\n                        attrs.gradientUnits = \"userSpaceOnUse\";\n                        attrs.gradientTransform = matrix2string(fill.matrix);\n                        if(\"linear\" == type){ \n                            attrs.x1 = -819.2;\n                            attrs.x2 = 819.2;\n                        }else{\n                            attrs.cx = attrs.cy = 0;\n                            attrs.r = 819.2;\n                        }\n                        switch(fill.spread){\n                            case s.REFLECT:\n                                attrs.spreadMethod = \"reflect\";\n                                break;\n                            case s.REPEAT:\n                                attrs.spreadMethod = \"repeat\";\n                                break;\n                        }\n                        if(fill.interpolation == i.LINEAR_RGB){ attrs[\"color-interpolation\"] = \"linearRGB\"; }\n                        stops.forEach(function(stop){\n                            var stopNode = node.appendChild(t._createElement(\"stop\")),\n                                color = cxform ? transformColor(stop.color, cxform) : stop.color;\n                            t._setAttributes(stopNode, {\n                                offset: stop.offset,\n                                \"stop-color\": color2string(color),\n                                \"stop-opacity\": \"alpha\" in color ? 1 : color.alpha\n                            });\n                        });\n                        break;\n                    case \"pattern\":\n                        var node = t._createElement(\"pattern\"),\n                            fillImg = fill.image,\n                            width = fillImg.width,\n                            height = fillImg.height;\n                        if(cxform){\n                            var img = new Image(),\n                                origin = doc.getElementById('i' + fillImg.id),\n                                canvas = doc.createElement(\"canvas\"),\n                                ctx = canvas.getContext(\"2d\"),\n                                imgNode = node.appendChild(t._createElement(\"image\"));\n                            img.src = origin.getAttribute(\"href\");\n                            canvas.width = width;\n                            canvas.height = height;\n                            ctx.drawImage(img, 0, 0);\n                            var imgData = ctx.getImageData(0, 0, width, height),\n                                pxData = imgData.data,\n                                len = pxData.length,\n                                multR = cxform.multR,\n                                multG = cxform.multG,\n                                multB = cxform.multB,\n                                addR = cxform.addR,\n                                addG = cxform.addG,\n                                addB = cxform.addB;\n                            for(var i = 0; i < len; i+= 4){\n                                pxData[i] = ~~max(0, min((pxData[i] * multR) + addR, 255));\n                                pxData[i + 1] = ~~max(0, min((pxData[i + 1] * multG) + addG, 255));\n                                pxData[i + 2] = ~~max(0, min((pxData[i + 2] * multB) + addB, 255));\n                            }\n                            ctx.putImageData(imgData, 0, 0);\n                            t._setAttributes(imgNode, {href: canvas.toDataURL()}, NS_XLINK);\n                            t._setAttributes(imgNode, {\n                                width: width,\n                                height: height,\n                                opacity: ~~max(0, min(cxform.multA + cxform.addA, 1))\n                            });\n                        }else{\n                            var useNode = node.appendChild(t._createElement(\"use\"));\n                            t._setAttributes(useNode, {href: \"#i\" + fillImg.id}, NS_XLINK);\n                        }\n                        attrs.patternUnits = \"userSpaceOnUse\";\n                        attrs.patternTransform = matrix2string(fill.matrix);\n                        attrs.width = width;\n                        attrs.height = height;\n                        break;\n                }\n                t._setAttributes(node, attrs);\n                t._fills[id] = node;\n            }\n            return node;\n        },\n        \n        show: function(frmIdx){\n            var t = this,\n                frm = t._timeline[frmIdx],\n                d = frm.displayList;\n            for(var depth in d){\n                var character = d[depth];\n                if(character){ t.place(character); }\n                else{ t.remove(depth); }\n            }\n            return t;\n        },\n        \n        place: function(character){\n            var depth = character.depth,\n                t = this,\n                d = t._displayList,\n                replace = d[depth];\n            if(replace && !character.object){\n                var id = character._id,\n                    node = replace.node,\n                    matrix = character.matrix;\n                if(id != replace.character._id){ t._setAttributes(node, {href: \"#c\" + id}, NS_XLINK); }\n                var matrix = character.matrix;\n                if(matrix && matrix != replace.matrix){ t._setAttributes(node, {transform: matrix2string(matrix)}); }\n            }else{\n                if(character.clipDepth){\n                    var node = t._createElement('g');\n                    t._setAttributes(node, {\"clip-path\": \"url(#p\" + character.object + ')'});\n                }else{ var node = t._prepare(character); }\n                if(replace){ t.remove(depth); }\n                var stage = t._stage;\n                if(1 == depth){ stage.insertBefore(node, stage.firstChild); }\n                else{\n                    var nextDepth = 0;\n                    for(var entry in d){\n                        var c = d[entry].character;\n                        if(c.clipDepth && depth <= c.clipDepth){ stage = d[entry].node; }\n                        if(entry > depth){\n                            nextDepth = entry;\n                            break;\n                        }\n                    }\n                    if(nextDepth){ stage.insertBefore(node, d[nextDepth].node); }\n                    else{ stage.appendChild(node); }\n                }\n            }\n            d[depth] = {\n                character: character,\n                node: node\n            };\n            return t;\n        },\n        \n        _prepare: function(character){\n            var t = this,\n                obj = t._dictionary[character.object].object,\n                type = obj.type,\n                node = null,\n                matrix = character.matrix;\n            switch(type){\n                case \"button\":\n                    var node = t._createElement('g'),\n                        states = character._states,\n                        btnCxform = obj.cxform,\n                        hitNode = null,\n                        stateNodes = {},\n                        frag = doc.createDocumentFragment(),\n                        style = doc.body.style,\n                        currState = b.UP,\n                        m = Gordon.mouseButtons,\n                        isMouseOver = false,\n                        action = obj.action,\n                        trackAsMenu = obj.trackAsMenu;\n                    for(var state in states){\n                        var stateFrag = doc.createDocumentFragment(),\n                            list = states[state];\n                        for(var depth in list){ stateFrag.appendChild(t._prepare(list[depth])); }\n                        if(stateFrag.length > 1){\n                            var stateNode = t._createElement('g');\n                            stateNode.appendChild(stateFrag);\n                        }else{ var stateNode = stateFrag.firstChild; }\n                        if(state == b.HIT){\n                            t._setAttributes(stateNode, {opacity: 0});\n                            hitNode = stateNode;\n                        }else{\n                            t._setAttributes(stateNode, {visibility: state == b.UP ? \"visible\" : \"hidden\"});\n                            stateNodes[state] = frag.appendChild(stateNode);\n                        }\n                    }\n                    node.appendChild(frag);\n                    node.appendChild(hitNode);\n                    \n                    function setState(state){\n                        if(state == b.UP){ style.cursor = setState._cursor || \"default\"; }\n                        else{\n                            setState._cursor = style.cursor;\n                            style.cursor = \"pointer\";\n                        }\n                        t._setAttributes(stateNodes[currState], {visibility: \"hidden\"});\n                        t._setAttributes(stateNodes[state], {visibility: \"visible\"});\n                        currState = state;\n                    };\n                    \n                    hitNode.onmouseover = function(){\n                        if(!(buttonMask & m.LEFT)){ setState(b.OVER); }\n                        else if(this == t.eventTarget){ setState(b.DOWN); }\n                        return false;\n                    }\n                    \n                    hitNode.onmousedown = function(){\n                        t.eventTarget = this;\n                        setState(b.DOWN);\n                        var handle = doc.addEventListener(\"mouseup\", function(){\n                            setState(b.UP);\n                            doc.removeEventListener(\"mouseup\", handle, true);\n                            t.eventTarget = null;\n                        }, true);\n                        return false;\n                    }\n                    \n                    hitNode.onmouseup = function(){\n                        setState(b.OVER);\n                        if(this == t.eventTarget){\n                            if(action){ action(); }\n                            t.eventTarget = null;\n                        }\n                        return false;\n                    }\n                    \n                    hitNode.onmouseout = function(){\n                        if(this == t.eventTarget){\n                            if(trackAsMenu){\n                                t.eventTarget = null;\n                                setState(b.UP);\n                            }else{ setState(b.OVER); }\n                        }\n                        else{ setState(b.UP); }\n                        return false;\n                    }\n                    break;\n                default:\n                    var node = t._createElement(\"use\");\n                    t._setAttributes(node, {href: \"#c\" + character._id}, NS_XLINK);\n            }\n            if(matrix){ t._setAttributes(node, {transform: matrix2string(matrix)}); }\n            return node;\n        },\n        \n        remove: function(depth){\n            var d = this._displayList,\n                item = d[depth],\n                node = item.node,\n                parentNode = node.parentNode;\n            if(item.character.clipDepth){\n                var childNodes = node.childNodes;\n                for(var c in childNodes){ parentNode.insertBefore(childNodes[c], node); }\n            }\n            parentNode.removeChild(node);\n            delete d[depth];\n            return this;\n        }\n    };\n    \n    var REGEXP_IS_COLOR = /^([\\da-f]{1,2}){3}$/i;\n    \n    function color2string(color){\n        if(\"string\" == typeof color){ return REGEXP_IS_COLOR.test(color) ? color : null; }\n        return \"rgb(\" + [color.red, color.green, color.blue] + ')';\n    }\n    \n    function matrix2string(matrix){\n        return \"matrix(\" + [\n            matrix.scaleX, matrix.skewX,\n            matrix.skewY, matrix.scaleY,\n            matrix.moveX, matrix.moveY\n        ] + ')';\n    }\n    \n    function transformColor(color, cxform){\n        return {\n            red: ~~max(0, min((color.red * cxform.multR) + cxform.addR, 255)),\n            green: ~~max(0, min((color.green * cxform.multG) + cxform.addG, 255)),\n            blue: ~~max(0, min((color.blue * cxform.multB) + cxform.addB, 255)),\n            alpha: ~~max(0, min((color.alpha * cxform.multA) + cxform.addA, 255))\n        }\n    }\n    \n    function objectId(obj){\n        var memo = objectId._memo || (objectId._memo = {}),\n            nextId = (objectId._nextId || (objectId._nextId = 1)),\n            key = object2key(obj),\n            origId = memo[key];\n        if(!origId){ memo[key] = nextId; }\n        return origId || objectId._nextId++;\n    }\n    \n    function object2key(obj){\n        var a = 1,\n            b = 0;\n        for(var prop in obj){\n            var val = obj[prop];\n            if(\"object\" == typeof val){ a += object2key(val); }\n            else{\n                var buff = '' + val;\n                for(var j = 0; buff[j]; j++){\n                    a = (a + buff.charCodeAt(j)) % 65521;\n                    b = (b + a) % 65521;\n                }\n            }\n        }\n        return (b << 16) | a;\n    }\n    \n    function concatCxform(cxform1, cxform2){\n        return{\n            multR: cxform1.multR * cxform2.multR, multG: cxform1.multG * cxform2.multG,\n            multB: cxform1.multB * cxform2.multB, multA: cxform1.multA * cxform2.multA,\n            addR: cxform1.addR + cxform2.addR, addG: cxform1.addG + cxform2.addG,\n            addB: cxform1.addB + cxform2.addB, addA: cxform1.addA + cxform2.addA\n        }\n    }\n    \n    function cloneCharacter(character){\n        return {\n            object: character.object,\n            depth: character.depth,\n            matrix: character.matrix,\n            cxform: character.cxform\n        };\n    }\n    \n    function cloneMatrix(matrix){\n        return {\n            scaleX: matrix.scaleX, scaleY: matrix.scaleY,\n            skewX: matrix.skewX, skewY: matrix.skewY,\n            moveX: matrix.moveX, moveY: matrix.moveY\n        };\n    }\n    \n    if(doc){\n        doc.addEventListener(\"mousedown\", function(e){\n            buttonMask |= 0x01 << e.button;\n        }, true);\n        doc.addEventListener(\"mouseup\", function(e){\n            buttonMask ^= 0x01 << e.button;\n        }, true);\n    }\n})();\n"
  },
  {
    "path": "src/renderer/vml.js",
    "content": "/* TODO */\n"
  },
  {
    "path": "src/renderer/webgl.js",
    "content": "/* TODO */\n"
  },
  {
    "path": "src/stream.js",
    "content": "(function(){\n    var DEFLATE_CODE_LENGTH_ORDER = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15],\n        DEFLATE_CODE_LENGHT_MAP = [\n            [0, 3], [0, 4], [0, 5], [0, 6], [0, 7], [0, 8], [0, 9], [0, 10], [1, 11], [1, 13], [1, 15], [1, 17],\n            [2, 19], [2, 23], [2, 27], [2, 31], [3, 35], [3, 43], [3, 51], [3, 59], [4, 67], [4, 83], [4, 99],\n            [4, 115], [5, 131], [5, 163], [5, 195], [5, 227], [0, 258]\n        ],\n        DEFLATE_DISTANCE_MAP = [\n            [0, 1], [0, 2], [0, 3], [0, 4], [1, 5], [1, 7], [2, 9], [2, 13], [3, 17], [3, 25], [4, 33], [4, 49],\n            [5, 65], [5, 97], [6, 129], [6, 193], [7, 257], [7, 385], [8, 513], [8, 769], [9, 1025], [9, 1537],\n            [10, 2049], [10, 3073], [11, 4097], [11, 6145], [12, 8193], [12, 12289], [13, 16385], [13, 24577]\n        ];\n    \n    Gordon.Stream = function(data){\n        var buff = [],\n            t = this,\n            i = t.length = data.length;\n        t.offset = 0;\n        for(var i = 0; data[i]; i++){ buff.push(fromCharCode(data.charCodeAt(i) & 0xff)); }\n        t._buffer = buff.join('');\n        t._bitBuffer = null;\n        t._bitOffset = 8;\n    };\n    Gordon.Stream.prototype = {\n        readByteAt: function(pos){\n            return this._buffer.charCodeAt(pos);\n        },\n        \n        readNumber: function(numBytes, bigEnd){\n            var t = this,\n                val = 0;\n            if(bigEnd){\n                while(numBytes--){ val = (val << 8) | t.readByteAt(t.offset++); }\n            }else{\n                var o = t.offset,\n                    i = o + numBytes;\n                while(i > o){ val = (val << 8) | t.readByteAt(--i); }\n                t.offset += numBytes;\n            }\n            t.align();\n            return val;\n        },\n        \n        readSNumber: function(numBytes, bigEnd){\n            var val = this.readNumber(numBytes, bigEnd),\n                numBits = numBytes * 8;\n            if(val >> (numBits - 1)){ val -= Math.pow(2, numBits); }\n            return val;\n        },\n        \n        readSI8: function(){\n            return this.readSNumber(1);\n        },\n        \n        readSI16: function(bigEnd){\n            return this.readSNumber(2, bigEnd);\n        },\n        \n        readSI32: function(bigEnd){\n            return this.readSNumber(4, bigEnd);\n        },\n        \n        readUI8: function(){\n            return this.readNumber(1);\n        },\n        \n        readUI16: function(bigEnd){\n            return this.readNumber(2, bigEnd);\n        },\n        \n        readUI24: function(bigEnd){\n            return this.readNumber(3, bigEnd);\n        },\n        \n        readUI32: function(bigEnd){\n            return this.readNumber(4, bigEnd);\n        },\n        \n        readFixed: function(){\n            return this._readFixedPoint(32, 16);\n        },\n        \n        _readFixedPoint: function(numBits, precision){\n            return this.readSB(numBits) * Math.pow(2, -precision);\n        },\n        \n        readFixed8: function(){\n            return this._readFixedPoint(16, 8);\n        },\n        \n        readFloat: function(){\n            return this._readFloatingPoint(8, 23);\n        },\n        \n        _readFloatingPoint: function(numEBits, numSBits){\n            var numBits = 1 + numEBits + numSBits,\n                numBytes = numBits / 8,\n                t = this,\n                val = 0.0;\n            if(numBytes > 4){\n                var i = Math.ceil(numBytes / 4);\n                while(i--){\n                    var buff = [],\n                        o = t.offset,\n                        j = o + (numBytes >= 4 ? 4 : numBytes % 4);\n                    while(j > o){\n                        buff.push(t.readByteAt(--j));\n                        numBytes--;\n                        t.offset++;\n                    }\n                }\n                var s = new Gordon.Stream(fromCharCode.apply(String, buff)),\n                    sign = s.readUB(1),\n                    expo = s.readUB(numEBits),\n                    mantis = 0,\n                    i = numSBits;\n                while(i--){\n                    if(s.readBool()){ mantis += Math.pow(2, i); }\n                }\n            }else{\n                var sign = t.readUB(1),\n                    expo = t.readUB(numEBits),\n                    mantis = t.readUB(numSBits);\n            }\n            if(sign || expo || mantis){\n                var maxExpo = Math.pow(2, numEBits),\n                    bias = ~~((maxExpo - 1) / 2),\n                    scale = Math.pow(2, numSBits),\n                    fract = mantis / scale;\n                if(bias){\n                    if(bias < maxExpo){ val = Math.pow(2, expo - bias) * (1 + fract); }\n                    else if(fract){ val = NaN; }\n                    else{ val = Infinity; }\n                }else if(fract){ val = Math.pow(2, 1 - bias) * fract; }\n                if(NaN != val && sign){ val *= -1; }\n            }\n            return val;\n        },\n        \n        readFloat16: function(){\n            return this._readFloatingPoint(5, 10);\n        },\n        \n        readDouble: function(){\n            return this._readFloatingPoint(11, 52);\n        },\n        \n        readEncodedU32: function(){\n            var val = 0;\n            for(var i = 0; i < 5; i++){\n                var num = this.readByteAt(this._offset++);\n                val = val | ((num & 0x7f) << (7 * i));\n                if(!(num & 0x80)){ break; }\n            }\n            return val;\n        },\n        \n        readSB: function(numBits){\n            var val = this.readUB(numBits);\n            if(val >> (numBits - 1)){ val -= Math.pow(2, numBits); }\n            return val;\n        },\n        \n        readUB: function(numBits, lsb){\n            var t = this,\n                val = 0;\n            for(var i = 0; i < numBits; i++){\n                if(8 == t._bitOffset){\n                    t._bitBuffer = t.readUI8();\n                    t._bitOffset = 0;\n                }\n                if(lsb){ val |= (t._bitBuffer & (0x01 << t._bitOffset++) ? 1 : 0) << i; }\n                else{ val = (val << 1) | (t._bitBuffer & (0x80 >> t._bitOffset++) ? 1 : 0); }\n            }\n            return val;\n        },\n        \n        readFB: function(numBits){\n            return this._readFixedPoint(numBits, 16);\n        },\n        \n        readString: function(numChars){\n            var t = this,\n                b = t._buffer;\n            if(undefined != numChars){\n                var str = b.substr(t.offset, numChars);\n                t.offset += numChars;\n            }else{\n                var chars = [],\n                    i = t.length - t.offset;\n                while(i--){\n                    var code = t.readByteAt(t.offset++);\n                    if(code){ chars.push(fromCharCode(code)); }\n                    else{ break; }\n                }\n                var str = chars.join('');\n            }\n            return str;\n        },\n        \n        readBool: function(numBits){\n            return !!this.readUB(numBits || 1);\n        },\n        \n        seek: function(offset, absolute){\n            var t = this;\n            t.offset = (absolute ? 0 : t.offset) + offset;\n            t.align();\n            return t;\n        },\n        \n        align: function(){\n            this._bitBuffer = null;\n            this._bitOffset = 8;\n            return this;\n        },\n        \n        readLanguageCode: function(){\n            return this.readUI8();\n        },\n        \n        readRGB: function(){\n            return {\n                red: this.readUI8(),\n                green: this.readUI8(),\n                blue: this.readUI8()\n            }\n        },\n        \n        readRGBA: function(){\n            var rgba = this.readRGB();\n            rgba.alpha = this.readUI8() / 255;\n            return rgba;\n        },\n        \n        readARGB: function(){\n            var alpha = this.readUI8() / 255,\n                rgba = this.readRGB();\n            rgba.alpha = alpha;\n            return rgba;\n        },\n        \n        readRect: function(){\n            var t = this;\n                numBits = t.readUB(5),\n                rect = {\n                    left: t.readSB(numBits),\n                    right: t.readSB(numBits),\n                    top: t.readSB(numBits),\n                    bottom: t.readSB(numBits)\n                };\n            t.align();\n            return rect;\n        },\n        \n        readMatrix: function(){\n            var t = this,\n                hasScale = t.readBool();\n            if(hasScale){\n                var numBits = t.readUB(5),\n                    scaleX = t.readFB(numBits),\n                    scaleY = t.readFB(numBits);\n            }else{ var scaleX = scaleY = 1.0; }\n            var hasRotation = t.readBool();\n            if(hasRotation){\n                var numBits = t.readUB(5),\n                    skewX = t.readFB(numBits),\n                    skewY = t.readFB(numBits);\n            }else{ var skewX =  skewY = 0.0; }\n            var numBits = t.readUB(5);\n                matrix = {\n                    scaleX: scaleX, scaleY: scaleY,\n                    skewX: skewX, skewY: skewY,\n                    moveX: t.readSB(numBits), moveY: t.readSB(numBits)\n                };\n            t.align();\n            return matrix;\n        },\n        \n        readCxform: function(){\n            return this._readCxf();\n        },\n        \n        readCxformA: function(){\n            return this._readCxf(true);\n        },\n        \n        _readCxf: function(withAlpha){\n            var t = this;\n                hasAddTerms = t.readBool(),\n                hasMultTerms = t.readBool(),\n                numBits = t.readUB(4);\n            if(hasMultTerms){\n                var multR = t.readSB(numBits) / 256,\n                    multG = t.readSB(numBits) / 256,\n                    multB = t.readSB(numBits) / 256,\n                    multA = withAlpha ? t.readSB(numBits) / 256 : 1;\n            }else{ var multR = multG = multB = multA = 1; }\n            if(hasAddTerms){\n                var addR = t.readSB(numBits),\n                    addG = t.readSB(numBits),\n                    addB = t.readSB(numBits),\n                    addA = withAlpha ? t.readSB(numBits) / 256 : 0;\n            }else{ var addR = addG = addB = addA = 0; }\n            var cxform = {\n                multR: multR, multG: multG, multB: multB, multA: multA,\n                addR: addR, addG: addG, addB: addB, addA: addA\n            }\n            t.align();\n            return cxform;\n        },\n        \n        decompress: function(){\n            var t = this,\n                b = t._buffer,\n                o = t.offset,\n                data = b.substr(0, o) + t.unzip();\n            t.length = data.length;\n            t.offset = o;\n            t._buffer = data;\n            return t;\n        },\n        \n        unzip: function uz(raw){\n            var t = this,\n                buff = [],\n                o = DEFLATE_CODE_LENGTH_ORDER,\n                m = DEFLATE_CODE_LENGHT_MAP,\n                d = DEFLATE_DISTANCE_MAP;\n            t.seek(2);\n            do{\n                var isFinal = t.readUB(1, true),\n                    type = t.readUB(2, true);\n                if(type){\n                    if(1 == type){\n                        var distTable = uz.fixedDistTable,\n                            litTable = uz.fixedLitTable;\n                        if(!distTable){\n                            var bitLengths = [];\n                            for(var i = 0; i < 32; i++){ bitLengths.push(5); }\n                            distTable = uz.fixedDistTable = buildHuffTable(bitLengths);\n                        }\n                        if(!litTable){\n                            var bitLengths = [];\n                            for(var i = 0; i <= 143; i++){ bitLengths.push(8); }\n                            for(; i <= 255; i++){ bitLengths.push(9); }\n                            for(; i <= 279; i++){ bitLengths.push(7); }\n                            for(; i <= 287; i++){ bitLengths.push(8); }\n                            litTable = uz.fixedLitTable = buildHuffTable(bitLengths);\n                        }\n                    }else{\n                        var numLitLengths = t.readUB(5, true) + 257,\n                            numDistLengths = t.readUB(5, true) + 1,\n                            numCodeLenghts = t.readUB(4, true) + 4,\n                            codeLengths = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];\n                        for(var i = 0; i < numCodeLenghts; i++){ codeLengths[o[i]] = t.readUB(3, true); }\n                        var codeTable = buildHuffTable(codeLengths),\n                            litLengths = [],\n                            prevCodeLen = 0,\n                            maxLengths = numLitLengths + numDistLengths;\n                        while(litLengths.length < maxLengths){\n                            var sym = decodeSymbol(t, codeTable);\n                            switch(sym){\n                                case 16:\n                                    var i = t.readUB(2, true) + 3;\n                                    while(i--){ litLengths.push(prevCodeLen); }\n                                    break;\n                                case 17:\n                                    var i = t.readUB(3, true) + 3;\n                                    while(i--){ litLengths.push(0); }\n                                    break;\n                                case 18:\n                                    var i = t.readUB(7, true) + 11;\n                                    while(i--){ litLengths.push(0); }\n                                    break;\n                                default:\n                                    if(sym <= 15){\n                                        litLengths.push(sym);\n                                        prevCodeLen = sym;\n                                    }\n                            }\n                        }\n                        var distTable = buildHuffTable(litLengths.splice(numLitLengths, numDistLengths)),\n                            litTable = buildHuffTable(litLengths);\n                    }\n                    do{\n                        var sym = decodeSymbol(t, litTable);\n                        if(sym < 256){ buff.push(raw ? sym : fromCharCode(sym)); }\n                        else if(sym > 256){\n                            var lengthMap = m[sym - 257],\n                                len = lengthMap[1] + t.readUB(lengthMap[0], true),\n                                distMap = d[decodeSymbol(t, distTable)],\n                                dist = distMap[1] + t.readUB(distMap[0], true),\n                                i = buff.length - dist;\n                            while(len--){ buff.push(buff[i++]); }\n                        }\n                    }while(256 != sym);\n                }else{\n                    t.align();\n                    var len = t.readUI16(),\n                        nlen = t.readUI16();\n                    if(raw){ while(len--){ buff.push(t.readUI8()); } }\n                    else{ buff.push(t.readString(len)); }\n                }\n            }while(!isFinal);\n            t.seek(4);\n            return raw ? buff : buff.join('');\n        }\n    };\n    \n    function buildHuffTable(bitLengths){\n        var numLengths = bitLengths.length,\n            blCount = [],\n            maxBits = max.apply(Math, bitLengths),\n            nextCode = [],\n            code = 0,\n            table = {},\n            i = numLengths;\n        while(i--){\n            var len = bitLengths[i];\n            blCount[len] = (blCount[len] || 0) + (len > 0);\n        }\n        for(var i = 1; i <= maxBits; i++){\n            var len = i - 1;\n            if(undefined == blCount[len]){ blCount[len] = 0; }\n            code = (code + blCount[i - 1]) << 1;\n            nextCode[i] = code;\n        }\n        for(var i = 0; i < numLengths; i++){\n            var len = bitLengths[i];\n            if(len){\n                table[nextCode[len]] = {\n                    length: len,\n                    symbol: i\n                };\n                nextCode[len]++;\n            }\n        }\n        return table;\n    }\n    \n    function decodeSymbol(s, table) {\n        var code = 0,\n            len = 0;\n        while(true){\n            code = (code << 1) | s.readUB(1, true);\n            len++;\n            var entry = table[code];\n            if(undefined != entry && entry.length == len){ return entry.symbol }\n        }\n    }\n})();\n"
  }
]