merge mozilla-central to holly
authorJared Wein <jwein@mozilla.com>
Wed, 27 Nov 2013 10:44:40 -0500
changeset 224496 b1c32805287ea580d0185b94e424efc2fbf0c986
parent 224493 f58b1b0c9973ad44f4e76a02c7a5b00e401eabf5 (current diff)
parent 224495 8871345304814b1a4881f3e94a2d46cc668279d9 (diff)
child 224497 bd11e7e8a63eb48a2d8aed436d3ed7859e1fbc6b
push id6
push userryanvm@gmail.com
push dateMon, 12 Jan 2015 22:04:06 +0000
treeherdermozilla-b2g37_v2_2@895c8fc7b734 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone28.0a1
merge mozilla-central to holly
CLOBBER
accessible/src/jsat/tick.wav
browser/components/places/content/browserPlacesViews.js
browser/devtools/shadereditor/test/browser_se_programs-blackbox.js
browser/devtools/shadereditor/test/browser_se_programs-highlight.js
gfx/layers/ThebesLayerBuffer.cpp
gfx/layers/ThebesLayerBuffer.h
gfx/layers/opengl/CanvasLayerOGL.cpp
gfx/layers/opengl/CanvasLayerOGL.h
gfx/layers/opengl/ColorLayerOGL.cpp
gfx/layers/opengl/ColorLayerOGL.h
gfx/layers/opengl/ContainerLayerOGL.cpp
gfx/layers/opengl/ContainerLayerOGL.h
gfx/layers/opengl/ImageLayerOGL.cpp
gfx/layers/opengl/ImageLayerOGL.h
gfx/layers/opengl/LayerManagerOGL.cpp
gfx/layers/opengl/LayerManagerOGL.h
gfx/layers/opengl/LayerManagerOGLProgram.cpp
gfx/layers/opengl/LayerManagerOGLProgram.h
gfx/layers/opengl/LayerManagerOGLShaders.h
gfx/layers/opengl/LayerManagerOGLShaders.txt
gfx/layers/opengl/ThebesLayerOGL.cpp
gfx/layers/opengl/ThebesLayerOGL.h
security/patches/bug-935831.patch
toolkit/components/telemetry/Histograms.json
widget/cocoa/nsChildView.mm
--- a/CLOBBER
+++ b/CLOBBER
@@ -13,9 +13,9 @@
 #          |               |
 #          O <-- Clobber   O  <-- Clobber
 #
 # Note: The description below will be part of the error message shown to users.
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
-Bug 942207 - apparently need clobber to avoid bustage
+Another Windows WebIDL clobber needed due to bug 928195
--- a/accessible/src/jsat/AccessFu.jsm
+++ b/accessible/src/jsat/AccessFu.jsm
@@ -491,32 +491,35 @@ var Output = {
       this.selectionStart = braille.selectionStart = aSelection.selectionStart + this.startOffset;
       this.selectionEnd = braille.selectionEnd = aSelection.selectionEnd + this.startOffset;
 
       return braille;
     }
   },
 
   speechHelper: {
-    EARCONS: ['chrome://global/content/accessibility/tick.wav'],
+    EARCONS: ['virtual_cursor_move.ogg',
+              'virtual_cursor_key.ogg',
+              'clicked.ogg'],
 
     earconBuffers: {},
 
     inited: false,
 
     webspeechEnabled: false,
 
     init: function init() {
       let window = Utils.win;
       this.webspeechEnabled = !!window.speechSynthesis;
 
       for (let earcon of this.EARCONS) {
-        let earconName = /.*\/(.*)\..*$/.exec(earcon)[1];
+        let earconName = /(^.*)\..*$/.exec(earcon)[1];
         this.earconBuffers[earconName] = new WeakMap();
-        this.earconBuffers[earconName].set(window, new window.Audio(earcon));
+        this.earconBuffers[earconName].set(
+          window, new window.Audio('chrome://global/content/accessibility/' + earcon));
       }
 
       this.inited = true;
     },
 
     output: function output(aActions) {
       if (!this.inited) {
         this.init();
--- a/accessible/src/jsat/EventManager.jsm
+++ b/accessible/src/jsat/EventManager.jsm
@@ -52,18 +52,16 @@ this.EventManager.prototype = {
 
         AccessibilityEventObserver.addListener(this);
 
         this.webProgress.addProgressListener(this,
           (Ci.nsIWebProgress.NOTIFY_STATE_ALL |
            Ci.nsIWebProgress.NOTIFY_LOCATION));
         this.addEventListener('scroll', this, true);
         this.addEventListener('resize', this, true);
-        // XXX: Ideally this would be an a11y event. Bug #742280.
-        this.addEventListener('DOMActivate', this, true);
       }
       this.present(Presentation.tabStateChanged(null, 'newtab'));
 
     } catch (x) {
       Logger.logException(x, 'Failed to start EventManager');
     }
   },
 
@@ -74,43 +72,26 @@ this.EventManager.prototype = {
       return;
     }
     Logger.debug('EventManager.stop');
     AccessibilityEventObserver.removeListener(this);
     try {
       this.webProgress.removeProgressListener(this);
       this.removeEventListener('scroll', this, true);
       this.removeEventListener('resize', this, true);
-      // XXX: Ideally this would be an a11y event. Bug #742280.
-      this.removeEventListener('DOMActivate', this, true);
     } catch (x) {
       // contentScope is dead.
     } finally {
       this._started = false;
     }
   },
 
   handleEvent: function handleEvent(aEvent) {
     try {
       switch (aEvent.type) {
-      case 'DOMActivate':
-      {
-        let activatedAcc =
-          Utils.AccRetrieval.getAccessibleFor(aEvent.originalTarget);
-        let [state, extState] = Utils.getStates(activatedAcc);
-
-        // Checkable objects will have a state changed event that we will use
-        // instead of this hackish DOMActivate. We will also know the true
-        // action that was taken.
-        if (state & Ci.nsIAccessibleStates.STATE_CHECKABLE)
-          return;
-
-        this.present(Presentation.actionInvoked(activatedAcc, 'click'));
-        break;
-      }
       case 'scroll':
       case 'resize':
       {
         // the target could be an element, document or window
         let window = null;
         if (aEvent.target instanceof Ci.nsIDOMWindow)
           window = aEvent.target;
         else if (aEvent.target instanceof Ci.nsIDOMDocument)
--- a/accessible/src/jsat/Presentation.jsm
+++ b/accessible/src/jsat/Presentation.jsm
@@ -15,16 +15,18 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, 'Logger',
   'resource://gre/modules/accessibility/Utils.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'PivotContext',
   'resource://gre/modules/accessibility/Utils.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'UtteranceGenerator',
   'resource://gre/modules/accessibility/OutputGenerator.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'BrailleGenerator',
   'resource://gre/modules/accessibility/OutputGenerator.jsm');
+XPCOMUtils.defineLazyModuleGetter(this, 'Roles',
+  'resource://gre/modules/accessibility/Constants.jsm');
 
 this.EXPORTED_SYMBOLS = ['Presentation'];
 
 /**
  * The interface for all presenter classes. A presenter could be, for example,
  * a speech output module, or a visual cursor indicator.
  */
 function Presenter() {}
@@ -299,16 +301,21 @@ AndroidPresenter.prototype = {
     return {
       type: this.type,
       details: androidEvents
     };
   },
 
   actionInvoked: function AndroidPresenter_actionInvoked(aObject, aActionName) {
     let state = Utils.getStates(aObject)[0];
+
+    // Checkable objects will have a state changed event we will use instead.
+    if (state & Ci.nsIAccessibleStates.STATE_CHECKABLE)
+      return null;
+
     return {
       type: this.type,
       details: [{
         eventType: this.ANDROID_VIEW_CLICKED,
         text: UtteranceGenerator.genForAction(aObject, aActionName),
         checked: !!(state & Ci.nsIAccessibleStates.STATE_CHECKED)
       }]
     };
@@ -446,36 +453,40 @@ SpeechPresenter.prototype = {
   pivotChanged: function SpeechPresenter_pivotChanged(aContext, aReason) {
     if (!aContext.accessible)
       return null;
 
     return {
       type: this.type,
       details: {
         actions: [
-          {method: 'playEarcon', data: 'tick', options: {}},
+          {method: 'playEarcon',
+           data: aContext.accessible.role === Roles.KEY ?
+             'virtual_cursor_key' : 'virtual_cursor_move',
+           options: {}},
           {method: 'speak',
             data: UtteranceGenerator.genForContext(aContext).output.join(' '),
             options: {enqueue: true}}
         ]
       }
     };
   },
 
   actionInvoked: function SpeechPresenter_actionInvoked(aObject, aActionName) {
-    return {
-      type: this.type,
-      details: {
-        actions: [
-          {method: 'speak',
-           data: UtteranceGenerator.genForAction(aObject, aActionName).join(' '),
-           options: {enqueue: false}}
-        ]
-      }
-    };
+    let actions = [];
+    if (aActionName === 'click') {
+      actions.push({method: 'playEarcon',
+                    data: 'clicked',
+                    options: {}});
+    } else {
+      actions.push({method: 'speak',
+                    data: UtteranceGenerator.genForAction(aObject, aActionName).join(' '),
+                    options: {enqueue: false}});
+    }
+    return { type: this.type, details: { actions: actions } };
   },
 
   liveRegion: function SpeechPresenter_liveRegion(aContext, aIsPolite, aIsHide,
     aModifiedText) {
     return {
       type: this.type,
       details: {
         actions: [{
--- a/accessible/src/jsat/content-script.js
+++ b/accessible/src/jsat/content-script.js
@@ -198,16 +198,22 @@ function activateCurrent(aMessage) {
         evt.initMouseEvent(aEventType, true, true, content,
                            x, y, 0, 0, 0, false, false, false, false, 0, null);
         node.dispatchEvent(evt);
       }
 
       dispatchMouseEvent('mousedown');
       dispatchMouseEvent('mouseup');
     }
+
+    if (aAccessible.role !== Roles.KEY) {
+      // Keys will typically have a sound of their own.
+      sendAsyncMessage('AccessFu:Present',
+                       Presentation.actionInvoked(aAccessible, 'click'));
+    }
   }
 
   function moveCaretTo(aAccessible, aOffset) {
     let accText = aAccessible.QueryInterface(Ci.nsIAccessibleText);
     let oldOffset = accText.caretOffset;
     let text = accText.getText(0, accText.characterCount);
 
     if (aOffset >= 0 && aOffset <= accText.characterCount) {
--- a/accessible/src/jsat/jar.mn
+++ b/accessible/src/jsat/jar.mn
@@ -1,8 +1,10 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 toolkit.jar:
     content/global/accessibility/AccessFu.css (AccessFu.css)
     content/global/accessibility/content-script.js (content-script.js)
-    content/global/accessibility/tick.wav (tick.wav)
+    content/global/accessibility/virtual_cursor_move.ogg (sounds/virtual_cursor_move.ogg)
+    content/global/accessibility/virtual_cursor_key.ogg (sounds/virtual_cursor_key.ogg)
+    content/global/accessibility/clicked.ogg (sounds/clicked.ogg)
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..68388018e5e3054e07a9e59fe4dcb5100843f6fc
GIT binary patch
literal 6618
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
aRvi{Ragql>V?WD73_WkD4aB>p75*EAP#^~Y
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b29b55b449519d7f489f4a383a13cf77c663a71d
GIT binary patch
literal 4224
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
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..da97934605c8661999d0ea78e5e4f2bb330b880d
GIT binary patch
literal 5636
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
DKV)pg
deleted file mode 100644
index b40a1bbd0e85afe96f869ef38ac21d5a80344e2d..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -731,18 +731,17 @@ pref("jsloader.reuseGlobal", true);
 pref("font.size.inflation.minTwips", 120);
 // And disable it for lingering master-process UI.
 pref("font.size.inflation.disabledInMasterProcess", true);
 
 // Enable freeing dirty pages when minimizing memory; this reduces memory
 // consumption when applications are sent to the background.
 pref("memory.free_dirty_pages", true);
 
-pref("layout.imagevisibility.enabled", false);
-pref("layout.imagevisibility.enabled_for_browser_elements_only", true);
+pref("layout.imagevisibility.enabled", true);
 pref("layout.imagevisibility.numscrollportwidths", 1);
 pref("layout.imagevisibility.numscrollportheights", 1);
 
 // Enable native identity (persona/browserid)
 pref("dom.identity.enabled", true);
 
 // Wait up to this much milliseconds when orientation changed
 pref("layers.orientation.sync.timeout", 1000);
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,4 +1,4 @@
 {
-    "revision": "70f416f866858cb2068bffa31118fc4b15b482c9", 
+    "revision": "9ba62e3061abd5521ffbbee5386a0654f972f73b", 
     "repo_path": "/integration/gaia-central"
 }
--- a/browser/base/content/browser-charsetmenu.inc
+++ b/browser/base/content/browser-charsetmenu.inc
@@ -1,41 +1,62 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 #filter substitution
 
 #expand <menu id="__ID_PREFIX__charsetMenu"
     label="&charsetMenu.label;"
+#ifndef OMIT_ACCESSKEYS
     accesskey="&charsetMenu.accesskey;"
+#endif
     oncommand="MultiplexHandler(event)"
+#ifdef OMIT_ACCESSKEYS
     onpopupshowing="CharsetMenu.build(event);"
+#else
+    onpopupshowing="CharsetMenu.build(event, true);"
+#endif
     onpopupshown="UpdateMenus(event);">
   <menupopup>
     <menu label="&charsetMenuAutodet.label;"
-          accesskey="&charsetMenuAutodet.accesskey;">
+#ifndef OMIT_ACCESSKEYS
+          accesskey="&charsetMenuAutodet.accesskey;"
+#endif
+        >
       <menupopup>
         <menuitem type="radio"
                   name="detectorGroup"
-                  id="chardet.off"
+#expand           id="__ID_PREFIX__chardet.off"
                   label="&charsetMenuAutodet.off.label;"
-                  accesskey="&charsetMenuAutodet.off.accesskey;"/>
+#ifndef OMIT_ACCESSKEYS
+                  accesskey="&charsetMenuAutodet.off.accesskey;"
+#endif
+                  />
         <menuitem type="radio"
                   name="detectorGroup"
-                  id="chardet.ja_parallel_state_machine"
+#expand           id="__ID_PREFIX__chardet.ja_parallel_state_machine"
                   label="&charsetMenuAutodet.ja.label;"
-                  accesskey="&charsetMenuAutodet.ja.accesskey;"/>
+#ifndef OMIT_ACCESSKEYS
+                  accesskey="&charsetMenuAutodet.ja.accesskey;"
+#endif
+                  />
         <menuitem type="radio"
                   name="detectorGroup"
-                  id="chardet.ruprob"
+#expand           id="__ID_PREFIX__chardet.ruprob"
                   label="&charsetMenuAutodet.ru.label;"
-                  accesskey="&charsetMenuAutodet.ru.accesskey;"/>
+#ifndef OMIT_ACCESSKEYS
+                  accesskey="&charsetMenuAutodet.ru.accesskey;"
+#endif
+                  />
         <menuitem type="radio"
                   name="detectorGroup"
-                  id="chardet.ukprob"
+#expand           id="__ID_PREFIX__chardet.ukprob"
                   label="&charsetMenuAutodet.uk.label;"
-                  accesskey="&charsetMenuAutodet.uk.accesskey;"/>
+#ifndef OMIT_ACCESSKEYS
+                  accesskey="&charsetMenuAutodet.uk.accesskey;"
+#endif
+                  />
       </menupopup>
     </menu>
     <menuseparator/>
   </menupopup>
 </menu>
--- a/browser/components/places/content/browserPlacesViews.js
+++ b/browser/components/places/content/browserPlacesViews.js
@@ -321,20 +321,16 @@ PlacesViewBase.prototype = {
 
         let popup = document.createElement("menupopup");
         popup._placesNode = PlacesUtils.asContainer(aPlacesNode);
 
         if (!this._nativeView) {
           popup.setAttribute("placespopup", "true");
         }
 
-#ifdef XP_MACOSX
-        // No context menu on mac.
-        popup.setAttribute("context", "placesContext");
-#endif
         element.appendChild(popup);
         element.className = "menu-iconic bookmark-item";
 
         this._domNodes.set(aPlacesNode, popup);
       }
       else
         throw "Unexpected node";
 
@@ -983,19 +979,17 @@ PlacesToolbar.prototype = {
             }.bind(this)
           );
         }
 
         let popup = document.createElement("menupopup");
         popup.setAttribute("placespopup", "true");
         button.appendChild(popup);
         popup._placesNode = PlacesUtils.asContainer(aChild);
-#ifndef XP_MACOSX
         popup.setAttribute("context", "placesContext");
-#endif
 
         this._domNodes.set(aChild, popup);
       }
       else if (PlacesUtils.nodeIsURI(aChild)) {
         button.setAttribute("scheme",
                             PlacesUIUtils.guessUrlSchemeForUI(aChild.uri));
       }
     }
--- a/browser/components/sessionstore/src/SessionWorker.js
+++ b/browser/components/sessionstore/src/SessionWorker.js
@@ -82,17 +82,18 @@ let Agent = {
       try {
         let durationMs = Date.now();
         let bytes = File.read(path);
         durationMs = Date.now() - durationMs;
         this.initialState = Decoder.decode(bytes);
 
         return {
           result: this.initialState,
-          telemetry: {FX_SESSION_RESTORE_READ_FILE_MS: durationMs}
+          telemetry: {FX_SESSION_RESTORE_READ_FILE_MS: durationMs,
+                      FX_SESSION_RESTORE_FILE_SIZE_BYTES: bytes.byteLength}
         };
       } catch (ex if isNoSuchFileEx(ex)) {
         // Ignore exceptions about non-existent files.
       }
     }
     // No sessionstore data files found. Return an empty string.
     return {result: ""};
   },
--- a/browser/components/sessionstore/src/TabState.jsm
+++ b/browser/components/sessionstore/src/TabState.jsm
@@ -163,16 +163,21 @@ let TabStateInternal = {
 
     let browser = tab.linkedBrowser;
 
     let promise = Task.spawn(function task() {
       // Collect session history data asynchronously. Also collects
       // text and scroll data.
       let history = yield Messenger.send(tab, "SessionStore:collectSessionHistory");
 
+      // The tab could have been closed while waiting for a response.
+      if (!tab.linkedBrowser) {
+        return;
+      }
+
       // Collect basic tab data, without session history and storage.
       let tabData = this._collectBaseTabData(tab);
 
       // Apply collected data.
       tabData.entries = history.entries;
       if ("index" in history) {
         tabData.index = history.index;
       }
--- a/browser/components/sessionstore/test/content.js
+++ b/browser/components/sessionstore/test/content.js
@@ -24,23 +24,23 @@ addMessageListener("ss-test:notifyObserv
 addMessageListener("ss-test:getStyleSheets", function (msg) {
   let sheets = content.document.styleSheets;
   let titles = Array.map(sheets, ss => [ss.title, ss.disabled]);
   sendSyncMessage("ss-test:getStyleSheets", titles);
 });
 
 addMessageListener("ss-test:enableStyleSheetsForSet", function (msg) {
   content.document.enableStyleSheetsForSet(msg.data);
-  sendSyncMessage("ss-test:enableStyleSheetsForSet");
+  sendAsyncMessage("ss-test:enableStyleSheetsForSet");
 });
 
 addMessageListener("ss-test:enableSubDocumentStyleSheetsForSet", function (msg) {
   let iframe = content.document.getElementById(msg.data.id);
   iframe.contentDocument.enableStyleSheetsForSet(msg.data.set);
-  sendSyncMessage("ss-test:enableSubDocumentStyleSheetsForSet");
+  sendAsyncMessage("ss-test:enableSubDocumentStyleSheetsForSet");
 });
 
 addMessageListener("ss-test:getAuthorStyleDisabled", function (msg) {
   let {authorStyleDisabled} =
     docShell.contentViewer.QueryInterface(Ci.nsIMarkupDocumentViewer);
   sendSyncMessage("ss-test:getAuthorStyleDisabled", authorStyleDisabled);
 });
 
--- a/browser/devtools/markupview/test/browser_inspector_markup_765105_tooltip.js
+++ b/browser/devtools/markupview/test/browser_inspector_markup_765105_tooltip.js
@@ -86,19 +86,16 @@ function testImageTooltip(index) {
   let target = container.editor.tag;
   if (isImg) {
     target = container.editor.getAttributeElement("src");
   }
 
   assertTooltipShownOn(target, () => {
     let images = markup.tooltip.panel.getElementsByTagName("image");
     is(images.length, 1, "Tooltip for [" + TEST_NODES[index] + "] contains an image");
-    if (isImg) {
-      compareImageData(node, images[0].src);
-    }
 
     markup.tooltip.hide();
 
     testImageTooltip(index + 1);
   });
 }
 
 function compareImageData(img, imgData) {
--- a/browser/devtools/netmonitor/netmonitor-view.js
+++ b/browser/devtools/netmonitor/netmonitor-view.js
@@ -553,16 +553,27 @@ RequestsMenuView.prototype = Heritage.ex
         break;
     }
 
     this.refreshSummary();
     this.refreshZebra();
   },
 
   /**
+   * Removes all network requests and closes the sidebar if open.
+   */
+  clear: function() {
+    NetMonitorView.Sidebar.toggle(false);
+    $("#details-pane-toggle").disabled = true;
+
+    this.empty();
+    this.refreshSummary();
+  },
+
+  /**
    * Predicates used when filtering items.
    *
    * @param object aItem
    *        The filtered item.
    * @return boolean
    *         True if the item should be visible, false otherwise.
    */
   _onHtml: function({ attachment: { mimeType } })
--- a/browser/devtools/netmonitor/netmonitor.xul
+++ b/browser/devtools/netmonitor/netmonitor.xul
@@ -205,16 +205,21 @@
         </button>
         <spacer id="requests-menu-spacer-end"
                 class="requests-menu-footer-spacer"
                 flex="100"/>
         <label id="request-menu-network-summary"
                class="plain requests-menu-footer-label"
                flex="1"
                crop="end"/>
+        <button id="requests-menu-clear-button"
+               class="requests-menu-footer-button"
+               onclick="NetMonitorView.RequestsMenu.clear()"
+               label="&netmonitorUI.footer.clear;">
+        </button>
       </hbox>
     </vbox>
 
     <splitter id="splitter" class="devtools-side-splitter"/>
 
     <deck id="details-pane"
           hidden="true">
       <vbox id="custom-pane"
--- a/browser/devtools/netmonitor/test/browser.ini
+++ b/browser/devtools/netmonitor/test/browser.ini
@@ -21,16 +21,17 @@ support-files =
   sjs_sorting-test-server.sjs
   sjs_status-codes-test-server.sjs
   test-image.png
 
 [browser_net_aaa_leaktest.js]
 [browser_net_accessibility-01.js]
 [browser_net_accessibility-02.js]
 [browser_net_autoscroll.js]
+[browser_net_clear.js]
 [browser_net_content-type.js]
 [browser_net_copy_url.js]
 [browser_net_cyrillic-01.js]
 [browser_net_cyrillic-02.js]
 [browser_net_filter-01.js]
 [browser_net_filter-02.js]
 [browser_net_filter-03.js]
 [browser_net_footer-summary.js]
new file mode 100644
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_clear.js
@@ -0,0 +1,76 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if the clear button empties the request menu.
+ */
+
+function test() {
+  initNetMonitor(SIMPLE_URL).then(([aTab, aDebuggee, aMonitor]) => {
+    info("Starting test... ");
+
+    let { document, $, NetMonitorView } = aMonitor.panelWin;
+    let { RequestsMenu } = NetMonitorView;
+    let detailsPane = $("#details-pane");
+    let detailsPaneToggleButton = $('#details-pane-toggle');
+    let clearButton = $('#requests-menu-clear-button');
+
+    RequestsMenu.lazyUpdate = false;
+
+    // Make sure we start in a sane state
+    assertNoRequestState(RequestsMenu, detailsPaneToggleButton);
+
+    // Load one request and assert it shows up in the lis
+    aMonitor.panelWin.once(aMonitor.panelWin.EVENTS.NETWORK_EVENT, () => {
+      assertSingleRequestState(RequestsMenu, detailsPaneToggleButton);
+
+      // Click clear and make sure the requests are gone
+      EventUtils.sendMouseEvent({ type: "click" }, clearButton);
+      assertNoRequestState(RequestsMenu, detailsPaneToggleButton);
+
+      // Load a second request and make sure they still show up
+      aMonitor.panelWin.once(aMonitor.panelWin.EVENTS.NETWORK_EVENT, () => {
+        assertSingleRequestState(RequestsMenu, detailsPaneToggleButton);
+
+        // Make sure we can now open the details pane
+        NetMonitorView.toggleDetailsPane({ visible: true, animated: false });
+        ok(!detailsPane.hasAttribute("pane-collapsed") &&
+          !detailsPaneToggleButton.hasAttribute("pane-collapsed"),
+          "The details pane should be visible after clicking the toggle button.");
+
+        // Click clear and make sure the details pane closes
+        EventUtils.sendMouseEvent({ type: "click" }, clearButton);
+        assertNoRequestState(RequestsMenu, detailsPaneToggleButton);
+        ok(detailsPane.hasAttribute("pane-collapsed") &&
+          detailsPaneToggleButton.hasAttribute("pane-collapsed"),
+          "The details pane should not be visible clicking 'clear'.");
+
+        teardown(aMonitor).then(finish);
+      });
+
+      aDebuggee.location.reload();
+    });
+
+    aDebuggee.location.reload();
+  });
+
+  /**
+   * Asserts the state of the network monitor when one request has loaded
+   */
+  function assertSingleRequestState(RequestsMenu, detailsPaneToggleButton) {
+    is(RequestsMenu.itemCount, 1,
+      "The request menu should have one item at this point.");
+    is(detailsPaneToggleButton.hasAttribute("disabled"), false,
+      "The pane toggle button should be enabled after a request is made.");
+  }
+
+  /**
+   * Asserts the state of the network monitor when no requests have loaded
+   */
+  function assertNoRequestState(RequestsMenu, detailsPaneToggleButton) {
+    is(RequestsMenu.itemCount, 0,
+      "The request menu should be empty at this point.");
+    is(detailsPaneToggleButton.hasAttribute("disabled"), true,
+      "The pane toggle button should be disabled when the request menu is cleared.");
+  }
+}
--- a/browser/devtools/scratchpad/test/browser_scratchpad_ui.js
+++ b/browser/devtools/scratchpad/test/browser_scratchpad_ui.js
@@ -30,28 +30,27 @@ function runTests()
     "sp-text-inspect": "inspect",
     "sp-text-display": "display",
     "sp-text-reloadAndRun" : "reloadAndRun",
     "sp-menu-content": "setContentContext",
     "sp-menu-browser": "setBrowserContext",
   };
 
   let lastMethodCalled = null;
-  sp.__noSuchMethod__ = function(aMethodName) {
-    lastMethodCalled = aMethodName;
-  };
 
   for (let id in methodsAndItems) {
     lastMethodCalled = null;
 
     let methodName = methodsAndItems[id];
     let oldMethod = sp[methodName];
     ok(oldMethod, "found method " + methodName + " in Scratchpad object");
 
-    delete sp[methodName];
+    sp[methodName] = () => {
+      lastMethodCalled = methodName;
+    }
 
     let menu = doc.getElementById(id);
     ok(menu, "found menuitem #" + id);
 
     try {
       menu.doCommand();
     }
     catch (ex) {
@@ -59,12 +58,10 @@ function runTests()
     }
 
     ok(lastMethodCalled == methodName,
        "method " + methodName + " invoked by the associated menuitem");
 
     sp[methodName] = oldMethod;
   }
 
-  delete sp.__noSuchMethod__;
-
   finish();
 }
--- a/browser/devtools/shadereditor/shadereditor.js
+++ b/browser/devtools/shadereditor/shadereditor.js
@@ -27,17 +27,17 @@ const EVENTS = {
   // When the vertex and fragment sources were shown in the editor.
   SOURCES_SHOWN: "ShaderEditor:SourcesShown",
 
   // When a shader's source was edited and compiled via the editor.
   SHADER_COMPILED: "ShaderEditor:ShaderCompiled"
 };
 
 const STRINGS_URI = "chrome://browser/locale/devtools/shadereditor.properties"
-const HIGHLIGHT_COLOR = [1, 0, 0, 1]; // rgba
+const HIGHLIGHT_TINT = [1, 0, 0.25, 1]; // rgba
 const TYPING_MAX_DELAY = 500; // ms
 const SHADERS_AUTOGROW_ITEMS = 4;
 const GUTTER_ERROR_PANEL_OFFSET_X = 7; // px
 const GUTTER_ERROR_PANEL_DELAY = 100; // ms
 const DEFAULT_EDITOR_CONFIG = {
   gutters: ["errors"],
   lineNumbers: true,
   showAnnotationRuler: true
@@ -292,17 +292,17 @@ let ShadersListView = Heritage.extend(Wi
   },
 
   /**
    * The mouseenter listener for the programs container.
    */
   _onProgramMouseEnter: function(e) {
     let sourceItem = this.getItemForElement(e.target, { noSiblings: true });
     if (sourceItem && !sourceItem.attachment.isBlackBoxed) {
-      sourceItem.attachment.programActor.highlight(HIGHLIGHT_COLOR);
+      sourceItem.attachment.programActor.highlight(HIGHLIGHT_TINT);
 
       if (e instanceof Event) {
         e.preventDefault();
         e.stopPropagation();
       }
     }
   },
 
--- a/browser/devtools/shadereditor/test/browser.ini
+++ b/browser/devtools/shadereditor/test/browser.ini
@@ -1,27 +1,30 @@
 [DEFAULT]
 support-files =
+  doc_blended-geometry.html
   doc_multiple-contexts.html
   doc_overlapping-geometry.html
   doc_shader-order.html
   doc_simple-canvas.html
   head.js
 
 [browser_se_aaa_run_first_leaktest.js]
 [browser_se_bfcache.js]
 [browser_se_editors-contents.js]
 [browser_se_editors-error-gutter.js]
 [browser_se_editors-error-tooltip.js]
 [browser_se_editors-lazy-init.js]
 [browser_se_first-run.js]
 [browser_se_navigation.js]
-[browser_se_programs-blackbox.js]
+[browser_se_programs-blackbox-01.js]
+[browser_se_programs-blackbox-02.js]
 [browser_se_programs-cache.js]
-[browser_se_programs-highlight.js]
+[browser_se_programs-highlight-01.js]
+[browser_se_programs-highlight-02.js]
 [browser_se_programs-list.js]
 [browser_se_shaders-edit-01.js]
 [browser_se_shaders-edit-02.js]
 [browser_se_shaders-edit-03.js]
 [browser_webgl-actor-test-01.js]
 [browser_webgl-actor-test-02.js]
 [browser_webgl-actor-test-03.js]
 [browser_webgl-actor-test-04.js]
rename from browser/devtools/shadereditor/test/browser_se_programs-blackbox.js
rename to browser/devtools/shadereditor/test/browser_se_programs-blackbox-01.js
--- a/browser/devtools/shadereditor/test/browser_se_programs-blackbox.js
+++ b/browser/devtools/shadereditor/test/browser_se_programs-blackbox-01.js
@@ -79,34 +79,34 @@ function ifWebGLSupported() {
   ok(true, "The second program was correctly blackboxed.");
 
   ShadersListView._onProgramMouseEnter({ target: getItemLabel(panel, 0) });
 
   yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas1");
   yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas2");
   yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas1");
   yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas2");
-  ok(true, "Highlighting didn't work while blackboxed (1).");
+  ok(true, "Highlighting shouldn't work while blackboxed (1).");
 
   ShadersListView._onProgramMouseLeave({ target: getItemLabel(panel, 0) });
   ShadersListView._onProgramMouseEnter({ target: getItemLabel(panel, 1) });
 
   yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas1");
   yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas2");
   yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas1");
   yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas2");
-  ok(true, "Highlighting didn't work while blackboxed (2).");
+  ok(true, "Highlighting shouldn't work while blackboxed (2).");
 
   ShadersListView._onProgramMouseLeave({ target: getItemLabel(panel, 1) });
 
   yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas1");
   yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas2");
   yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas1");
   yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 0, b: 0, a: 255 }, true, "#canvas2");
-  ok(true, "Highlighting didn't work while blackboxed (3).");
+  ok(true, "Highlighting shouldn't work while blackboxed (3).");
 
   getBlackBoxCheckbox(panel, 0).click();
   getBlackBoxCheckbox(panel, 1).click();
 
   ok(!ShadersListView.selectedAttachment.isBlackBoxed,
     "The first program should now be unblackboxed.");
   is(getBlackBoxCheckbox(panel, 0).checked, true,
     "The first blackbox checkbox should now be rechecked.");
@@ -128,19 +128,19 @@ function ifWebGLSupported() {
   yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
   yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
   ok(true, "The first program was correctly highlighted.");
 
   ShadersListView._onProgramMouseLeave({ target: getItemLabel(panel, 0) });
   ShadersListView._onProgramMouseEnter({ target: getItemLabel(panel, 1) });
 
   yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
-  yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas2");
+  yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 64, a: 255 }, true, "#canvas2");
   yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
-  yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas2");
+  yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 0, b: 64, a: 255 }, true, "#canvas2");
   ok(true, "The second program was correctly highlighted.");
 
   ShadersListView._onProgramMouseLeave({ target: getItemLabel(panel, 1) });
 
   yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
   yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
   yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
   yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
new file mode 100644
--- /dev/null
+++ b/browser/devtools/shadereditor/test/browser_se_programs-blackbox-02.js
@@ -0,0 +1,67 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if blackboxing a program works properly in tandem with blended
+ * overlapping geometry.
+ */
+
+function ifWebGLSupported() {
+  let [target, debuggee, panel] = yield initShaderEditor(BLENDED_GEOMETRY_CANVAS_URL);
+  let { gFront, EVENTS, ShadersListView, ShadersEditorsView } = panel.panelWin;
+
+  reload(target);
+  let firstProgramActor = yield once(gFront, "program-linked");
+  let secondProgramActor = yield once(gFront, "program-linked");
+
+  yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 127, g: 127, b: 127, a: 255 }, true);
+  yield ensurePixelIs(debuggee, { x: 64, y: 64 }, { r: 0, g: 127, b: 127, a: 127 }, true);
+  ok(true, "The canvas was correctly drawn.");
+
+  getBlackBoxCheckbox(panel, 0).click();
+
+  yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true);
+  yield ensurePixelIs(debuggee, { x: 64, y: 64 }, { r: 0, g: 0, b: 0, a: 127 }, true);
+  ok(true, "The first program was correctly blackboxed.");
+
+  getBlackBoxCheckbox(panel, 0).click();
+  getBlackBoxCheckbox(panel, 1).click();
+
+  yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 127, g: 127, b: 127, a: 255 }, true);
+  yield ensurePixelIs(debuggee, { x: 64, y: 64 }, { r: 127, g: 127, b: 127, a: 255 }, true);
+  ok(true, "The second program was correctly blackboxed.");
+
+  getBlackBoxCheckbox(panel, 1).click();
+
+  yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 127, g: 127, b: 127, a: 255 }, true);
+  yield ensurePixelIs(debuggee, { x: 64, y: 64 }, { r: 0, g: 127, b: 127, a: 127 }, true);
+  ok(true, "The two programs were correctly unblackboxed.");
+
+  getBlackBoxCheckbox(panel, 0).click();
+  getBlackBoxCheckbox(panel, 1).click();
+
+  yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true);
+  yield ensurePixelIs(debuggee, { x: 64, y: 64 }, { r: 0, g: 0, b: 0, a: 255 }, true);
+  ok(true, "The two programs were correctly blackboxed again.");
+
+  getBlackBoxCheckbox(panel, 0).click();
+  getBlackBoxCheckbox(panel, 1).click();
+
+  yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 127, g: 127, b: 127, a: 255 }, true);
+  yield ensurePixelIs(debuggee, { x: 64, y: 64 }, { r: 0, g: 127, b: 127, a: 127 }, true);
+  ok(true, "The two programs were correctly unblackboxed again.");
+
+  yield teardown(panel);
+  finish();
+}
+
+function getBlackBoxCheckbox(aPanel, aIndex) {
+  return aPanel.panelWin.document.querySelectorAll(
+    ".side-menu-widget-item-checkbox")[aIndex];
+}
+
+function once(aTarget, aEvent) {
+  let deferred = promise.defer();
+  aTarget.once(aEvent, deferred.resolve);
+  return deferred.promise;
+}
rename from browser/devtools/shadereditor/test/browser_se_programs-highlight.js
rename to browser/devtools/shadereditor/test/browser_se_programs-highlight-01.js
--- a/browser/devtools/shadereditor/test/browser_se_programs-highlight.js
+++ b/browser/devtools/shadereditor/test/browser_se_programs-highlight-01.js
@@ -42,19 +42,19 @@ function ifWebGLSupported() {
   yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
   yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
   ok(true, "The first program was correctly highlighted.");
 
   ShadersListView._onProgramMouseLeave({ target: getItemLabel(panel, 0) });
   ShadersListView._onProgramMouseEnter({ target: getItemLabel(panel, 1) });
 
   yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
-  yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas2");
+  yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 64, a: 255 }, true, "#canvas2");
   yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
-  yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas2");
+  yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 0, b: 64, a: 255 }, true, "#canvas2");
   ok(true, "The second program was correctly highlighted.");
 
   ShadersListView._onProgramMouseLeave({ target: getItemLabel(panel, 1) });
 
   yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
   yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
   yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
   yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
new file mode 100644
--- /dev/null
+++ b/browser/devtools/shadereditor/test/browser_se_programs-highlight-02.js
@@ -0,0 +1,53 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if highlighting a program works properly in tandem with blended
+ * overlapping geometry.
+ */
+
+function ifWebGLSupported() {
+  let [target, debuggee, panel] = yield initShaderEditor(BLENDED_GEOMETRY_CANVAS_URL);
+  let { gFront, EVENTS, ShadersListView, ShadersEditorsView } = panel.panelWin;
+
+  reload(target);
+  let firstProgramActor = yield once(gFront, "program-linked");
+  let secondProgramActor = yield once(gFront, "program-linked");
+
+  yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 127, g: 127, b: 127, a: 255 }, true);
+  yield ensurePixelIs(debuggee, { x: 64, y: 64 }, { r: 0, g: 127, b: 127, a: 127 }, true);
+  ok(true, "The canvas was correctly drawn.");
+
+  ShadersListView._onProgramMouseEnter({ target: getItemLabel(panel, 0) });
+
+  yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 127, g: 0, b: 32, a: 255 }, true);
+  yield ensurePixelIs(debuggee, { x: 64, y: 64 }, { r: 0, g: 0, b: 32, a: 127 }, true);
+  ok(true, "The first program was correctly highlighted.");
+
+  ShadersListView._onProgramMouseLeave({ target: getItemLabel(panel, 0) });
+  ShadersListView._onProgramMouseEnter({ target: getItemLabel(panel, 1) });
+
+  yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 127, g: 127, b: 127, a: 255 }, true);
+  yield ensurePixelIs(debuggee, { x: 64, y: 64 }, { r: 255, g: 0, b: 64, a: 255 }, true);
+  ok(true, "The second program was correctly highlighted.");
+
+  ShadersListView._onProgramMouseLeave({ target: getItemLabel(panel, 1) });
+
+  yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 127, g: 127, b: 127, a: 255 }, true);
+  yield ensurePixelIs(debuggee, { x: 64, y: 64 }, { r: 0, g: 127, b: 127, a: 127 }, true);
+  ok(true, "The two programs were correctly unhighlighted.");
+
+  yield teardown(panel);
+  finish();
+}
+
+function getItemLabel(aPanel, aIndex) {
+  return aPanel.panelWin.document.querySelectorAll(
+    ".side-menu-widget-item-label")[aIndex];
+}
+
+function once(aTarget, aEvent) {
+  let deferred = promise.defer();
+  aTarget.once(aEvent, deferred.resolve);
+  return deferred.promise;
+}
--- a/browser/devtools/shadereditor/test/browser_webgl-actor-test-06.js
+++ b/browser/devtools/shadereditor/test/browser_webgl-actor-test-06.js
@@ -14,19 +14,19 @@ function ifWebGLSupported() {
   let vertexShader = yield programActor.getVertexShader();
   let fragmentShader = yield programActor.getFragmentShader();
 
   yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
   yield ensurePixelIs(debuggee, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
   yield checkShaderSource("The shader sources are correct before highlighting.");
   ok(true, "The corner pixel colors are correct before highlighting.");
 
-  yield programActor.highlight([0, 0, 1, 1]);
-  yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 255, a: 255 }, true);
-  yield ensurePixelIs(debuggee, { x: 511, y: 511 }, { r: 0, g: 0, b: 255, a: 255 }, true);
+  yield programActor.highlight([0, 1, 0, 1]);
+  yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true);
+  yield ensurePixelIs(debuggee, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
   yield checkShaderSource("The shader sources are preserved after highlighting.");
   ok(true, "The corner pixel colors are correct after highlighting.");
 
   yield programActor.unhighlight();
   yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
   yield ensurePixelIs(debuggee, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
   yield checkShaderSource("The shader sources are correct after unhighlighting.");
   ok(true, "The corner pixel colors are correct after unhighlighting.");
--- a/browser/devtools/shadereditor/test/browser_webgl-actor-test-09.js
+++ b/browser/devtools/shadereditor/test/browser_webgl-actor-test-09.js
@@ -65,19 +65,19 @@ function ifWebGLSupported() {
   yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
   yield ensurePixelIs(debuggee, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
   ok(true, "The shader was reverted to the old source.");
 
   let fragSource = yield fragmentShader.getText();
   ok(fragSource.contains("vec3 vFragmentColor;"),
     "The previous correct fragment shader source was preserved.");
 
-  yield programActor.highlight([0, 0, 1, 1]);
-  yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 255, a: 255 }, true);
-  yield ensurePixelIs(debuggee, { x: 511, y: 511 }, { r: 0, g: 0, b: 255, a: 255 }, true);
+  yield programActor.highlight([0, 1, 0, 1]);
+  yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true);
+  yield ensurePixelIs(debuggee, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
   ok(true, "Highlighting worked after setting a defective fragment source.");
 
   yield programActor.unhighlight();
   yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
   yield ensurePixelIs(debuggee, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
   ok(true, "Unhighlighting worked after setting a defective vertex source.");
 
   yield removeTab(target.tab);
--- a/browser/devtools/shadereditor/test/browser_webgl-actor-test-10.js
+++ b/browser/devtools/shadereditor/test/browser_webgl-actor-test-10.js
@@ -22,20 +22,23 @@ function ifWebGLSupported() {
   ok(true, "Canvas was correctly instrumented on the third navigation.");
 
   yield removeTab(target.tab);
   finish();
 
   function testHighlighting(programActor) {
     return Task.spawn(function() {
       yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
-      ok(true, "The top left pixel color was correct before highlighting.");
+      yield ensurePixelIs(debuggee, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
+      ok(true, "The corner pixel colors are correct before highlighting.");
 
-      yield programActor.highlight([0, 0, 1, 1]);
-      yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 255, a: 255 }, true);
-      ok(true, "The top left pixel color is correct after highlighting.");
+      yield programActor.highlight([0, 1, 0, 1]);
+      yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true);
+      yield ensurePixelIs(debuggee, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
+      ok(true, "The corner pixel colors are correct after highlighting.");
 
       yield programActor.unhighlight();
       yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
-      ok(true, "The top left pixel color is correct after unhighlighting.");
+      yield ensurePixelIs(debuggee, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
+      ok(true, "The corner pixel colors are correct after unhighlighting.");
     });
   }
 }
--- a/browser/devtools/shadereditor/test/browser_webgl-actor-test-15.js
+++ b/browser/devtools/shadereditor/test/browser_webgl-actor-test-15.js
@@ -76,25 +76,28 @@ function ifWebGLSupported() {
       isnot(newProgramActors[1], oldProgramActor,
         "The old program actor is not equal to the new second program actor.");
     });
   }
 
   function checkHighlightingInTheFirstPage(programActor) {
     return Task.spawn(function() {
       yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
-      ok(true, "The top left pixel color was correct before highlighting.");
+      yield ensurePixelIs(debuggee, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
+      ok(true, "The corner pixel colors are correct before highlighting.");
 
-      yield programActor.highlight([0, 0, 1, 1]);
-      yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 255, a: 255 }, true);
-      ok(true, "The top left pixel color is correct after highlighting.");
+      yield programActor.highlight([0, 1, 0, 1]);
+      yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true);
+      yield ensurePixelIs(debuggee, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
+      ok(true, "The corner pixel colors are correct after highlighting.");
 
       yield programActor.unhighlight();
       yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
-      ok(true, "The top left pixel color is correct after unhighlighting.");
+      yield ensurePixelIs(debuggee, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
+      ok(true, "The corner pixel colors are correct after unhighlighting.");
     });
   }
 
   function checkHighlightingInTheSecondPage(firstProgramActor, secondProgramActor) {
     return Task.spawn(function() {
       yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
       yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
       yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
--- a/browser/devtools/shadereditor/test/browser_webgl-actor-test-16.js
+++ b/browser/devtools/shadereditor/test/browser_webgl-actor-test-16.js
@@ -76,25 +76,28 @@ function ifWebGLSupported() {
   ok(true, "The cached programs behave correctly after navigating forward and reloading.");
 
   yield removeTab(target.tab);
   finish();
 
   function checkHighlightingInTheFirstPage(programActor) {
     return Task.spawn(function() {
       yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
-      ok(true, "The top left pixel color was correct before highlighting.");
+      yield ensurePixelIs(debuggee, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
+      ok(true, "The corner pixel colors are correct before highlighting.");
 
-      yield programActor.highlight([0, 0, 1, 1]);
-      yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 255, a: 255 }, true);
-      ok(true, "The top left pixel color is correct after highlighting.");
+      yield programActor.highlight([0, 1, 0, 1]);
+      yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 0, a: 255 }, true);
+      yield ensurePixelIs(debuggee, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
+      ok(true, "The corner pixel colors are correct after highlighting.");
 
       yield programActor.unhighlight();
       yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
-      ok(true, "The top left pixel color is correct after unhighlighting.");
+      yield ensurePixelIs(debuggee, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true);
+      ok(true, "The corner pixel colors are correct after unhighlighting.");
     });
   }
 
   function checkHighlightingInTheSecondPage(firstProgramActor, secondProgramActor) {
     return Task.spawn(function() {
       yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
       yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
       yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
new file mode 100644
--- /dev/null
+++ b/browser/devtools/shadereditor/test/doc_blended-geometry.html
@@ -0,0 +1,136 @@
+<!-- Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/ -->
+<!doctype html>
+
+<html>
+  <head>
+    <meta charset="utf-8"/>
+    <title>WebGL editor test page</title>
+
+    <script id="shader-vs" type="x-shader/x-vertex">
+      precision lowp float;
+      attribute vec3 aVertexPosition;
+      uniform float uDepth;
+
+      void main(void) {
+        gl_Position = vec4(aVertexPosition, uDepth);
+      }
+    </script>
+
+    <script id="shader-fs-0" type="x-shader/x-fragment">
+      precision lowp float;
+
+      void main(void) {
+        gl_FragColor = vec4(0.5, 0.5, 0.5, 1.0);
+      }
+    </script>
+
+    <script id="shader-fs-1" type="x-shader/x-fragment">
+      precision lowp float;
+
+      void main(void) {
+        gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
+      }
+    </script>
+  </head>
+
+  <body>
+    <canvas id="canvas" width="128" height="128"></canvas>
+
+    <script type="text/javascript;version=1.8">
+      "use strict";
+
+      let canvas, gl;
+      let program = [];
+      let squareVerticesPositionBuffer;
+      let vertexPositionAttribute = [];
+      let depthUniform = [];
+
+      window.onload = function() {
+        canvas = document.querySelector("canvas");
+        gl = canvas.getContext("webgl");
+        gl.clearColor(0.0, 0.0, 0.0, 1.0);
+
+        initProgram(0);
+        initProgram(1);
+        initBuffers();
+        drawScene();
+      }
+
+      function initProgram(i) {
+        let vertexShader = getShader("shader-vs");
+        let fragmentShader = getShader("shader-fs-" + i);
+
+        program[i] = gl.createProgram();
+        gl.attachShader(program[i], vertexShader);
+        gl.attachShader(program[i], fragmentShader);
+        gl.linkProgram(program[i]);
+
+        vertexPositionAttribute[i] = gl.getAttribLocation(program[i], "aVertexPosition");
+        gl.enableVertexAttribArray(vertexPositionAttribute[i]);
+
+        depthUniform[i] = gl.getUniformLocation(program[i], "uDepth");
+      }
+
+      function getShader(id) {
+        let script = document.getElementById(id);
+        let source = script.textContent;
+        let shader;
+
+        if (script.type == "x-shader/x-fragment") {
+          shader = gl.createShader(gl.FRAGMENT_SHADER);
+        } else if (script.type == "x-shader/x-vertex") {
+          shader = gl.createShader(gl.VERTEX_SHADER);
+        }
+
+        gl.shaderSource(shader, source);
+        gl.compileShader(shader);
+
+        return shader;
+      }
+
+      function initBuffers() {
+        squareVerticesPositionBuffer = gl.createBuffer();
+        gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesPositionBuffer);
+        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
+           1.0,  1.0, 0.0,
+          -1.0,  1.0, 0.0,
+           1.0, -1.0, 0.0,
+          -1.0, -1.0, 0.0
+        ]), gl.STATIC_DRAW);
+      }
+
+      function drawScene() {
+        gl.clear(gl.COLOR_BUFFER_BIT);
+
+        for (let i = 0; i < 2; i++) {
+          gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesPositionBuffer);
+          gl.vertexAttribPointer(vertexPositionAttribute[i], 3, gl.FLOAT, false, 0, 0);
+
+          gl.useProgram(program[i]);
+          gl.uniform1f(depthUniform[i], i + 1);
+          blend(i);
+          gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
+        }
+
+        window.requestAnimationFrame(drawScene);
+      }
+
+      function blend(i) {
+        if (i == 0) {
+          gl.disable(gl.BLEND);
+        }
+        else if (i == 1) {
+          gl.enable(gl.BLEND);
+          gl.blendColor(0.5, 0, 0, 0.25);
+          gl.blendEquationSeparate(
+            gl.FUNC_REVERSE_SUBTRACT, gl.FUNC_SUBTRACT);
+          gl.blendFuncSeparate(
+            gl.CONSTANT_COLOR, gl.ONE_MINUS_CONSTANT_COLOR,
+            gl.ONE_MINUS_CONSTANT_COLOR, gl.CONSTANT_COLOR);
+        }
+      }
+    </script>
+  </body>
+
+</html>
--- a/browser/devtools/shadereditor/test/head.js
+++ b/browser/devtools/shadereditor/test/head.js
@@ -23,16 +23,17 @@ let TiltGL = devtools.require("devtools/
 let TargetFactory = devtools.TargetFactory;
 let Toolbox = devtools.Toolbox;
 
 const EXAMPLE_URL = "http://example.com/browser/browser/devtools/shadereditor/test/";
 const SIMPLE_CANVAS_URL = EXAMPLE_URL + "doc_simple-canvas.html";
 const SHADER_ORDER_URL = EXAMPLE_URL + "doc_shader-order.html";
 const MULTIPLE_CONTEXTS_URL = EXAMPLE_URL + "doc_multiple-contexts.html";
 const OVERLAPPING_GEOMETRY_CANVAS_URL = EXAMPLE_URL + "doc_overlapping-geometry.html";
+const BLENDED_GEOMETRY_CANVAS_URL = EXAMPLE_URL + "doc_blended-geometry.html";
 
 // All tests are asynchronous.
 waitForExplicitFinish();
 
 let gToolEnabled = Services.prefs.getBoolPref("devtools.shadereditor.enabled");
 
 registerCleanupFunction(() => {
   info("finish() was called, cleaning up...");
--- a/browser/devtools/sourceeditor/editor.js
+++ b/browser/devtools/sourceeditor/editor.js
@@ -233,19 +233,29 @@ Editor.prototype = {
       cm = win.CodeMirror(win.document.body, this.config);
       cm.getWrapperElement().addEventListener("contextmenu", (ev) => {
         ev.preventDefault();
         this.showContextMenu(el.ownerDocument, ev.screenX, ev.screenY);
       }, false);
 
       cm.on("focus", () => this.emit("focus"));
       cm.on("change", () => this.emit("change"));
-      cm.on("gutterClick", (cm, line) => this.emit("gutterClick", line));
       cm.on("cursorActivity", (cm) => this.emit("cursorActivity"));
 
+      cm.on("gutterClick", (cm, line, gutter, ev) => {
+        let head = { line: line, ch: 0 };
+        let tail = { line: line, ch: this.getText(line).length };
+
+        // Shift-click on a gutter selects the whole line.
+        if (ev.shiftKey)
+          return void cm.setSelection(head, tail);
+
+        this.emit("gutterClick", line);
+      });
+
       win.CodeMirror.defineExtension("l10n", (name) => {
         return L10N.GetStringFromName(name);
       });
 
       cm.getInputField().controllers.insertControllerAt(0, controller(this));
 
       this.container = env;
       editors.set(this, cm);
--- a/browser/devtools/sourceeditor/test/browser_editor_cursor.js
+++ b/browser/devtools/sourceeditor/test/browser_editor_cursor.js
@@ -26,11 +26,18 @@ function test() {
     is(ed.getSelection(), "Hello", "setSelection");
 
     ed.extendSelection({ start: 0, length: 5 });
     is(ed.getSelection(), ".\nHow", "extendSelection");
 
     ed.dropSelection();
     is(ed.getSelection(), "", "dropSelection");
 
+    // Check that shift-click on a gutter selects the whole line (bug 919707)
+    let iframe = win.document.querySelector("iframe");
+    let gutter = iframe.contentWindow.document.querySelector(".CodeMirror-gutters");
+
+    EventUtils.sendMouseEvent({ type: "mousedown", shiftKey: true }, gutter, iframe.contentWindow);
+    is(ed.getSelection(), "Hello.", "shift-click");
+
     teardown(ed, win);
   });
 }
\ No newline at end of file
--- a/browser/devtools/styleeditor/StyleEditorPanel.jsm
+++ b/browser/devtools/styleeditor/StyleEditorPanel.jsm
@@ -95,17 +95,17 @@ StyleEditorPanel.prototype = {
    * @param {number} col
    *        Column number to jump to after selecting. One-indexed
    */
   selectStyleSheet: function(href, line, col) {
     if (!this._debuggee || !this.UI) {
       return;
     }
     let stylesheet = this._debuggee.styleSheetFromHref(href);
-    this.UI.selectStyleSheet(href, line - 1, col - 1);
+    this.UI.selectStyleSheet(href, line - 1, col ? col - 1 : 0);
   },
 
   /**
    * Destroy the style editor.
    */
   destroy: function() {
     if (!this._destroyed) {
       this._destroyed = true;
--- a/browser/devtools/styleeditor/test/browser.ini
+++ b/browser/devtools/styleeditor/test/browser.ini
@@ -34,8 +34,9 @@ support-files =
 [browser_styleeditor_loading.js]
 [browser_styleeditor_new.js]
 [browser_styleeditor_nostyle.js]
 [browser_styleeditor_pretty.js]
 [browser_styleeditor_private_perwindowpb.js]
 [browser_styleeditor_reload.js]
 [browser_styleeditor_sv_keynav.js]
 [browser_styleeditor_sv_resize.js]
+[browser_styleeditor_selectstylesheet.js]
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleeditor/test/browser_styleeditor_selectstylesheet.js
@@ -0,0 +1,54 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const TESTCASE_URI = TEST_BASE_HTTPS + "simple.html";
+const NEW_URI = TEST_BASE_HTTPS + "media.html";
+
+const LINE_NO = 5;
+const COL_NO  = 0;
+
+let gContentWin;
+let gUI;
+
+function test()
+{
+  waitForExplicitFinish();
+
+  addTabAndOpenStyleEditor(function(panel) {
+    gContentWin = gBrowser.selectedTab.linkedBrowser.contentWindow.wrappedJSObject;
+    gUI = panel.UI;
+
+    let count = 0;
+    gUI.on("editor-added", function editorAdded(event, editor) {
+      if (++count == 2) {
+        gUI.off("editor-added", editorAdded);
+        gUI.editors[0].getSourceEditor().then(runTests);
+      }
+    })
+  });
+
+  content.location = TESTCASE_URI;
+}
+
+function runTests()
+{
+  let count = 0;
+
+  // Make sure Editor doesn't go into an infinite loop when
+  // column isn't passed. See bug 941018.
+  gUI.once("editor-selected", (event, editor) => {
+    editor.getSourceEditor().then(() => {
+      is(gUI.selectedEditor, gUI.editors[1], "second editor is selected");
+      let {line, ch} = gUI.selectedEditor.sourceEditor.getCursor();
+      
+      is(line, LINE_NO, "correct line selected");
+      is(ch, COL_NO, "correct column selected");
+
+      gUI = null;
+      finish();
+    });
+  });
+
+  gUI.selectStyleSheet(gUI.editors[1].styleSheet.href, LINE_NO);
+}
\ No newline at end of file
--- a/browser/devtools/webconsole/hudservice.js
+++ b/browser/devtools/webconsole/hudservice.js
@@ -23,16 +23,18 @@ loader.lazyImporter(this, "DebuggerClien
 const STRINGS_URI = "chrome://browser/locale/devtools/webconsole.properties";
 let l10n = new WebConsoleUtils.l10n(STRINGS_URI);
 
 const BROWSER_CONSOLE_WINDOW_FEATURES = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
 
 // The preference prefix for all of the Browser Console filters.
 const BROWSER_CONSOLE_FILTER_PREFS_PREFIX = "devtools.browserconsole.filter.";
 
+let gHudId = 0;
+
 ///////////////////////////////////////////////////////////////////////////
 //// The HUD service
 
 function HUD_SERVICE()
 {
   this.consoles = new Map();
   this.lastFinishedRequest = { callback: null };
 }
@@ -296,17 +298,17 @@ HUD_SERVICE.prototype =
  *        The window where the web console UI is already loaded.
  * @param nsIDOMWindow aChromeWindow
  *        The window of the web console owner.
  */
 function WebConsole(aTarget, aIframeWindow, aChromeWindow)
 {
   this.iframeWindow = aIframeWindow;
   this.chromeWindow = aChromeWindow;
-  this.hudId = "hud_" + Date.now();
+  this.hudId = "hud_" + ++gHudId;
   this.target = aTarget;
 
   this.browserWindow = this.chromeWindow.top;
 
   let element = this.browserWindow.document.documentElement;
   if (element.getAttribute("windowtype") != "navigator:browser") {
     this.browserWindow = HUDService.currentContext();
   }
--- a/browser/devtools/webconsole/test/browser.ini
+++ b/browser/devtools/webconsole/test/browser.ini
@@ -88,16 +88,17 @@ support-files =
   test-property-provider.html
   test-repeated-messages.html
   test-result-format-as-string.html
   test-webconsole-error-observer.html
   test_bug_770099_bad_policy_uri.html
   test_bug_770099_bad_policy_uri.html^headers^
   test_bug_770099_violation.html
   test_bug_770099_violation.html^headers^
+  test-autocomplete-in-stackframe.html
   testscript.js
   test-bug_923281_console_log_filter.html
   test-bug_923281_test1.js
   test-bug_923281_test2.js
 
 [browser_bug664688_sandbox_update_after_navigation.js]
 [browser_bug_638949_copy_link_location.js]
 [browser_bug_862916_console_dir_and_filter_off.js]
@@ -236,8 +237,9 @@ skip-if = os == "linux"
 [browser_webconsole_output_order.js]
 [browser_webconsole_property_provider.js]
 [browser_webconsole_scratchpad_panel_link.js]
 [browser_webconsole_split.js]
 [browser_webconsole_view_source.js]
 [browser_webconsole_reflow.js]
 [browser_webconsole_log_file_filter.js]
 [browser_webconsole_expandable_timestamps.js]
+[browser_webconsole_autocomplete_in_debugger_stackframe.js]
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_autocomplete_in_debugger_stackframe.js
@@ -0,0 +1,212 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Test that makes sure web console autocomplete happens in the user-selected stackframe
+// from the js debugger.
+
+const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-autocomplete-in-stackframe.html";
+
+let testDriver, gStackframes;
+
+function test()
+{
+  requestLongerTimeout(2);
+  addTab(TEST_URI);
+  browser.addEventListener("load", function onLoad() {
+    browser.removeEventListener("load", onLoad, true);
+    openConsole(null, function(hud) {
+      testDriver = testCompletion(hud);
+      testDriver.next();
+    });
+  }, true);
+}
+
+function testNext() {
+  executeSoon(function() {
+    testDriver.next();
+  });
+}
+
+function testCompletion(hud) {
+  let jsterm = hud.jsterm;
+  let input = jsterm.inputNode;
+  let popup = jsterm.autocompletePopup;
+
+  // Test if 'f' gives 'foo1' but not 'foo2' or 'foo3'
+  input.value = "f";
+  input.setSelectionRange(1, 1);
+  jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext);
+  yield undefined;
+
+  let newItems = popup.getItems();
+  ok(newItems.length > 0, "'f' gave a list of suggestions");
+  ok(!newItems.every(function(item) {
+       return item.label != "foo1";
+     }), "autocomplete results do contain foo1");
+  ok(!newItems.every(function(item) {
+       return item.label != "foo1Obj";
+     }), "autocomplete results do contain foo1Obj");
+  ok(newItems.every(function(item) {
+       return item.label != "foo2";
+     }), "autocomplete results do not contain foo2");
+  ok(newItems.every(function(item) {
+       return item.label != "foo2Obj";
+     }), "autocomplete results do not contain foo2Obj");
+  ok(newItems.every(function(item) {
+       return item.label != "foo3";
+     }), "autocomplete results do not contain foo3");
+  ok(newItems.every(function(item) {
+       return item.label != "foo3Obj";
+     }), "autocomplete results do not contain foo3Obj");
+
+  // Test if 'foo1Obj.' gives 'prop1' and 'prop2'
+  input.value = "foo1Obj.";
+  input.setSelectionRange(8, 8);
+  jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext);
+  yield undefined;
+
+  newItems = popup.getItems();
+  ok(!newItems.every(function(item) {
+       return item.label != "prop1";
+     }), "autocomplete results do contain prop1");
+  ok(!newItems.every(function(item) {
+       return item.label != "prop2";
+     }), "autocomplete results do contain prop2");
+
+  // Test if 'foo1Obj.prop2.' gives 'prop21'
+  input.value = "foo1Obj.prop2.";
+  input.setSelectionRange(14, 14);
+  jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext);
+  yield undefined;
+
+  newItems = popup.getItems();
+  ok(!newItems.every(function(item) {
+       return item.label != "prop21";
+     }), "autocomplete results do contain prop21");
+
+  info("openDebugger");
+  executeSoon(() => openDebugger().then(debuggerOpened));
+  yield undefined;
+
+  // From this point on the
+  // Test if 'f' gives 'foo3' and 'foo1' but not 'foo2'
+  input.value = "f";
+  input.setSelectionRange(1, 1);
+  jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext);
+  yield undefined;
+
+  newItems = popup.getItems();
+  ok(newItems.length > 0, "'f' gave a list of suggestions");
+  ok(!newItems.every(function(item) {
+       return item.label != "foo3";
+     }), "autocomplete results do contain foo3");
+  ok(!newItems.every(function(item) {
+       return item.label != "foo3Obj";
+     }), "autocomplete results do contain foo3Obj");
+  ok(!newItems.every(function(item) {
+       return item.label != "foo1";
+     }), "autocomplete results do contain foo1");
+  ok(!newItems.every(function(item) {
+       return item.label != "foo1Obj";
+     }), "autocomplete results do contain foo1Obj");
+  ok(newItems.every(function(item) {
+       return item.label != "foo2";
+     }), "autocomplete results do not contain foo2");
+  ok(newItems.every(function(item) {
+       return item.label != "foo2Obj";
+     }), "autocomplete results do not contain foo2Obj");
+
+  openDebugger().then(() => {
+    gStackframes.selectFrame(1);
+
+    info("openConsole");
+    executeSoon(() => openConsole(null, () => testDriver.next()));
+  });
+  yield undefined;
+
+  // Test if 'f' gives 'foo2' and 'foo1' but not 'foo3'
+  input.value = "f";
+  input.setSelectionRange(1, 1);
+  jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext);
+  yield undefined;
+
+  newItems = popup.getItems();
+  ok(newItems.length > 0, "'f' gave a list of suggestions");
+  ok(!newItems.every(function(item) {
+       return item.label != "foo2";
+     }), "autocomplete results do contain foo2");
+  ok(!newItems.every(function(item) {
+       return item.label != "foo2Obj";
+     }), "autocomplete results do contain foo2Obj");
+  ok(!newItems.every(function(item) {
+       return item.label != "foo1";
+     }), "autocomplete results do contain foo1");
+  ok(!newItems.every(function(item) {
+       return item.label != "foo1Obj";
+     }), "autocomplete results do contain foo1Obj");
+  ok(newItems.every(function(item) {
+       return item.label != "foo3";
+     }), "autocomplete results do not contain foo3");
+  ok(newItems.every(function(item) {
+       return item.label != "foo3Obj";
+     }), "autocomplete results do not contain foo3Obj");
+
+  // Test if 'foo2Obj.' gives 'prop1'
+  input.value = "foo2Obj.";
+  input.setSelectionRange(8, 8);
+  jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext);
+  yield undefined;
+
+  newItems = popup.getItems();
+  ok(!newItems.every(function(item) {
+       return item.label != "prop1";
+     }), "autocomplete results do contain prop1");
+
+  // Test if 'foo1Obj.prop1.' gives 'prop11'
+  input.value = "foo2Obj.prop1.";
+  input.setSelectionRange(14, 14);
+  jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext);
+  yield undefined;
+
+  newItems = popup.getItems();
+  ok(!newItems.every(function(item) {
+       return item.label != "prop11";
+     }), "autocomplete results do contain prop11");
+
+  // Test if 'foo1Obj.prop1.prop11.' gives suggestions for a string i.e. 'length'
+  input.value = "foo2Obj.prop1.prop11.";
+  input.setSelectionRange(21, 21);
+  jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext);
+  yield undefined;
+
+  newItems = popup.getItems();
+  ok(!newItems.every(function(item) {
+       return item.label != "length";
+     }), "autocomplete results do contain length");
+
+  testDriver = null;
+  executeSoon(finishTest);
+  yield undefined;
+}
+
+function debuggerOpened(aResult)
+{
+  let debuggerWin = aResult.panelWin;
+  let debuggerController = debuggerWin.DebuggerController;
+  let thread = debuggerController.activeThread;
+  gStackframes = debuggerController.StackFrames;
+
+  executeSoon(() => {
+    thread.addOneTimeListener("framesadded", onFramesAdded);
+    info("firstCall()");
+    content.wrappedJSObject.firstCall();
+  });
+}
+
+function onFramesAdded()
+{
+  info("onFramesAdded, openConsole() now");
+  executeSoon(() => openConsole(null, testNext));
+}
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_585991_autocomplete_keys.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_585991_autocomplete_keys.js
@@ -13,24 +13,24 @@ function test() {
     openConsole(null, consoleOpened);
   }, true);
 }
 
 function consoleOpened(aHud) {
   HUD = aHud;
   info("web console opened");
 
-  content.wrappedJSObject.foobarBug585991 = {
-    "item0": "value0",
-    "item1": "value1",
-    "item2": "value2",
-    "item3": "value3",
-  };
+  jsterm = HUD.jsterm;
 
-  jsterm = HUD.jsterm;
+  jsterm.execute("window.foobarBug585991={" +
+    "'item0': 'value0'," +
+    "'item1': 'value1'," +
+    "'item2': 'value2'," +
+    "'item3': 'value3'" +
+  "}");
   popup = jsterm.autocompletePopup;
   completeNode = jsterm.completeNode;
   inputNode = jsterm.inputNode;
 
   ok(!popup.isOpen, "popup is not open");
 
   popup._panel.addEventListener("popupshown", function onShown() {
     popup._panel.removeEventListener("popupshown", onShown, false);
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_632347_iterators_generators.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_632347_iterators_generators.js
@@ -14,49 +14,55 @@ function test() {
     openConsole(null, consoleOpened);
   }, true);
 }
 
 function consoleOpened(HUD) {
   let tools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
   let JSPropertyProvider = tools.require("devtools/toolkit/webconsole/utils").JSPropertyProvider;
 
+  let tmp = Cu.import("resource://gre/modules/jsdebugger.jsm", {});
+  tmp.addDebuggerToGlobal(tmp);
+  let dbg = new tmp.Debugger;
+
   let jsterm = HUD.jsterm;
   let win = content.wrappedJSObject;
+  let dbgWindow = dbg.makeGlobalObjectReference(win);
 
   // Make sure autocomplete does not walk through iterators and generators.
   let result = win.gen1.next();
-  let completion = JSPropertyProvider(win, "gen1.");
-  is(completion, null, "no matches for gen1");
+  let completion = JSPropertyProvider(dbgWindow, null, "gen1.");
+  isnot(completion.matches.length, 0, "Got matches for gen1");
 
   is(result+1, win.gen1.next(), "gen1.next() did not execute");
 
   result = win.gen2.next();
 
-  completion = JSPropertyProvider(win, "gen2.");
-  is(completion, null, "no matches for gen2");
+  completion = JSPropertyProvider(dbgWindow, null, "gen2.");
+  isnot(completion.matches.length, 0, "Got matches for gen2");
 
   is((result/2+1)*2, win.gen2.next(),
      "gen2.next() did not execute");
 
   result = win.iter1.next();
   is(result[0], "foo", "iter1.next() [0] is correct");
   is(result[1], "bar", "iter1.next() [1] is correct");
 
-  completion = JSPropertyProvider(win, "iter1.");
-  is(completion, null, "no matches for iter1");
+  completion = JSPropertyProvider(dbgWindow, null, "iter1.");
+  isnot(completion.matches.length, 0, "Got matches for iter1");
 
   result = win.iter1.next();
   is(result[0], "baz", "iter1.next() [0] is correct");
   is(result[1], "baaz", "iter1.next() [1] is correct");
 
-  completion = JSPropertyProvider(content, "iter2.");
-  is(completion, null, "no matches for iter2");
+  let dbgContent = dbg.makeGlobalObjectReference(content);
+  completion = JSPropertyProvider(dbgContent, null, "iter2.");
+  isnot(completion.matches.length, 0, "Got matches for iter2");
 
-  completion = JSPropertyProvider(win, "window.");
+  completion = JSPropertyProvider(dbgWindow, null, "window.");
   ok(completion, "matches available for window");
   ok(completion.matches.length, "matches available for window (length)");
 
   jsterm.clearOutput();
 
   jsterm.execute("window", (msg) => {
     jsterm.once("variablesview-fetched", testVariablesView.bind(null, HUD));
     let anchor = msg.querySelector(".body a");
--- a/browser/devtools/webconsole/test/browser_webconsole_property_provider.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_property_provider.js
@@ -13,27 +13,32 @@ function test() {
   browser.addEventListener("load", testPropertyProvider, true);
 }
 
 function testPropertyProvider() {
   browser.removeEventListener("load", testPropertyProvider, true);
   let tools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
   let JSPropertyProvider = tools.require("devtools/toolkit/webconsole/utils").JSPropertyProvider;
 
-  let completion = JSPropertyProvider(content, "thisIsNotDefined");
+  let tmp = Cu.import("resource://gre/modules/jsdebugger.jsm", {});
+  tmp.addDebuggerToGlobal(tmp);
+  let dbg = new tmp.Debugger;
+  let dbgWindow = dbg.makeGlobalObjectReference(content);
+
+  let completion = JSPropertyProvider(dbgWindow, null, "thisIsNotDefined");
   is (completion.matches.length, 0, "no match for 'thisIsNotDefined");
 
   // This is a case the PropertyProvider can't handle. Should return null.
-  completion = JSPropertyProvider(content, "window[1].acb");
+  completion = JSPropertyProvider(dbgWindow, null, "window[1].acb");
   is (completion, null, "no match for 'window[1].acb");
 
   // A very advanced completion case.
   var strComplete =
     'function a() { }document;document.getElementById(window.locatio';
-  completion = JSPropertyProvider(content, strComplete);
+  completion = JSPropertyProvider(dbgWindow, null, strComplete);
   ok(completion.matches.length == 2, "two matches found");
   ok(completion.matchProp == "locatio", "matching part is 'test'");
   var matches = completion.matches;
   matches.sort();
   ok(matches[0] == "location", "the first match is 'location'");
   ok(matches[1] == "locationbar", "the second match is 'locationbar'");
 
   finishTest();
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-autocomplete-in-stackframe.html
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML>
+<html dir="ltr" lang="en">
+  <head>
+    <meta charset="utf8">
+    <!--
+    - Any copyright is dedicated to the Public Domain.
+    - http://creativecommons.org/publicdomain/zero/1.0/
+    -->
+    <title>Test for bug 842682 - use the debugger API for web console autocomplete</title>
+    <script>
+      var foo1 = "globalFoo";
+
+      var foo1Obj = {
+        prop1: "111",
+        prop2: {
+          prop21: "212121"
+        }
+      };
+
+      function firstCall()
+      {
+        var foo2 = "fooFirstCall";
+
+        var foo2Obj = {
+          prop1: {
+            prop11: "111111"
+          }
+        };
+
+        secondCall();
+      }
+
+      function secondCall()
+      {
+        var foo3 = "fooSecondCall";
+
+        var foo3Obj = {
+          prop1: {
+            prop11: "313131"
+          }
+        };
+
+        debugger;
+      }
+    </script>
+  </head>
+  <body>
+    <p>Hello world!</p>
+  </body>
+</html>
--- a/browser/devtools/webconsole/webconsole.js
+++ b/browser/devtools/webconsole/webconsole.js
@@ -3070,16 +3070,24 @@ JSTerm.prototype = {
    * The input that caused the last request to the server, whose response is
    * cached in the _autocompleteCache array.
    * @private
    * @type string
    */
   _autocompleteQuery: null,
 
   /**
+   * The frameActorId used in the last autocomplete query. Whenever this changes
+   * the autocomplete cache must be invalidated.
+   * @private
+   * @type string
+   */
+  _lastFrameActorId: null,
+
+  /**
    * The Web Console sidebar.
    * @see this._createSidebar()
    * @see Sidebar.jsm
    */
   sidebar: null,
 
   /**
    * The Variables View instance shown in the sidebar.
@@ -4281,30 +4289,32 @@ JSTerm.prototype = {
    *        updated.
    * @returns boolean true if there existed a completion for the current input,
    *          or false otherwise.
    */
   complete: function JSTF_complete(aType, aCallback)
   {
     let inputNode = this.inputNode;
     let inputValue = inputNode.value;
+    let frameActor = this.getFrameActor(this.SELECTED_FRAME);
+
     // If the inputNode has no value, then don't try to complete on it.
     if (!inputValue) {
       this.clearCompletion();
       return false;
     }
 
     // Only complete if the selection is empty.
     if (inputNode.selectionStart != inputNode.selectionEnd) {
       this.clearCompletion();
       return false;
     }
 
     // Update the completion results.
-    if (this.lastCompletion.value != inputValue) {
+    if (this.lastCompletion.value != inputValue || frameActor != this._lastFrameActorId) {
       this._updateCompletionResult(aType, aCallback);
       return false;
     }
 
     let popup = this.autocompletePopup;
     let accepted = false;
 
     if (aType != this.COMPLETE_HINT_ONLY && popup.itemCount == 1) {
@@ -4330,32 +4340,33 @@ JSTerm.prototype = {
    * @param int aType
    *        Completion type. See this.complete() for details.
    * @param function [aCallback]
    *        Optional, function to invoke when completion results are received.
    */
   _updateCompletionResult:
   function JST__updateCompletionResult(aType, aCallback)
   {
-    if (this.lastCompletion.value == this.inputNode.value) {
+    let frameActor = this.getFrameActor(this.SELECTED_FRAME);
+    if (this.lastCompletion.value == this.inputNode.value && frameActor == this._lastFrameActorId) {
       return;
     }
 
     let requestId = gSequenceId();
     let cursor = this.inputNode.selectionStart;
     let input = this.inputNode.value.substring(0, cursor);
     let cache = this._autocompleteCache;
 
     // If the current input starts with the previous input, then we already
     // have a list of suggestions and we just need to filter the cached
     // suggestions. When the current input ends with a non-alphanumeric
     // character we ask the server again for suggestions.
 
     // Check if last character is non-alphanumeric
-    if (!/[a-zA-Z0-9]$/.test(input)) {
+    if (!/[a-zA-Z0-9]$/.test(input) || frameActor != this._lastFrameActorId) {
       this._autocompleteQuery = null;
       this._autocompleteCache = null;
     }
 
     if (this._autocompleteQuery && input.startsWith(this._autocompleteQuery)) {
       let filterBy = input;
       // Find the last non-alphanumeric if exists.
       let lastNonAlpha = input.match(/[^a-zA-Z0-9][a-zA-Z0-9]*$/);
@@ -4375,25 +4386,28 @@ JSTerm.prototype = {
         value: null,
       };
 
       let response = { matches: newList, matchProp: filterBy };
       this._receiveAutocompleteProperties(null, aCallback, response);
       return;
     }
 
+    this._lastFrameActorId = frameActor;
+
     this.lastCompletion = {
       requestId: requestId,
       completionType: aType,
       value: null,
     };
 
     let callback = this._receiveAutocompleteProperties.bind(this, requestId,
                                                             aCallback);
-    this.webConsoleClient.autocomplete(input, cursor, callback);
+
+    this.webConsoleClient.autocomplete(input, cursor, callback, frameActor);
   },
 
   /**
    * Handler for the autocompletion results. This method takes
    * the completion result received from the server and updates the UI
    * accordingly.
    *
    * @param number aRequestId
--- a/browser/extensions/shumway/content/ShumwayStreamConverter.jsm
+++ b/browser/extensions/shumway/content/ShumwayStreamConverter.jsm
@@ -67,17 +67,18 @@ function getStringPref(pref, def) {
 
 function log(aMsg) {
   let msg = 'ShumwayStreamConverter.js: ' + (aMsg.join ? aMsg.join('') : aMsg);
   Services.console.logStringMessage(msg);
   dump(msg + '\n');
 }
 
 function getDOMWindow(aChannel) {
-  var requestor = aChannel.notificationCallbacks;
+  var requestor = aChannel.notificationCallbacks ||
+                  aChannel.loadGroup.notificationCallbacks;
   var win = requestor.getInterface(Components.interfaces.nsIDOMWindow);
   return win;
 }
 
 function parseQueryString(qs) {
   if (!qs)
     return {};
 
@@ -172,17 +173,20 @@ function isShumwayEnabledFor(actions) {
     return false;
   }
 
   var url = actions.url;
   var baseUrl = actions.baseUrl;
 
   // blacklisting well known sites with issues
   if (/\.ytimg\.com\//i.test(url) /* youtube movies */ ||
-    /\/vui.swf\b/i.test(url) /* vidyo manager */ ) {
+    /\/vui.swf\b/i.test(url) /* vidyo manager */  ||
+    /soundcloud\.com\/player\/assets\/swf/i.test(url) /* soundcloud */ ||
+    /sndcdn\.com\/assets\/swf/.test(url) /* soundcloud */ ||
+    /vimeocdn\.com/.test(url) /* vimeo */) {
     return false;
   }
 
   return true;
 }
 
 // All the priviledged actions.
 function ChromeActions(url, window, document) {
@@ -722,86 +726,96 @@ ShumwayStreamConverterBase.prototype = {
    * it's just the synchronous version of asyncConvertData.
    */
 
   // nsIStreamConverter::convert
   convert: function(aFromStream, aFromType, aToType, aCtxt) {
     throw Cr.NS_ERROR_NOT_IMPLEMENTED;
   },
 
-  isValidRequest: function() {
-    return true;
-  },
-
   getUrlHint: function(requestUrl) {
     return requestUrl.spec;
   },
 
   createChromeActions: function(window, document, urlHint) {
-    var url;
+    var url = urlHint;
     var baseUrl;
     var pageUrl;
     var element = window.frameElement;
     var isOverlay = false;
     var objectParams = {};
     if (element) {
-      var tagName = element.nodeName;
+      // PlayPreview overlay "belongs" to the embed/object tag and consists of
+      // DIV and IFRAME. Starting from IFRAME and looking for first object tag.
+      var tagName = element.nodeName, containerElement;
       while (tagName != 'EMBED' && tagName != 'OBJECT') {
         // plugin overlay skipping until the target plugin is found
         isOverlay = true;
+        containerElement = element;
         element = element.parentNode;
-        if (!element)
-          throw 'Plugin element is not found';
+        if (!element) {
+          throw new Error('Plugin element is not found');
+        }
         tagName = element.nodeName;
       }
 
-      // TODO: remove hack once bug 920927 is fixed
-      element.style.visibility = 'visible';
+      if (isOverlay) {
+        // Checking if overlay is a proper PlayPreview overlay.
+        for (var i = 0; i < element.children.length; i++) {
+          if (element.children[i] === containerElement) {
+            throw new Error('Plugin element is invalid');
+          }
+        }
+      }
+    }
+
+    if (element) {
+      // Getting absolute URL from the EMBED tag
+      url = element.srcURI.spec;
 
       pageUrl = element.ownerDocument.location.href; // proper page url?
 
       if (tagName == 'EMBED') {
         for (var i = 0; i < element.attributes.length; ++i) {
           var paramName = element.attributes[i].localName.toLowerCase();
           objectParams[paramName] = element.attributes[i].value;
         }
       } else {
-        url = element.getAttribute('data');
         for (var i = 0; i < element.childNodes.length; ++i) {
           var paramElement = element.childNodes[i];
           if (paramElement.nodeType != 1 ||
               paramElement.nodeName != 'PARAM') {
             continue;
           }
           var paramName = paramElement.getAttribute('name').toLowerCase();
           objectParams[paramName] = paramElement.getAttribute('value');
         }
       }
     }
 
-    url = url || objectParams.src || objectParams.movie;
+    if (!url) { // at this point url shall be known -- asserting
+      throw new Error('Movie url is not specified');
+    }
+
     baseUrl = objectParams.base || pageUrl;
 
     var movieParams = {};
     if (objectParams.flashvars) {
       movieParams = parseQueryString(objectParams.flashvars);
     }
     var queryStringMatch = /\?([^#]+)/.exec(url);
     if (queryStringMatch) {
       var queryStringParams = parseQueryString(queryStringMatch[1]);
       for (var i in queryStringParams) {
         if (!(i in movieParams)) {
           movieParams[i] = queryStringParams[i];
         }
       }
     }
 
-    url = !url ? urlHint : Services.io.newURI(url, null,
-      baseUrl ? Services.io.newURI(baseUrl, null, null) : null).spec;
-
     var allowScriptAccess = false;
     switch (objectParams.allowscriptaccess || 'sameDomain') {
     case 'always':
       allowScriptAccess = true;
       break;
     case 'never':
       allowScriptAccess = false;
       break;
@@ -825,98 +839,115 @@ ShumwayStreamConverterBase.prototype = {
     actions.embedTag = element;
     actions.isPausedAtStart = /\bpaused=true$/.test(urlHint);
     actions.allowScriptAccess = allowScriptAccess;
     return actions;
   },
 
   // nsIStreamConverter::asyncConvertData
   asyncConvertData: function(aFromType, aToType, aListener, aCtxt) {
-    if(!this.isValidRequest(aCtxt))
-      throw Cr.NS_ERROR_NOT_IMPLEMENTED;
-
     // Store the listener passed to us
     this.listener = aListener;
   },
 
   // nsIStreamListener::onDataAvailable
   onDataAvailable: function(aRequest, aContext, aInputStream, aOffset, aCount) {
     // Do nothing since all the data loading is handled by the viewer.
     log('SANITY CHECK: onDataAvailable SHOULD NOT BE CALLED!');
   },
 
   // nsIRequestObserver::onStartRequest
   onStartRequest: function(aRequest, aContext) {
     // Setup the request so we can use it below.
     aRequest.QueryInterface(Ci.nsIChannel);
-    // Cancel the request so the viewer can handle it.
-    aRequest.cancel(Cr.NS_BINDING_ABORTED);
+
+    aRequest.QueryInterface(Ci.nsIWritablePropertyBag);
+
+    // Change the content type so we don't get stuck in a loop.
+    aRequest.setProperty('contentType', aRequest.contentType);
+    aRequest.contentType = 'text/html';
+
+    // TODO For now suspending request, however we can continue fetching data
+    aRequest.suspend();
 
     var originalURI = aRequest.URI;
 
     // checking if the plug-in shall be run in simple mode
     var isSimpleMode = originalURI.spec === EXPECTED_PLAYPREVIEW_URI_PREFIX &&
                        getBoolPref('shumway.simpleMode', false);
 
     // Create a new channel that loads the viewer as a resource.
-    var channel = Services.io.newChannel(isSimpleMode ?
+    var viewerUrl = isSimpleMode ?
                     'resource://shumway/web/simple.html' :
-                    'resource://shumway/web/viewer.html', null, null);
+                    'resource://shumway/web/viewer.html';
+    var channel = Services.io.newChannel(viewerUrl, null, null);
 
     var converter = this;
     var listener = this.listener;
     // Proxy all the request observer calls, when it gets to onStopRequest
     // we can get the dom window.
     var proxy = {
-      onStartRequest: function() {
-        listener.onStartRequest.apply(listener, arguments);
+      onStartRequest: function(request, context) {
+        listener.onStartRequest(aRequest, context);
+      },
+      onDataAvailable: function(request, context, inputStream, offset, count) {
+        listener.onDataAvailable(aRequest, context, inputStream, offset, count);
       },
-      onDataAvailable: function() {
-        listener.onDataAvailable.apply(listener, arguments);
-      },
-      onStopRequest: function() {
+      onStopRequest: function(request, context, statusCode) {
+        // Cancel the request so the viewer can handle it.
+        aRequest.resume();
+        aRequest.cancel(Cr.NS_BINDING_ABORTED);
+
         var domWindow = getDOMWindow(channel);
-        if (domWindow.document.documentURIObject.equals(channel.originalURI)) {
-          // Double check the url is still the correct one.
-          let actions = converter.createChromeActions(domWindow,
-                                                      domWindow.document,
-                                                      converter.getUrlHint(originalURI));
-          if (!isShumwayEnabledFor(actions)) {
-            actions.fallback(true);
-            return;
-          }
+        let actions = converter.createChromeActions(domWindow,
+                                                    domWindow.document,
+                                                    converter.getUrlHint(originalURI));
+
+        if (!isShumwayEnabledFor(actions)) {
+          actions.fallback(true);
+          return;
+        }
 
-          // Report telemetry on amount of swfs on the page
-          if (actions.isOverlay) {
-            // Looking for last actions with same baseUrl
-            var prevPageActions = ActivationQueue.findLastOnPage(actions.baseUrl);
-            var pageIndex = !prevPageActions ? 1 : (prevPageActions.telemetry.pageIndex + 1);
-            actions.telemetry.pageIndex = pageIndex;
-            ShumwayTelemetry.onPageIndex(pageIndex);
-          } else {
-            ShumwayTelemetry.onPageIndex(0);
-          }
+        // Report telemetry on amount of swfs on the page
+        if (actions.isOverlay) {
+          // Looking for last actions with same baseUrl
+          var prevPageActions = ActivationQueue.findLastOnPage(actions.baseUrl);
+          var pageIndex = !prevPageActions ? 1 : (prevPageActions.telemetry.pageIndex + 1);
+          actions.telemetry.pageIndex = pageIndex;
+          ShumwayTelemetry.onPageIndex(pageIndex);
+        } else {
+          ShumwayTelemetry.onPageIndex(0);
+        }
 
-          actions.activationCallback = function(domWindow, isSimpleMode) {
-            delete this.activationCallback;
-            activateShumwayScripts(domWindow, isSimpleMode);
-          }.bind(actions, domWindow, isSimpleMode);
-          ActivationQueue.enqueue(actions);
+        actions.activationCallback = function(domWindow, isSimpleMode) {
+          delete this.activationCallback;
+          activateShumwayScripts(domWindow, isSimpleMode);
+        }.bind(actions, domWindow, isSimpleMode);
+        ActivationQueue.enqueue(actions);
 
-          let requestListener = new RequestListener(actions);
-          domWindow.addEventListener('shumway.message', function(event) {
-            requestListener.receive(event);
-          }, false, true);
-        }
-        listener.onStopRequest.apply(listener, arguments);
+        let requestListener = new RequestListener(actions);
+        domWindow.addEventListener('shumway.message', function(event) {
+          requestListener.receive(event);
+        }, false, true);
+
+        listener.onStopRequest(aRequest, context, statusCode);
       }
     };
 
-    // XXX? Keep the URL the same so the browser sees it as the same.
-    // channel.originalURI = aRequest.URI;
+    // Keep the URL the same so the browser sees it as the same.
+    channel.originalURI = aRequest.URI;
+    channel.loadGroup = aRequest.loadGroup;
+
+    // We can use resource principal when data is fetched by the chrome
+    // e.g. useful for NoScript
+    var securityManager = Cc['@mozilla.org/scriptsecuritymanager;1']
+                          .getService(Ci.nsIScriptSecurityManager);
+    var uri = Services.io.newURI(viewerUrl, null, null);
+    var resourcePrincipal = securityManager.getNoAppCodebasePrincipal(uri);
+    aRequest.owner = resourcePrincipal;
     channel.asyncOpen(proxy, aContext);
   },
 
   // nsIRequestObserver::onStopRequest
   onStopRequest: function(aRequest, aContext, aStatusCode) {
     // Do nothing.
   }
 };
@@ -938,22 +969,11 @@ copyProperties(ShumwayStreamConverter.pr
 
 function ShumwayStreamOverlayConverter() {}
 ShumwayStreamOverlayConverter.prototype = new ShumwayStreamConverterBase();
 copyProperties(ShumwayStreamOverlayConverter.prototype, {
   classID: Components.ID('{4c6030f7-e20a-264f-5f9b-ada3a9e97384}'),
   classDescription: 'Shumway PlayPreview Component',
   contractID: '@mozilla.org/streamconv;1?from=application/x-moz-playpreview&to=*/*'
 });
-ShumwayStreamOverlayConverter.prototype.isValidRequest =
-  (function(aCtxt) {
-    try {
-      var request = aCtxt;
-      request.QueryInterface(Ci.nsIChannel);
-      var spec = request.URI.spec;
-      return spec.indexOf(EXPECTED_PLAYPREVIEW_URI_PREFIX) === 0;
-    } catch (e) {
-      return false;
-    }
-  });
 ShumwayStreamOverlayConverter.prototype.getUrlHint = function (requestUrl) {
   return '';
 };
index 0f9c67914b5135a8fbda922d10a03e2335fef5a1..cfa75d6d6ac01339a1ed2190e1114a05627c411d
GIT binary patch
literal 26532
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
XZ;VF`+o|>&)_!A{r*mi@&FudH(AxN#
index 28ccc19e9f2b077360be111ff8bf6e66731c6403..53a0322aad8d22d0384443adc5a89a881df5a345
GIT binary patch
literal 81420
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
M$@x*dfN$6Qe;cnv^Z)<=
--- a/browser/extensions/shumway/content/shumway-worker.js
+++ b/browser/extensions/shumway/content/shumway-worker.js
@@ -151,32 +151,47 @@
       for (var i = 0; i < size; i++)
         view._bytes[offset + i] = temp[size - 1 - i];
     }
   }
   function fail(msg) {
     throw new Error(msg);
   }
 }(this));
+var create = Object.create;
+var defineProperty = Object.defineProperty;
+var keys = Object.keys;
+var isArray = Array.isArray;
+var fromCharCode = String.fromCharCode;
+var logE = Math.log;
+var max = Math.max;
+var min = Math.min;
+var pow = Math.pow;
+var push = Array.prototype.push;
+var slice = Array.prototype.slice;
+var splice = Array.prototype.splice;
+function fail(msg, context) {
+  throw new Error((context ? context + ': ' : '') + msg);
+}
+function assert(cond, msg, context) {
+  if (!cond)
+    fail(msg, context);
+}
 function scriptProperties(namespace, props) {
   return props.reduce(function (o, p) {
     o[p] = namespace + ' ' + p;
     return o;
   }, {});
 }
 function cloneObject(obj) {
   var clone = Object.create(null);
   for (var prop in obj)
     clone[prop] = obj[prop];
   return clone;
 }
-function throwError(name, error) {
-  var message = formatErrorMessage.apply(null, slice.call(arguments, 1));
-  throwErrorFromVM(AVM2.currentDomain(), name, message, error.code);
-}
 function sortByDepth(a, b) {
   var levelA = a._level;
   var levelB = b._level;
   if (a._parent !== b._parent && a._index > -1 && b._index > -1) {
     while (a._level > levelB) {
       a = a._parent;
     }
     while (b._level > levelA) {
@@ -193,16 +208,99 @@ function sortByDepth(a, b) {
   if (a === b) {
     return levelA - levelB;
   }
   return a._index - b._index;
 }
 function sortNumeric(a, b) {
   return a - b;
 }
+function rgbaObjToStr(color) {
+  return 'rgba(' + color.red + ',' + color.green + ',' + color.blue + ',' + color.alpha / 255 + ')';
+}
+function rgbIntAlphaToStr(color, alpha) {
+  color |= 0;
+  if (alpha >= 1) {
+    var colorStr = color.toString(16);
+    while (colorStr.length < 6) {
+      colorStr = '0' + colorStr;
+    }
+    return '#' + colorStr;
+  }
+  var red = color >> 16 & 255;
+  var green = color >> 8 & 255;
+  var blue = color & 255;
+  return 'rgba(' + red + ',' + green + ',' + blue + ',' + alpha + ')';
+}
+function argbUintToStr(argb) {
+  return 'rgba(' + (argb >>> 16 & 255) + ',' + (argb >>> 8 & 255) + ',' + (argb & 255) + ',' + (argb >>> 24 & 255) / 255 + ')';
+}
+(function functionNameSupport() {
+  if (eval('function t() {} t.name === \'t\'')) {
+    return;
+  }
+  Object.defineProperty(Function.prototype, 'name', {
+    get: function () {
+      if (this.__name) {
+        return this.__name;
+      }
+      var m = /function\s([^\(]+)/.exec(this.toString());
+      var name = m && m[1] !== 'anonymous' ? m[1] : null;
+      this.__name = name;
+      return name;
+    },
+    configurable: true,
+    enumerable: false
+  });
+}());
+var randomStyleCache;
+var nextStyle = 0;
+function randomStyle() {
+  if (!randomStyleCache) {
+    randomStyleCache = [
+      '#ff5e3a',
+      '#ff9500',
+      '#ffdb4c',
+      '#87fc70',
+      '#52edc7',
+      '#1ad6fd',
+      '#c644fc',
+      '#ef4db6',
+      '#4a4a4a',
+      '#dbddde',
+      '#ff3b30',
+      '#ff9500',
+      '#ffcc00',
+      '#4cd964',
+      '#34aadc',
+      '#007aff',
+      '#5856d6',
+      '#ff2d55',
+      '#8e8e93',
+      '#c7c7cc',
+      '#5ad427',
+      '#c86edf',
+      '#d1eefc',
+      '#e0f8d8',
+      '#fb2b69',
+      '#f7f7f7',
+      '#1d77ef',
+      '#d6cec3',
+      '#55efcb',
+      '#ff4981',
+      '#ffd3e0',
+      '#f7f7f7',
+      '#ff1300',
+      '#1f1f21',
+      '#bdbec2',
+      '#ff3a2d'
+    ];
+  }
+  return randomStyleCache[nextStyle++ % randomStyleCache.length];
+}
 var Promise = function PromiseClosure() {
     function isPromise(obj) {
       return typeof obj === 'object' && obj !== null && typeof obj.then === 'function';
     }
     function defaultOnFulfilled(value) {
       return value;
     }
     function defaultOnRejected(reason) {
@@ -445,83 +543,16 @@ var VIDEO_FEATURE = 4;
 var SOUND_FEATURE = 5;
 var NETCONNECTION_FEATURE = 6;
 if (!this.performance) {
   this.performance = {};
 }
 if (!this.performance.now) {
   this.performance.now = Date.now;
 }
-var create = Object.create;
-var defineProperty = Object.defineProperty;
-var keys = Object.keys;
-var isArray = Array.isArray;
-var fromCharCode = String.fromCharCode;
-var logE = Math.log;
-var max = Math.max;
-var min = Math.min;
-var pow = Math.pow;
-var push = Array.prototype.push;
-var slice = Array.prototype.slice;
-var splice = Array.prototype.splice;
-function fail(msg, context) {
-  throw new Error((context ? context + ': ' : '') + msg);
-}
-function assert(cond, msg, context) {
-  if (!cond)
-    fail(msg, context);
-}
-function rgbaObjToStr(color) {
-  return 'rgba(' + color.red + ',' + color.green + ',' + color.blue + ',' + color.alpha / 255 + ')';
-}
-function rgbIntAlphaToStr(color, alpha) {
-  color |= 0;
-  if (alpha >= 1) {
-    var colorStr = color.toString(16);
-    while (colorStr.length < 6) {
-      colorStr = '0' + colorStr;
-    }
-    return '#' + colorStr;
-  }
-  var red = color >> 16 & 255;
-  var green = color >> 8 & 255;
-  var blue = color & 255;
-  return 'rgba(' + red + ',' + green + ',' + blue + ',' + alpha + ')';
-}
-function argbUintToStr(argb) {
-  return 'rgba(' + (argb >>> 16 & 255) + ',' + (argb >>> 8 & 255) + ',' + (argb & 255) + ',' + (argb >>> 24 & 255) / 255 + ')';
-}
-(function functionNameSupport() {
-  if (eval('function t() {} t.name === \'t\'')) {
-    return;
-  }
-  Object.defineProperty(Function.prototype, 'name', {
-    get: function () {
-      if (this.__name) {
-        return this.__name;
-      }
-      var m = /function\s([^\(]+)/.exec(this.toString());
-      var name = m && m[1] !== 'anonymous' ? m[1] : null;
-      this.__name = name;
-      return name;
-    },
-    configurable: true,
-    enumerable: false
-  });
-}());
-var randomStyleCache;
-function randomStyle() {
-  if (!randomStyleCache) {
-    randomStyleCache = [];
-    for (var i = 0; i < 50; i++) {
-      randomStyleCache.push('#' + ('00000' + (Math.random() * (1 << 24) | 0).toString(16)).slice(-6));
-    }
-  }
-  return randomStyleCache[Math.random() * randomStyleCache.length | 0];
-}
 var SWF_TAG_CODE_CSM_TEXT_SETTINGS = 74;
 var SWF_TAG_CODE_DEFINE_BINARY_DATA = 87;
 var SWF_TAG_CODE_DEFINE_BITS = 6;
 var SWF_TAG_CODE_DEFINE_BITS_JPEG2 = 21;
 var SWF_TAG_CODE_DEFINE_BITS_JPEG3 = 35;
 var SWF_TAG_CODE_DEFINE_BITS_JPEG4 = 90;
 var SWF_TAG_CODE_DEFINE_BITS_LOSSLESS = 20;
 var SWF_TAG_CODE_DEFINE_BITS_LOSSLESS2 = 36;
@@ -1359,26 +1390,26 @@ function applySegmentToStyles(segment, s
     if (isMorph) {
     }
   }
   if (styles.line && styles.fill1) {
     path = linePaths[styles.line - 1];
     path.addSegment(commands, data, morphData);
   }
 }
-function convertRecordsToStyledPaths(records, fillPaths, linePaths, dictionary, dependencies, recordsMorph) {
+function convertRecordsToStyledPaths(records, fillPaths, linePaths, dictionary, dependencies, recordsMorph, transferables) {
   var isMorph = recordsMorph !== null;
   var styles = {
       fill0: 0,
       fill1: 0,
       line: 0
     };
   var segment = null;
-  var allFillPaths = fillPaths;
-  var allLinePaths = linePaths;
+  var allPaths;
+  var defaultPath;
   var numRecords = records.length - 1;
   var x = 0;
   var y = 0;
   var morphX = 0;
   var morphY = 0;
   var path;
   for (var i = 0, j = 0; i < numRecords; i++) {
     var record = records[i];
@@ -1386,20 +1417,27 @@ function convertRecordsToStyledPaths(rec
     if (isMorph) {
       morphRecord = recordsMorph[j++];
     }
     if (record.type === 0) {
       if (segment) {
         applySegmentToStyles(segment, styles, linePaths, fillPaths, isMorph);
       }
       if (record.hasNewStyles) {
+        if (!allPaths) {
+          allPaths = [];
+        }
+        push.apply(allPaths, fillPaths);
         fillPaths = createPathsList(record.fillStyles, false, dictionary, dependencies);
-        push.apply(allFillPaths, fillPaths);
+        push.apply(allPaths, linePaths);
         linePaths = createPathsList(record.lineStyles, true, dictionary, dependencies);
-        push.apply(allLinePaths, linePaths);
+        if (defaultPath) {
+          allPaths.push(defaultPath);
+          defaultPath = null;
+        }
         styles = {
           fill0: 0,
           fill1: 0,
           line: 0
         };
       }
       if (record.hasFillStyle0) {
         styles.fill0 = record.fillStyle0;
@@ -1433,17 +1471,43 @@ function convertRecordsToStyledPaths(rec
             morphX = x;
             morphY = y;
             j--;
           }
           segment.morphData.push(morphX, morphY);
         }
       }
     } else {
+      if (!segment) {
+        if (!defaultPath) {
+          var style = {
+              color: {
+                red: 0,
+                green: 0,
+                blue: 0,
+                alpha: 255
+              },
+              width: 20
+            };
+          defaultPath = new SegmentedPath(null, processStyle(style, true));
+        }
+        segment = defaultPath.addSegment([], [], isMorph ? [] : null);
+        segment.commands.push(SHAPE_MOVE_TO);
+        segment.data.push(x, y);
+        if (isMorph) {
+          segment.morphData.push(morphX, morphY);
+        }
+      }
       if (isMorph) {
+        while (morphRecord && morphRecord.type === 0) {
+          morphRecord = recordsMorph[j++];
+        }
+        if (!morphRecord) {
+          morphRecord = record;
+        }
       }
       if (record.isStraight && (!isMorph || morphRecord.isStraight)) {
         x += record.deltaX | 0;
         y += record.deltaY | 0;
         segment.commands.push(SHAPE_LINE_TO);
         segment.data.push(x, y);
         if (isMorph) {
           morphX += morphRecord.deltaX | 0;
@@ -1483,30 +1547,38 @@ function convertRecordsToStyledPaths(rec
             morphY += deltaY;
           }
           segment.morphData.push(cx, cy, morphX, morphY);
         }
       }
     }
   }
   applySegmentToStyles(segment, styles, linePaths, fillPaths, isMorph);
-  push.apply(allFillPaths, allLinePaths);
+  if (allPaths) {
+    push.apply(allPaths, fillPaths);
+  } else {
+    allPaths = fillPaths;
+  }
+  push.apply(allPaths, linePaths);
+  if (defaultPath) {
+    allPaths.push(defaultPath);
+  }
   var removeCount = 0;
-  for (i = 0; i < allFillPaths.length; i++) {
-    path = allFillPaths[i];
+  for (i = 0; i < allPaths.length; i++) {
+    path = allPaths[i];
     if (!path.head()) {
       removeCount++;
       continue;
     }
-    allFillPaths[i - removeCount] = segmentedPathToShapePath(path, isMorph);
+    allPaths[i - removeCount] = segmentedPathToShapePath(path, isMorph, transferables);
   }
-  allFillPaths.length -= removeCount;
-  return allFillPaths;
+  allPaths.length -= removeCount;
+  return allPaths;
 }
-function segmentedPathToShapePath(path, isMorph) {
+function segmentedPathToShapePath(path, isMorph, transferables) {
   var start = path.head();
   var end = start;
   var finalRoot = null;
   var finalHead = null;
   var skippedMoves = 0;
   var current = start.prev;
   while (start) {
     while (current) {
@@ -1551,31 +1623,28 @@ function segmentedPathToShapePath(path, 
   var totalCommandsLength = -skippedMoves;
   var totalDataLength = -skippedMoves << 1;
   current = finalRoot;
   while (current) {
     totalCommandsLength += current.commands.length;
     totalDataLength += current.data.length;
     current = current.next;
   }
-  var shape = new ShapePath(path.fillStyle, path.lineStyle, totalCommandsLength, totalDataLength, isMorph);
+  var shape = new ShapePath(path.fillStyle, path.lineStyle, totalCommandsLength, totalDataLength, isMorph, transferables);
   var allCommands = shape.commands;
   var allData = shape.data;
   var allMorphData = shape.morphData;
   var commandsIndex = 0;
   var dataIndex = 0;
   current = finalRoot;
   while (current) {
-    var offset = 0;
     var commands = current.commands;
     var data = current.data;
     var morphData = current.morphData;
-    if (data[0] === allData[dataIndex - 2] && data[1] === allData[dataIndex - 1]) {
-      offset = 1;
-    }
+    var offset = +(data[0] === allData[dataIndex - 2] && data[1] === allData[dataIndex - 1]);
     for (var i = offset; i < commands.length; i++, commandsIndex++) {
       allCommands[commandsIndex] = commands[i];
     }
     for (i = offset << 1; i < data.length; i++, dataIndex++) {
       allData[dataIndex] = data[i];
       if (isMorph) {
         allMorphData[dataIndex] = morphData[i];
       }
@@ -1593,17 +1662,17 @@ var JOIN_STYLE_TYPES = [
     'round',
     'bevel',
     'miter'
   ];
 function processStyle(style, isLineStyle, dictionary, dependencies) {
   if (isLineStyle) {
     style.lineCap = CAPS_STYLE_TYPES[style.endCapStyle | 0];
     style.lineJoin = JOIN_STYLE_TYPES[style.joinStyle | 0];
-    style.miterLimit = style.miterLimitFactor * 2;
+    style.miterLimit = (style.miterLimitFactor || 1.5) * 2;
     if (!style.color && style.hasFill) {
       var fillStyle = processStyle(style.fillStyle, false, dictionary, dependencies);
       style.style = fillStyle.style;
       style.type = fillStyle.type;
       style.transform = fillStyle.transform;
       style.records = fillStyle.records;
       style.focalPoint = fillStyle.focalPoint;
       style.bitmapId = fillStyle.bitmapId;
@@ -1662,19 +1731,20 @@ function createPathsList(styles, isLineS
     } else {
       paths[i] = new SegmentedPath(null, style);
     }
   }
   return paths;
 }
 function defineShape(tag, dictionary) {
   var dependencies = [];
+  var transferables = [];
   var fillPaths = createPathsList(tag.fillStyles, false, dictionary, dependencies);
   var linePaths = createPathsList(tag.lineStyles, true, dictionary, dependencies);
-  var paths = convertRecordsToStyledPaths(tag.records, fillPaths, linePaths, dictionary, dependencies, tag.recordsMorph || null);
+  var paths = convertRecordsToStyledPaths(tag.records, fillPaths, linePaths, dictionary, dependencies, tag.recordsMorph || null, transferables);
   if (tag.bboxMorph) {
     var mbox = tag.bboxMorph;
     extendBoundsByPoint(tag.bbox, mbox.xMin, mbox.yMin);
     extendBoundsByPoint(tag.bbox, mbox.xMax, mbox.yMax);
     mbox = tag.strokeBboxMorph;
     if (mbox) {
       extendBoundsByPoint(tag.strokeBbox, mbox.xMin, mbox.yMin);
       extendBoundsByPoint(tag.strokeBbox, mbox.xMax, mbox.yMax);
@@ -1684,19 +1754,26 @@ function defineShape(tag, dictionary) {
     type: 'shape',
     id: tag.id,
     strokeBbox: tag.strokeBbox,
     strokeBboxMorph: tag.strokeBboxMorph,
     bbox: tag.bbox,
     bboxMorph: tag.bboxMorph,
     isMorph: tag.isMorph,
     paths: paths,
-    require: dependencies.length ? dependencies : null
+    require: dependencies.length ? dependencies : null,
+    transferables: transferables
   };
 }
+function logShape(paths, bbox) {
+  var output = '{"bounds":' + JSON.stringify(bbox) + ',"paths":[' + paths.map(function (path) {
+      return path.serialize();
+    }).join() + ']}';
+  console.log(output);
+}
 function SegmentedPath(fillStyle, lineStyle) {
   this.fillStyle = fillStyle;
   this.lineStyle = lineStyle;
   this._head = null;
 }
 SegmentedPath.prototype = {
   addSegment: function (commands, data, morphData) {
     var segment = {
@@ -1740,31 +1817,44 @@ SegmentedPath.prototype = {
 var SHAPE_MOVE_TO = 1;
 var SHAPE_LINE_TO = 2;
 var SHAPE_CURVE_TO = 3;
 var SHAPE_WIDE_MOVE_TO = 4;
 var SHAPE_WIDE_LINE_TO = 5;
 var SHAPE_CUBIC_CURVE_TO = 6;
 var SHAPE_CIRCLE = 7;
 var SHAPE_ELLIPSE = 8;
-function ShapePath(fillStyle, lineStyle, commandsCount, dataLength, isMorph) {
+function ShapePath(fillStyle, lineStyle, commandsCount, dataLength, isMorph, transferables) {
   this.fillStyle = fillStyle;
   this.lineStyle = lineStyle;
   if (commandsCount) {
     this.commands = new Uint8Array(commandsCount);
     this.data = new Int32Array(dataLength);
     this.morphData = isMorph ? new Int32Array(dataLength) : null;
   } else {
     this.commands = [];
     this.data = [];
   }
   this.bounds = null;
   this.strokeBounds = null;
-  this.isMorph = isMorph;
+  this.isMorph = !(!isMorph);
   this.fullyInitialized = false;
+  if (inWorker) {
+    this.buffers = [
+      this.commands.buffer,
+      this.data.buffer
+    ];
+    transferables.push(this.commands.buffer, this.data.buffer);
+    if (isMorph) {
+      this.buffers.push(this.morphData.buffer);
+      transferables.push(this.morphData.buffer);
+    }
+  } else {
+    this.buffers = null;
+  }
 }
 ShapePath.prototype = {
   moveTo: function (x, y) {
     if (this.commands[this.commands.length - 1] === SHAPE_MOVE_TO) {
       this.data[this.data.length - 2] = x;
       this.data[this.data.length - 1] = y;
       return;
     }
@@ -1803,18 +1893,18 @@ ShapePath.prototype = {
     }
     ctx.beginPath();
     var commands = this.commands;
     var data = this.data;
     var morphData = this.morphData;
     var formOpen = false;
     var formOpenX = 0;
     var formOpenY = 0;
-    for (var j = 0, k = 0; j < commands.length; j++) {
-      if (!this.isMorph) {
+    if (!this.isMorph) {
+      for (var j = 0, k = 0; j < commands.length; j++) {
         switch (commands[j]) {
         case SHAPE_MOVE_TO:
           formOpen = true;
           formOpenX = data[k++] / 20;
           formOpenY = data[k++] / 20;
           ctx.moveTo(formOpenX, formOpenY);
           break;
         case SHAPE_WIDE_MOVE_TO:
@@ -1869,19 +1959,24 @@ ShapePath.prototype = {
           }
           ctx.moveTo((x + radius) / 20, y / 20);
           ctx.arc(x / 20, y / 20, radius / 20, 0, Math.PI * 2, false);
           if (rX !== rY) {
             ctx.restore();
           }
           break;
         default:
+          if (commands[j] === 0 && j === commands.length - 1) {
+            break;
+          }
           console.warn('Unknown drawing command encountered: ' + commands[j]);
         }
-      } else {
+      }
+    } else {
+      for (var j = 0, k = 0; j < commands.length; j++) {
         switch (commands[j]) {
         case SHAPE_MOVE_TO:
           ctx.moveTo(morph(data[k] / 20, morphData[k++] / 20, ratio), morph(data[k] / 20, morphData[k++] / 20, ratio));
           break;
         case SHAPE_LINE_TO:
           ctx.lineTo(morph(data[k] / 20, morphData[k++] / 20, ratio), morph(data[k] / 20, morphData[k++] / 20, ratio));
           break;
         case SHAPE_CURVE_TO:
@@ -2354,18 +2449,39 @@ ShapePath.prototype = {
         xMax: bounds.xMax + halfLineWidth,
         yMax: bounds.yMax + halfLineWidth
       };
       return this.strokeBounds;
     } else {
       this.strokeBounds = bounds;
     }
     return bounds;
+  },
+  serialize: function () {
+    var output = '{';
+    if (this.fillStyle) {
+      output += '"fill":' + JSON.stringify(this.fillStyle) + ',';
+    }
+    if (this.lineStyle) {
+      output += '"stroke":' + JSON.stringify(this.lineStyle) + ',';
+    }
+    output += '"commands":[' + Array.apply([], this.commands).join() + '],';
+    output += '"data":[' + Array.apply([], this.data).join() + ']';
+    return output + '}';
   }
 };
+ShapePath.fromPlainObject = function (obj) {
+  var path = new ShapePath(obj.fill || null, obj.stroke || null);
+  path.commands = new Uint8Array(obj.commands);
+  path.data = new Int32Array(obj.data);
+  if (!inWorker) {
+    finishShapePath(path);
+  }
+  return path;
+};
 function distanceSq(x1, y1, x2, y2) {
   var dX = x2 - x1;
   var dY = y2 - y1;
   return dX * dX + dY * dY;
 }
 function intersectsLine(x, y, x1, y1, x2, y2) {
   return y2 > y !== y1 > y && x < (x1 - x2) * (y - y2) / (y1 - y2) + x2;
 }
@@ -2573,64 +2689,89 @@ function extendBoundsByY(bounds, y) {
     bounds.yMin = y;
   } else if (y > bounds.yMax) {
     bounds.yMax = y;
   }
 }
 function morph(start, end, ratio) {
   return start + (end - start) * ratio;
 }
-function finishShapePaths(paths, dictionary) {
-  for (var i = 0; i < paths.length; i++) {
-    var path = paths[i];
-    if (path.fullyInitialized) {
-      continue;
-    }
-    if (!(path instanceof ShapePath)) {
-      var untypedPath = path;
-      path = paths[i] = new ShapePath(path.fillStyle, path.lineStyle, 0, 0, path.isMorph);
-      path.commands = untypedPath.commands;
-      path.data = untypedPath.data;
-      path.morphData = untypedPath.morphData;
-    }
-    path.fillStyle && initStyle(path.fillStyle, dictionary);
-    path.lineStyle && initStyle(path.lineStyle, dictionary);
-    path.fullyInitialized = true;
+function finishShapePath(path, dictionary) {
+  if (path.fullyInitialized) {
+    return path;
   }
+  if (!(path instanceof ShapePath)) {
+    var untypedPath = path;
+    path = new ShapePath(path.fillStyle, path.lineStyle, 0, 0, path.isMorph);
+    path.commands = new Uint8Array(untypedPath.buffers[0]);
+    path.data = new Int32Array(untypedPath.buffers[1]);
+    if (untypedPath.isMorph) {
+      path.morphData = new Int32Array(untypedPath.buffers[2]);
+    }
+    path.buffers = null;
+  }
+  path.fillStyle && initStyle(path.fillStyle, dictionary);
+  path.lineStyle && initStyle(path.lineStyle, dictionary);
+  path.fullyInitialized = true;
+  return path;
 }
 var inWorker = typeof window === 'undefined';
 var factoryCtx = !inWorker ? document.createElement('canvas').getContext('2d') : null;
 function buildLinearGradientFactory(colorStops) {
   var defaultGradient = factoryCtx.createLinearGradient(-1, 0, 1, 0);
   for (var i = 0; i < colorStops.length; i++) {
     defaultGradient.addColorStop(colorStops[i].ratio, colorStops[i].color);
   }
   var fn = function createLinearGradient(ctx, colorTransform) {
     var gradient = ctx.createLinearGradient(-1, 0, 1, 0);
     for (var i = 0; i < colorStops.length; i++) {
       colorTransform.addGradientColorStop(gradient, colorStops[i].ratio, colorStops[i].color);
     }
     return gradient;
   };
-  fn.defaultGradient = defaultGradient;
+  fn.defaultFillStyle = defaultGradient;
   return fn;
 }
 function buildRadialGradientFactory(focalPoint, colorStops) {
   var defaultGradient = factoryCtx.createRadialGradient(focalPoint, 0, 0, 0, 0, 1);
   for (var i = 0; i < colorStops.length; i++) {
     defaultGradient.addColorStop(colorStops[i].ratio, colorStops[i].color);
   }
   var fn = function createRadialGradient(ctx, colorTransform) {
     var gradient = ctx.createRadialGradient(focalPoint, 0, 0, 0, 0, 1);
     for (var i = 0; i < colorStops.length; i++) {
       colorTransform.addGradientColorStop(gradient, colorStops[i].ratio, colorStops[i].color);
     }
     return gradient;
   };
-  fn.defaultGradient = defaultGradient;
+  fn.defaultFillStyle = defaultGradient;
+  return fn;
+}
+function buildBitmapPatternFactory(img, repeat) {
+  var defaultPattern = factoryCtx.createPattern(img, repeat);
+  var cachedTransform, cachedTransformKey;
+  var fn = function createBitmapPattern(ctx, colorTransform) {
+    if (!colorTransform.mode) {
+      return defaultPattern;
+    }
+    var key = colorTransform.getTransformFingerprint();
+    if (key === cachedTransformKey) {
+      return cachedTransform;
+    }
+    var canvas = document.createElement('canvas');
+    canvas.width = img.width;
+    canvas.height = img.height;
+    var ctx = canvas.getContext('2d');
+    colorTransform.setAlpha(ctx, true);
+    ctx.drawImage(img, 0, 0);
+    cachedTransform = ctx.createPattern(canvas, repeat);
+    cachedTransformKey = key;
+    return cachedTransform;
+  };
+  fn.defaultFillStyle = defaultPattern;
   return fn;
 }
 function initStyle(style, dictionary) {
   if (style.type === undefined) {
     return;
   }
   switch (style.type) {
   case GRAPHICS_FILL_SOLID:
@@ -2657,17 +2798,17 @@ function initStyle(style, dictionary) {
     style.style = gradientConstructor;
     break;
   case GRAPHICS_FILL_REPEATING_BITMAP:
   case GRAPHICS_FILL_CLIPPED_BITMAP:
   case GRAPHICS_FILL_NONSMOOTHED_REPEATING_BITMAP:
   case GRAPHICS_FILL_NONSMOOTHED_CLIPPED_BITMAP:
     var bitmap = dictionary[style.bitmapId];
     var repeat = style.type === GRAPHICS_FILL_REPEATING_BITMAP || style.type === GRAPHICS_FILL_NONSMOOTHED_REPEATING_BITMAP;
-    style.style = factoryCtx.createPattern(bitmap.value.props.img, repeat ? 'repeat' : 'no-repeat');
+    style.style = buildBitmapPatternFactory(bitmap.value.props.img, repeat ? 'repeat' : 'no-repeat');
     break;
   default:
     fail('invalid fill style', 'shape');
   }
 }
 var SOUND_SIZE_8_BIT = 0;
 var SOUND_SIZE_16_BIT = 1;
 var SOUND_TYPE_MONO = 0;
@@ -3115,1153 +3256,417 @@ function defineText(tag, dictionary) {
       variableName: tag.variableName,
       tag: tag
     };
   if (dependencies.length)
     props.require = dependencies;
   return props;
 }
 var $RELEASE = false;
-var LoaderDefinition = function () {
-    var WORKERS_ENABLED = true;
-    var LOADER_PATH;
-    var workerScripts;
-    if (true) {
-      LOADER_PATH = 'shumway-worker.js';
-    } else {
-      LOADER_PATH = 'flash/display/Loader.js';
-      workerScripts = [
-        '../../../lib/DataView.js/DataView.js',
-        '../util.js',
-        '../../swf/config.js',
-        '../../swf/util.js',
-        '../../swf/swf.js',
-        '../../swf/types.js',
-        '../../swf/structs.js',
-        '../../swf/tags.js',
-        '../../swf/inflate.js',
-        '../../swf/stream.js',
-        '../../swf/templates.js',
-        '../../swf/generator.js',
-        '../../swf/handlers.js',
-        '../../swf/parser.js',
-        '../../swf/bitmap.js',
-        '../../swf/button.js',
-        '../../swf/font.js',
-        '../../swf/image.js',
-        '../../swf/label.js',
-        '../../swf/shape.js',
-        '../../swf/sound.js',
-        '../../swf/text.js'
-      ];
-    }
-    var isWorker = typeof window === 'undefined';
-    function loadFromWorker(loader, request, context) {
-      var symbols = {};
-      var commitData;
-      if (loader) {
-        commitData = function (data) {
-          return loader._commitData(data);
-        };
-      } else {
-        commitData = function (data) {
-          self.postMessage(data);
+var isWorker = typeof window === 'undefined';
+if (isWorker && !true) {
+  importScripts.apply(null, [
+    '../../lib/DataView.js/DataView.js',
+    '../flash/util.js',
+    'config.js',
+    'swf.js',
+    'types.js',
+    'structs.js',
+    'tags.js',
+    'inflate.js',
+    'stream.js',
+    'templates.js',
+    'generator.js',
+    'handlers.js',
+    'parser.js',
+    'bitmap.js',
+    'button.js',
+    'font.js',
+    'image.js',
+    'label.js',
+    'shape.js',
+    'sound.js',
+    'text.js'
+  ]);
+}
+function defineSymbol(swfTag, symbols) {
+  var symbol;
+  switch (swfTag.code) {
+  case SWF_TAG_CODE_DEFINE_BITS:
+  case SWF_TAG_CODE_DEFINE_BITS_JPEG2:
+  case SWF_TAG_CODE_DEFINE_BITS_JPEG3:
+  case SWF_TAG_CODE_DEFINE_BITS_JPEG4:
+  case SWF_TAG_CODE_JPEG_TABLES:
+    symbol = defineImage(swfTag, symbols);
+    break;
+  case SWF_TAG_CODE_DEFINE_BITS_LOSSLESS:
+  case SWF_TAG_CODE_DEFINE_BITS_LOSSLESS2:
+    symbol = defineBitmap(swfTag);
+    break;
+  case SWF_TAG_CODE_DEFINE_BUTTON:
+  case SWF_TAG_CODE_DEFINE_BUTTON2:
+    symbol = defineButton(swfTag, symbols);
+    break;
+  case SWF_TAG_CODE_DEFINE_EDIT_TEXT:
+    symbol = defineText(swfTag, symbols);
+    break;
+  case SWF_TAG_CODE_DEFINE_FONT:
+  case SWF_TAG_CODE_DEFINE_FONT2:
+  case SWF_TAG_CODE_DEFINE_FONT3:
+  case SWF_TAG_CODE_DEFINE_FONT4:
+    symbol = defineFont(swfTag, symbols);
+    break;
+  case SWF_TAG_CODE_DEFINE_MORPH_SHAPE:
+  case SWF_TAG_CODE_DEFINE_MORPH_SHAPE2:
+  case SWF_TAG_CODE_DEFINE_SHAPE:
+  case SWF_TAG_CODE_DEFINE_SHAPE2:
+  case SWF_TAG_CODE_DEFINE_SHAPE3:
+  case SWF_TAG_CODE_DEFINE_SHAPE4:
+    symbol = defineShape(swfTag, symbols);
+    break;
+  case SWF_TAG_CODE_DEFINE_SOUND:
+    symbol = defineSound(swfTag, symbols);
+    break;
+  case SWF_TAG_CODE_DEFINE_BINARY_DATA:
+    symbol = {
+      type: 'binary',
+      id: swfTag.id,
+      data: swfTag.data
+    };
+    break;
+  case SWF_TAG_CODE_DEFINE_SPRITE:
+    var depths = {};
+    var frame = {
+        type: 'frame'
+      };
+    var frames = [];
+    var tags = swfTag.tags;
+    var frameScripts = null;
+    var frameIndex = 0;
+    var soundStream = null;
+    for (var i = 0, n = tags.length; i < n; i++) {
+      var tag = tags[i];
+      switch (tag.code) {
+      case SWF_TAG_CODE_DO_ACTION:
+        if (!frameScripts)
+          frameScripts = [];
+        frameScripts.push(frameIndex);
+        frameScripts.push(tag.actionsData);
+        break;
+      case SWF_TAG_CODE_START_SOUND:
+        var startSounds = frame.startSounds || (frame.startSounds = []);
+        startSounds.push(tag);
+        break;
+      case SWF_TAG_CODE_SOUND_STREAM_HEAD:
+        try {
+          soundStream = createSoundStream(tag);
+          frame.soundStream = soundStream.info;
+        } catch (e) {
+        }
+        break;
+      case SWF_TAG_CODE_SOUND_STREAM_BLOCK:
+        if (soundStream) {
+          frame.soundStreamBlock = soundStream.decode(tag.data);
+        }
+        break;
+      case SWF_TAG_CODE_FRAME_LABEL:
+        frame.labelName = tag.name;
+        break;
+      case SWF_TAG_CODE_PLACE_OBJECT:
+      case SWF_TAG_CODE_PLACE_OBJECT2:
+      case SWF_TAG_CODE_PLACE_OBJECT3:
+        depths[tag.depth] = tag;
+        break;
+      case SWF_TAG_CODE_REMOVE_OBJECT:
+      case SWF_TAG_CODE_REMOVE_OBJECT2:
+        depths[tag.depth] = null;
+        break;
+      case SWF_TAG_CODE_SHOW_FRAME:
+        frameIndex += tag.repeat;
+        frame.repeat = tag.repeat;
+        frame.depths = depths;
+        frames.push(frame);
+        depths = {};
+        frame = {
+          type: 'frame'
         };
+        break;
       }
-      function defineSymbol(swfTag) {
-        var symbol;
-        switch (swfTag.code) {
-        case SWF_TAG_CODE_DEFINE_BITS:
-        case SWF_TAG_CODE_DEFINE_BITS_JPEG2:
-        case SWF_TAG_CODE_DEFINE_BITS_JPEG3:
-        case SWF_TAG_CODE_DEFINE_BITS_JPEG4:
-        case SWF_TAG_CODE_JPEG_TABLES:
-          symbol = defineImage(swfTag, symbols);
-          break;
-        case SWF_TAG_CODE_DEFINE_BITS_LOSSLESS:
-        case SWF_TAG_CODE_DEFINE_BITS_LOSSLESS2:
-          symbol = defineBitmap(swfTag, symbols);
-          break;
-        case SWF_TAG_CODE_DEFINE_BUTTON:
-        case SWF_TAG_CODE_DEFINE_BUTTON2:
-          symbol = defineButton(swfTag, symbols);
-          break;
-        case SWF_TAG_CODE_DEFINE_EDIT_TEXT:
-          symbol = defineText(swfTag, symbols);
-          break;
-        case SWF_TAG_CODE_DEFINE_FONT:
-        case SWF_TAG_CODE_DEFINE_FONT2:
-        case SWF_TAG_CODE_DEFINE_FONT3:
-        case SWF_TAG_CODE_DEFINE_FONT4:
-          symbol = defineFont(swfTag, symbols);
-          break;
-        case SWF_TAG_CODE_DEFINE_MORPH_SHAPE:
-        case SWF_TAG_CODE_DEFINE_MORPH_SHAPE2:
-        case SWF_TAG_CODE_DEFINE_SHAPE:
-        case SWF_TAG_CODE_DEFINE_SHAPE2:
-        case SWF_TAG_CODE_DEFINE_SHAPE3:
-        case SWF_TAG_CODE_DEFINE_SHAPE4:
-          symbol = defineShape(swfTag, symbols);
-          break;
-        case SWF_TAG_CODE_DEFINE_SOUND:
-          symbol = defineSound(swfTag, symbols);
-          break;
-        case SWF_TAG_CODE_DEFINE_BINARY_DATA:
-          symbol = {
-            type: 'binary',
-            id: swfTag.id,
-            data: swfTag.data
-          };
+    }
+    symbol = {
+      type: 'sprite',
+      id: swfTag.id,
+      frameCount: swfTag.frameCount,
+      frames: frames,
+      frameScripts: frameScripts
+    };
+    break;
+  case SWF_TAG_CODE_DEFINE_TEXT:
+  case SWF_TAG_CODE_DEFINE_TEXT2:
+    symbol = defineLabel(swfTag, symbols);
+    break;
+  }
+  if (!symbol) {
+    return {
+      command: 'error',
+      message: 'unknown symbol type: ' + swfTag.code
+    };
+  }
+  symbol.isSymbol = true;
+  symbols[swfTag.id] = symbol;
+  return symbol;
+}
+function createParsingContext(commitData) {
+  var depths = {};
+  var symbols = {};
+  var frame = {
+      type: 'frame'
+    };
+  var tagsProcessed = 0;
+  var soundStream = null;
+  var lastProgressSent = 0;
+  return {
+    onstart: function (result) {
+      commitData({
+        command: 'init',
+        result: result
+      });
+    },
+    onprogress: function (result) {
+      if (Date.now() - lastProgressSent > 1000 / 24 || result.bytesLoaded === result.bytesTotal) {
+        commitData({
+          command: 'progress',
+          result: {
+            bytesLoaded: result.bytesLoaded,
+            bytesTotal: result.bytesTotal
+          }
+        });
+        lastProgressSent = Date.now();
+      }
+      var tags = result.tags;
+      for (var n = tags.length; tagsProcessed < n; tagsProcessed++) {
+        var tag = tags[tagsProcessed];
+        if ('id' in tag) {
+          var symbol = defineSymbol(tag, symbols);
+          commitData(symbol, symbol.transferables);
+          continue;
+        }
+        switch (tag.code) {
+        case SWF_TAG_CODE_DEFINE_SCENE_AND_FRAME_LABEL_DATA:
+          frame.sceneData = tag;
           break;
-        case SWF_TAG_CODE_DEFINE_SPRITE:
-          var depths = {};
-          var frame = {
-              type: 'frame'
+        case SWF_TAG_CODE_DEFINE_SCALING_GRID:
+          var symbolUpdate = {
+              isSymbol: true,
+              id: tag.symbolId,
+              updates: {
+                scale9Grid: tag.splitter
+              }
             };
-          var frames = [];
-          var tags = swfTag.tags;
-          var frameScripts = null;
-          var frameIndex = 0;
-          var soundStream = null;
-          for (var i = 0, n = tags.length; i < n; i++) {
-            var tag = tags[i];
-            switch (tag.code) {
-            case SWF_TAG_CODE_DO_ACTION:
-              if (!frameScripts)
-                frameScripts = [];
-              frameScripts.push(frameIndex);
-              frameScripts.push(tag.actionsData);
-              break;
-            case SWF_TAG_CODE_START_SOUND:
-              var startSounds = frame.startSounds || (frame.startSounds = []);
-              startSounds.push(tag);
-              break;
-            case SWF_TAG_CODE_SOUND_STREAM_HEAD:
-              try {
-                soundStream = createSoundStream(tag);
-                frame.soundStream = soundStream.info;
-              } catch (e) {
-              }
-              break;
-            case SWF_TAG_CODE_SOUND_STREAM_BLOCK:
-              if (soundStream) {
-                frame.soundStreamBlock = soundStream.decode(tag.data);
+          commitData(symbolUpdate);
+          break;
+        case SWF_TAG_CODE_DO_ABC:
+        case SWF_TAG_CODE_DO_ABC_:
+          var abcBlocks = frame.abcBlocks;
+          if (abcBlocks)
+            abcBlocks.push({
+              data: tag.data,
+              flags: tag.flags
+            });
+          else
+            frame.abcBlocks = [
+              {
+                data: tag.data,
+                flags: tag.flags
               }
-              break;
-            case SWF_TAG_CODE_FRAME_LABEL:
-              frame.labelName = tag.name;
-              break;
-            case SWF_TAG_CODE_PLACE_OBJECT:
-            case SWF_TAG_CODE_PLACE_OBJECT2:
-            case SWF_TAG_CODE_PLACE_OBJECT3:
-              depths[tag.depth] = tag;
-              break;
-            case SWF_TAG_CODE_REMOVE_OBJECT:
-            case SWF_TAG_CODE_REMOVE_OBJECT2:
-              depths[tag.depth] = null;
-              break;
-            case SWF_TAG_CODE_SHOW_FRAME:
-              var repeat = 1;
-              while (i < n - 1) {
-                var nextTag = tags[i + 1];
-                if (nextTag.code !== SWF_TAG_CODE_SHOW_FRAME)
-                  break;
-                i++;
-                repeat++;
-              }
-              frameIndex += repeat;
-              frame.repeat = repeat;
-              frame.depths = depths;
-              frames.push(frame);
-              depths = {};
-              frame = {
-                type: 'frame'
-              };
-              break;
-            }
+            ];
+          break;
+        case SWF_TAG_CODE_DO_ACTION:
+          var actionBlocks = frame.actionBlocks;
+          if (actionBlocks)
+            actionBlocks.push(tag.actionsData);
+          else
+            frame.actionBlocks = [
+              tag.actionsData
+            ];
+          break;
+        case SWF_TAG_CODE_DO_INIT_ACTION:
+          var initActionBlocks = frame.initActionBlocks || (frame.initActionBlocks = []);
+          initActionBlocks.push({
+            spriteId: tag.spriteId,
+            actionsData: tag.actionsData
+          });
+          break;
+        case SWF_TAG_CODE_START_SOUND:
+          var startSounds = frame.startSounds;
+          if (!startSounds)
+            frame.startSounds = startSounds = [];
+          startSounds.push(tag);
+          break;
+        case SWF_TAG_CODE_SOUND_STREAM_HEAD:
+          try {
+            soundStream = createSoundStream(tag);
+            frame.soundStream = soundStream.info;
+          } catch (e) {
+          }
+          break;
+        case SWF_TAG_CODE_SOUND_STREAM_BLOCK:
+          if (soundStream) {
+            frame.soundStreamBlock = soundStream.decode(tag.data);
           }
-          symbol = {
-            type: 'sprite',
-            id: swfTag.id,
-            frameCount: swfTag.frameCount,
-            frames: frames,
-            frameScripts: frameScripts
-          };
+          break;
+        case SWF_TAG_CODE_EXPORT_ASSETS:
+          var exports = frame.exports;
+          if (exports)
+            frame.exports = exports.concat(tag.exports);
+          else
+            frame.exports = tag.exports.slice(0);
           break;
-        case SWF_TAG_CODE_DEFINE_TEXT:
-        case SWF_TAG_CODE_DEFINE_TEXT2:
-          symbol = defineLabel(swfTag, symbols);
+        case SWF_TAG_CODE_SYMBOL_CLASS:
+          var symbolClasses = frame.symbolClasses;
+          if (symbolClasses)
+            frame.symbolClasses = symbolClasses.concat(tag.exports);
+          else
+            frame.symbolClasses = tag.exports.slice(0);
+          break;
+        case SWF_TAG_CODE_FRAME_LABEL:
+          frame.labelName = tag.name;
           break;
-        }
-        if (!symbol) {
-          commitData({
-            command: 'error',
-            message: 'unknown symbol type: ' + swfTag.code
-          });
-          return;
-        }
-        symbol.isSymbol = true;
-        symbols[swfTag.id] = symbol;
-        commitData(symbol);
-      }
-      function createParsingContext() {
-        var depths = {};
-        var frame = {
+        case SWF_TAG_CODE_PLACE_OBJECT:
+        case SWF_TAG_CODE_PLACE_OBJECT2:
+        case SWF_TAG_CODE_PLACE_OBJECT3:
+          depths[tag.depth] = tag;
+          break;
+        case SWF_TAG_CODE_REMOVE_OBJECT:
+        case SWF_TAG_CODE_REMOVE_OBJECT2:
+          depths[tag.depth] = null;
+          break;
+        case SWF_TAG_CODE_SET_BACKGROUND_COLOR:
+          frame.bgcolor = tag.color;
+          break;
+        case SWF_TAG_CODE_SHOW_FRAME:
+          frame.repeat = tag.repeat;
+          frame.depths = depths;
+          frame.complete = !(!tag.finalTag);
+          commitData(frame);
+          depths = {};
+          frame = {
             type: 'frame'
           };
-        var tagsProcessed = 0;
-        var soundStream = null;
-        var lastProgressSent = 0;
-        return {
-          onstart: function (result) {
-            commitData({
-              command: 'init',
-              result: result
-            });
-          },
-          onprogress: function (result) {
-            if (Date.now() - lastProgressSent > 1000 / 24 || result.bytesLoaded === result.bytesTotal) {
-              commitData({
-                command: 'progress',
-                result: {
-                  bytesLoaded: result.bytesLoaded,
-                  bytesTotal: result.bytesTotal
-                }
-              });
-              lastProgressSent = Date.now();
-            }
-            var tags = result.tags;
-            for (var n = tags.length; tagsProcessed < n; tagsProcessed++) {
-              var tag = tags[tagsProcessed];
-              if ('id' in tag) {
-                defineSymbol(tag);
-                continue;
-              }
-              switch (tag.code) {
-              case SWF_TAG_CODE_DEFINE_SCENE_AND_FRAME_LABEL_DATA:
-                frame.sceneData = tag;
-                break;
-              case SWF_TAG_CODE_DEFINE_SCALING_GRID:
-                var symbolUpdate = {
-                    isSymbol: true,
-                    id: tag.symbolId,
-                    updates: {
-                      scale9Grid: tag.splitter
-                    }
-                  };
-                commitData(symbolUpdate);
-                break;
-              case SWF_TAG_CODE_DO_ABC:
-              case SWF_TAG_CODE_DO_ABC_:
-                var abcBlocks = frame.abcBlocks;
-                if (abcBlocks)
-                  abcBlocks.push({
-                    data: tag.data,
-                    flags: tag.flags
-                  });
-                else
-                  frame.abcBlocks = [
-                    {
-                      data: tag.data,
-                      flags: tag.flags
-                    }
-                  ];
-                break;
-              case SWF_TAG_CODE_DO_ACTION:
-                var actionBlocks = frame.actionBlocks;
-                if (actionBlocks)
-                  actionBlocks.push(tag.actionsData);
-                else
-                  frame.actionBlocks = [
-                    tag.actionsData
-                  ];
-                break;
-              case SWF_TAG_CODE_DO_INIT_ACTION:
-                var initActionBlocks = frame.initActionBlocks || (frame.initActionBlocks = []);
-                initActionBlocks.push({
-                  spriteId: tag.spriteId,
-                  actionsData: tag.actionsData
-                });
-                break;
-              case SWF_TAG_CODE_START_SOUND:
-                var startSounds = frame.startSounds;
-                if (!startSounds)
-                  frame.startSounds = startSounds = [];
-                startSounds.push(tag);
-                break;
-              case SWF_TAG_CODE_SOUND_STREAM_HEAD:
-                try {
-                  soundStream = createSoundStream(tag);
-                  frame.soundStream = soundStream.info;
-                } catch (e) {
-                }
-                break;
-              case SWF_TAG_CODE_SOUND_STREAM_BLOCK:
-                if (soundStream) {
-                  frame.soundStreamBlock = soundStream.decode(tag.data);
-                }
-                break;
-              case SWF_TAG_CODE_SYMBOL_CLASS:
-                var exports = frame.exports;
-                if (exports)
-                  frame.exports = exports.concat(tag.exports);
-                else
-                  frame.exports = tag.exports.slice(0);
-                break;
-              case SWF_TAG_CODE_FRAME_LABEL:
-                frame.labelName = tag.name;
-                break;
-              case SWF_TAG_CODE_PLACE_OBJECT:
-              case SWF_TAG_CODE_PLACE_OBJECT2:
-              case SWF_TAG_CODE_PLACE_OBJECT3:
-                depths[tag.depth] = tag;
-                break;
-              case SWF_TAG_CODE_REMOVE_OBJECT:
-              case SWF_TAG_CODE_REMOVE_OBJECT2:
-                depths[tag.depth] = null;
-                break;
-              case SWF_TAG_CODE_SET_BACKGROUND_COLOR:
-                frame.bgcolor = tag.color;
-                break;
-              case SWF_TAG_CODE_SHOW_FRAME:
-                var repeat = 1;
-                while (tagsProcessed < n) {
-                  var nextTag = tags[tagsProcessed + 1];
-                  if (!nextTag || nextTag.code !== SWF_TAG_CODE_SHOW_FRAME)
-                    break;
-                  tagsProcessed++;
-                  repeat++;
-                }
-                frame.repeat = repeat;
-                frame.depths = depths;
-                commitData(frame);
-                depths = {};
-                frame = {
-                  type: 'frame'
-                };
-                break;
-              }
-            }
-          },
-          oncomplete: function (result) {
-            commitData(result);
-            var stats;
-            if (typeof result.swfVersion === 'number') {
-              var bbox = result.bbox;
-              stats = {
-                topic: 'parseInfo',
-                parseTime: result.parseTime,
-                bytesTotal: result.bytesTotal,
-                swfVersion: result.swfVersion,
-                frameRate: result.frameRate,
-                width: (bbox.xMax - bbox.xMin) / 20,
-                height: (bbox.yMax - bbox.yMin) / 20,
-                isAvm2: !(!result.fileAttributes.doAbc)
-              };
-            }
-            commitData({
-              command: 'complete',
-              stats: stats
-            });
-          }
+          break;
+        }
+      }
+    },
+    oncomplete: function (result) {
+      commitData(result);
+      var stats;
+      if (typeof result.swfVersion === 'number') {
+        var bbox = result.bbox;
+        stats = {
+          topic: 'parseInfo',
+          parseTime: result.parseTime,
+          bytesTotal: result.bytesTotal,
+          swfVersion: result.swfVersion,
+          frameRate: result.frameRate,
+          width: (bbox.xMax - bbox.xMin) / 20,
+          height: (bbox.yMax - bbox.yMin) / 20,
+          isAvm2: !(!result.fileAttributes.doAbc)
         };
       }
-      function parseBytes(bytes) {
-        SWF.parse(bytes, createParsingContext());
+      commitData({
+        command: 'complete',
+        stats: stats
+      });
+    }
+  };
+}
+function parseBytes(bytes, commitData) {
+  SWF.parse(bytes, createParsingContext(commitData));
+}
+function ResourceLoader(scope) {
+  this.subscription = null;
+  var self = this;
+  if (!isWorker) {
+    this.messenger = {
+      postMessage: function (data) {
+        self.onmessage({
+          data: data
+        });
       }
-      if (isWorker || !flash.net.URLRequest.class.isInstanceOf(request)) {
-        var input = request;
-        if (input instanceof ArrayBuffer) {
-          parseBytes(input);
-        } else if ('subscribe' in input) {
-          var pipe = SWF.parseAsync(createParsingContext());
-          input.subscribe(function (data, progress) {
-            if (data) {
-              pipe.push(data, progress);
-            } else {
-              pipe.close();
-            }
-          });
-        } else if (typeof FileReaderSync !== 'undefined') {
-          var reader = new FileReaderSync();
-          var buffer = reader.readAsArrayBuffer(input);
-          parseBytes(buffer);
-        } else {
-          var reader = new FileReader();
-          reader.onload = function () {
-            parseBytes(this.result);
-          };
-          reader.readAsArrayBuffer(input);
-        }
-      } else {
-        var session = FileLoadingService.createSession();
-        var pipe = SWF.parseAsync(createParsingContext());
-        session.onprogress = function (data, progressState) {
-          pipe.push(data, progressState);
-          var data = {
-              command: 'progress',
-              result: {
-                bytesLoaded: progressState.bytesLoaded,
-                bytesTotal: progressState.bytesTotal
-              }
-            };
-          loader._commitData(data);
-        };
-        session.onerror = function (error) {
-          loader._commitData({
-            command: 'error',
-            error: error
-          });
-        };
-        session.onopen = function () {
-        };
-        session.onclose = function () {
-          pipe.close();
-        };
-        session.open(request._toFileRequest());
-      }
-    }
-    if (isWorker) {
-      if (workerScripts) {
-        importScripts.apply(null, workerScripts);
-      }
-      var subscription = null;
-      self.onmessage = function (evt) {
-        if (subscription) {
-          subscription.callback(evt.data.data, evt.data.progress);
-        } else if (evt.data === 'pipe:') {
-          subscription = {
-            subscribe: function (callback) {
-              this.callback = callback;
-            }
-          };
-          loadFromWorker(null, subscription);
-        } else {
-          loadFromWorker(null, evt.data);
+    };
+  } else {
+    this.messenger = scope;
+    scope.onmessage = function (event) {
+      self.listener(event.data);
+    };
+  }
+}
+ResourceLoader.prototype = {
+  terminate: function () {
+    this.messenger = null;
+    this.listener = null;
+  },
+  onmessage: function (event) {
+    this.listener(event.data);
+  },
+  postMessage: function (data) {
+    this.listener && this.listener(data);
+  },
+  listener: function (data) {
+    if (this.subscription) {
+      this.subscription.callback(data.data, data.progress);
+    } else if (data === 'pipe:') {
+      this.subscription = {
+        subscribe: function (callback) {
+          this.callback = callback;
         }
       };
-      return;
-    }
-    var head = document.head;
-    head.insertBefore(document.createElement('style'), head.firstChild);
-    var style = document.styleSheets[0];
-    var def = {
-        __class__: 'flash.display.Loader',
-        initialize: function () {
-          this._contentLoaderInfo = new flash.display.LoaderInfo();
-          this._contentLoaderInfo._loader = this;
-          this._dictionary = {};
-          this._displayList = null;
-          this._timeline = [];
-          this._lastPromise = null;
-          this._uncaughtErrorEvents = null;
-          this._worker = null;
-        },
-        _commitData: function (data) {
-          switch (data.command) {
-          case 'init':
-            this._init(data.result);
-            break;
-          case 'progress':
-            this._updateProgress(data.result);
-            break;
-          case 'complete':
-            var frameConstructed = new Promise();
-            avm2.systemDomain.onMessage.register('frameConstructed', function waitForFrame(type) {
-              if (type === 'frameConstructed') {
-                frameConstructed.resolve();
-                avm2.systemDomain.onMessage.unregister('frameConstructed', waitForFrame);
-              }
-            });
-            Promise.when(frameConstructed, this._lastPromise).then(function () {
-              this.contentLoaderInfo._dispatchEvent('complete');
-            }.bind(this));
-            var stats = data.stats;
-            if (stats) {
-              TelemetryService.reportTelemetry(stats);
-            }
-            this._worker && this._worker.terminate();
-            break;
-          case 'empty':
-            this._lastPromise = new Promise();
-            this._lastPromise.resolve();
-            break;
-          case 'error':
-            this.contentLoaderInfo._dispatchEvent('ioError', flash.events.IOErrorEvent);
-            break;
-          default:
-            if (data.id === 0)
-              break;
-            if (data.isSymbol)
-              this._commitSymbol(data);
-            else if (data.type === 'frame')
-              this._commitFrame(data);
-            else if (data.type === 'image')
-              this._commitImage(data);
-            break;
-          }
-        },
-        _updateProgress: function (state) {
-          var loaderInfo = this.contentLoaderInfo;
-          loaderInfo._bytesLoaded = state.bytesLoaded || 0;
-          loaderInfo._bytesTotal = state.bytesTotal || 0;
-          var event = new flash.events.ProgressEvent('progress', false, false, loaderInfo._bytesLoaded, loaderInfo._bytesTotal);
-          loaderInfo._dispatchEvent(event);
-        },
-        _buildFrame: function (currentDisplayList, timeline, promiseQueue, frame, frameNum) {
-          var loader = this;
-          var dictionary = loader._dictionary;
-          var displayList = {};
-          var depths = [];
-          var cmds = frame.depths;
-          if (currentDisplayList) {
-            var currentDepths = currentDisplayList.depths;
-            for (var i = 0; i < currentDepths.length; i++) {
-              var depth = currentDepths[i];
-              if (cmds[depth] === null) {
-                continue;
-              }
-              displayList[depth] = currentDisplayList[depth];
-              depths.push(depth);
-            }
-          }
-          for (var depth in cmds) {
-            var cmd = cmds[depth];
-            if (!cmd) {
-              continue;
-            }
-            if (cmd.move) {
-              var oldCmd = cmd;
-              cmd = cloneObject(currentDisplayList[depth]);
-              for (var prop in oldCmd) {
-                var val = oldCmd[prop];
-                if (val) {
-                  cmd[prop] = val;
-                }
-              }
-            }
-            if (cmd.symbolId) {
-              var itemPromise = dictionary[cmd.symbolId];
-              if (itemPromise && !itemPromise.resolved) {
-                promiseQueue.push(itemPromise);
-              }
-              cmd = cloneObject(cmd);
-              cmd.promise = itemPromise;
-            }
-            if (!displayList[depth]) {
-              depths.push(depth);
-            }
-            displayList[depth] = cmd;
-          }
-          depths.sort(sortNumeric);
-          displayList.depths = depths;
-          var i = frame.repeat;
-          while (i--) {
-            timeline.push(displayList);
-          }
-          return displayList;
-        },
-        _commitFrame: function (frame) {
-          var abcBlocks = frame.abcBlocks;
-          var actionBlocks = frame.actionBlocks;
-          var initActionBlocks = frame.initActionBlocks;
-          var exports = frame.exports;
-          var sceneData = frame.sceneData;
-          var loader = this;
-          var dictionary = loader._dictionary;
-          var loaderInfo = loader.contentLoaderInfo;
-          var timeline = loader._timeline;
-          var frameNum = timeline.length + 1;
-          var framePromise = new Promise();
-          var labelName = frame.labelName;
-          var prevPromise = this._lastPromise;
-          this._lastPromise = framePromise;
-          var promiseQueue = [
-              prevPromise
-            ];
-          this._displayList = this._buildFrame(this._displayList, timeline, promiseQueue, frame, frameNum);
-          if (frame.bgcolor)
-            loaderInfo._backgroundColor = frame.bgcolor;
-          else if (isNullOrUndefined(loaderInfo._backgroundColor))
-            loaderInfo._backgroundColor = {
-              red: 255,
-              green: 255,
-              blue: 255,
-              alpha: 255
-            };
-          Promise.when.apply(Promise, promiseQueue).then(function () {
-            if (abcBlocks && loader._isAvm2Enabled) {
-              var appDomain = avm2.applicationDomain;
-              for (var i = 0, n = abcBlocks.length; i < n; i++) {
-                var abc = new AbcFile(abcBlocks[i].data, 'abc_block_' + i);
-                if (abcBlocks[i].flags) {
-                  appDomain.loadAbc(abc);
-                } else {
-                  appDomain.executeAbc(abc);
-                }
-              }
-            }
-            if (exports && loader._isAvm2Enabled) {
-              var exportPromises = [];
-              for (var i = 0, n = exports.length; i < n; i++) {
-                var asset = exports[i];
-                var symbolPromise = dictionary[asset.symbolId];
-                if (!symbolPromise)
-                  continue;
-                symbolPromise.then(function (symbolPromise, className) {
-                  return function symbolPromiseResolved() {
-                    var symbolInfo = symbolPromise.value;
-                    symbolInfo.className = className;
-                    avm2.applicationDomain.getClass(className).setSymbol(symbolInfo.props);
-                  };
-                }(symbolPromise, asset.className));
-                exportPromises.push(symbolPromise);
-              }
-              return Promise.when.apply(Promise, exportPromises);
-            }
-          }).then(function () {
-            var root = loader._content;
-            var labelMap;
-            if (!root) {
-              var parent = loader._parent;
-              true;
-              var rootInfo = dictionary[0].value;
-              var rootClass = avm2.applicationDomain.getClass(rootInfo.className);
-              root = rootClass.createAsSymbol({
-                framesLoaded: timeline.length,
-                loader: loader,
-                parent: parent || loader,
-                index: parent ? 0 : -1,
-                level: parent ? 0 : -1,
-                timeline: timeline,
-                totalFrames: rootInfo.props.totalFrames,
-                stage: loader._stage
-              });
-              var isRootMovie = parent && parent == loader._stage && loader._stage._children.length === 0;
-              if (isRootMovie) {
-                parent._frameRate = loaderInfo._frameRate;
-                parent._stageHeight = loaderInfo._height;
-                parent._stageWidth = loaderInfo._width;
-                parent._root = root;
-                parent._setup();
-              } else {
-                loader._children.push(root);
-              }
-              var labels;
-              labelMap = root.symbol.labelMap = createEmptyObject();
-              if (sceneData) {
-                var scenes = [];
-                var startFrame;
-                var endFrame = root.symbol.totalFrames - 1;
-                var sd = sceneData.scenes;
-                var ld = sceneData.labels;
-                var i = sd.length;
-                while (i--) {
-                  var s = sd[i];
-                  startFrame = s.offset;
-                  labels = [];
-                  var j = ld.length;
-                  while (j--) {
-                    var lbl = ld[j];
-                    if (lbl.frame >= startFrame && lbl.frame <= endFrame) {
-                      labelMap[lbl.name] = lbl.frame + 1;
-                      labels.unshift(new flash.display.FrameLabel(lbl.name, lbl.frame - startFrame + 1));
-                    }
-                  }
-                  var scene = new flash.display.Scene(s.name, labels, endFrame - startFrame + 1);
-                  scene._startFrame = startFrame + 1;
-                  scene._endFrame = endFrame + 1;
-                  scenes.unshift(scene);
-                  endFrame = startFrame - 1;
-                }
-                root.symbol.scenes = scenes;
-              } else {
-                labels = [];
-                if (labelName) {
-                  labelMap[labelName] = frameNum;
-                  labels.push(new flash.display.FrameLabel(labelName, frameNum));
-                }
-                var scene = new flash.display.Scene('Scene 1', labels, root.symbol.totalFrames);
-                scene._endFrame = root.symbol.totalFrames;
-                root.symbol.scenes = [
-                  scene
-                ];
-              }
-              if (!loader._isAvm2Enabled) {
-                var avm1Context = loader._avm1Context;
-                var _root = root;
-                if (parent && parent !== loader._stage) {
-                  var parentLoader = parent._loader;
-                  while (parentLoader._parent && parentLoader._parent !== loader._stage) {
-                    parentLoader = parentLoader._parent._loader;
-                  }
-                  _root = parentLoader._content;
-                }
-                var as2Object = _root._getAS2Object();
-                avm1Context.globals.asSetPublicProperty('_root', as2Object);
-                avm1Context.globals.asSetPublicProperty('_level0', as2Object);
-                avm1Context.globals.asSetPublicProperty('_level1', as2Object);
-                var parameters = loader.loaderInfo._parameters;
-                for (var paramName in parameters) {
-                  if (!(paramName in as2Object)) {
-                    as2Object[paramName] = parameters[paramName];
-                  }
-                }
-              }
-              rootClass.instanceConstructor.call(root);
-              loader._content = root;
-            } else {
-              root._framesLoaded += frame.repeat;
-              if (labelName && root._labelMap) {
-                if (root._labelMap[labelName] === undefined) {
-                  root._labelMap[labelName] = frameNum;
-                  for (var i = 0, n = root.symbol.scenes.length; i < n; i++) {
-                    var scene = root.symbol.scenes[i];
-                    if (frameNum >= scene._startFrame && frameNum <= scene._endFrame) {
-                      scene.labels.push(new flash.display.FrameLabel(labelName, frameNum - scene._startFrame));
-                      break;
-                    }
-                  }
-                }
-              }
-            }
-            if (frame.startSounds) {
-              root._registerStartSounds(frameNum, frame.startSounds);
-            }
-            if (frame.soundStream) {
-              root._initSoundStream(frame.soundStream);
-            }
-            if (frame.soundStreamBlock) {
-              root._addSoundStreamBlock(frameNum, frame.soundStreamBlock);
-            }
-            if (!loader._isAvm2Enabled) {
-              var avm1Context = loader._avm1Context;
-              if (initActionBlocks) {
-                for (var i = 0; i < initActionBlocks.length; i++) {
-                  var spriteId = initActionBlocks[i].spriteId;
-                  var actionsData = initActionBlocks[i].actionsData;
-                  root.addFrameScript(frameNum - 1, function (actionsData, spriteId, state) {
-                    if (state.executed)
-                      return;
-                    state.executed = true;
-                    return executeActions(actionsData, avm1Context, this._getAS2Object(), exports);
-                  }.bind(root, actionsData, spriteId, {
-                    executed: false
-                  }));
-                }
-              }
-              if (actionBlocks) {
-                for (var i = 0; i < actionBlocks.length; i++) {
-                  var block = actionBlocks[i];
-                  root.addFrameScript(frameNum - 1, function (block) {
-                    return function () {
-                      return executeActions(block, avm1Context, this._getAS2Object(), exports);
-                    };
-                  }(block));
-                }
-              }
-            }
-            if (frameNum === 1)
-              loaderInfo._dispatchEvent(new flash.events.Event('init', false, false));
-            framePromise.resolve(frame);
-          });
-        },
-        _commitImage: function (imageInfo) {
-          var loader = this;
-          var imgPromise = this._lastPromise = new Promise();
-          var img = new Image();
-          imageInfo.props.img = img;
-          img.onload = function () {
-            var props = imageInfo.props;
-            props.parent = loader._parent;
-            props.stage = loader._stage;
-            props.skipCopyToCanvas = true;
-            var Bitmap = avm2.systemDomain.getClass('flash.display.Bitmap');
-            var BitmapData = avm2.systemDomain.getClass('flash.display.BitmapData');
-            var bitmapData = BitmapData.createAsSymbol(props);
-            BitmapData.instanceConstructor.call(bitmapData, 0, 0, true, 4294967295);
-            var image = Bitmap.createAsSymbol(bitmapData);
-            loader._children.push(image);
-            Bitmap.instanceConstructor.call(image, bitmapData);
-            image._parent = loader;
-            loader._content = image;
-            imgPromise.resolve(imageInfo);
-            loader.contentLoaderInfo._dispatchEvent('init');
-          };
-          img.src = URL.createObjectURL(imageInfo.data);
-          delete imageInfo.data;
-        },
-        _commitSymbol: function (symbol) {
-          var dictionary = this._dictionary;
-          if ('updates' in symbol) {
-            dictionary[symbol.id].then(function (s) {
-              for (var i in symbol.updates) {
-                s.props[i] = symbol.updates[i];
-              }
-            });
-            return;
-          }
-          var className = 'flash.display.DisplayObject';
-          var dependencies = symbol.require;
-          var promiseQueue = [];
-          var props = {
-              symbolId: symbol.id,
-              loader: this
-            };
-          var symbolPromise = new Promise();
-          if (dependencies && dependencies.length) {
-            for (var i = 0, n = dependencies.length; i < n; i++) {
-              var dependencyId = dependencies[i];
-              var dependencyPromise = dictionary[dependencyId];
-              if (dependencyPromise && !dependencyPromise.resolved)
-                promiseQueue.push(dependencyPromise);
-            }
-          }
-          switch (symbol.type) {
-          case 'button':
-            var states = {};
-            for (var stateName in symbol.states) {
-              var characters = [];
-              var displayList = {};
-              var state = symbol.states[stateName];
-              var depths = Object.keys(state);
-              for (var i = 0; i < depths.length; i++) {
-                var depth = depths[i];
-                var cmd = state[depth];
-                var characterPromise = dictionary[cmd.symbolId];
-                if (characterPromise && !characterPromise.resolved)
-                  promiseQueue.push(characterPromise);
-                characters.push(characterPromise);
-                displayList[depth] = Object.create(cmd, {
-                  promise: {
-                    value: characterPromise
-                  }
-                });
-              }
-              depths.sort(sortNumeric);
-              displayList.depths = depths;
-              var statePromise = new Promise();
-              statePromise.resolve({
-                className: 'flash.display.Sprite',
-                props: {
-                  loader: this,
-                  timeline: [
-                    displayList
-                  ]
-                }
-              });
-              states[stateName] = statePromise;
-            }
-            className = 'flash.display.SimpleButton';
-            props.states = states;
-            props.buttonActions = symbol.buttonActions;
-            break;
-          case 'font':
-            var charset = fromCharCode.apply(null, symbol.codes);
-            if (charset) {
-              style.insertRule('@font-face{font-family:"' + symbol.uniqueName + '";' + 'src:url(data:font/opentype;base64,' + btoa(symbol.data) + ')' + '}', style.cssRules.length);
-              if (!/Mozilla\/5.0.*?rv:(\d+).*? Gecko/.test(window.navigator.userAgent)) {
-                var testDiv = document.createElement('div');
-                testDiv.setAttribute('style', 'position: absolute; top: 0; right: 0;visibility: hidden; z-index: -500;font-family:"' + symbol.uniqueName + '";');
-                testDiv.textContent = 'font test';
-                document.body.appendChild(testDiv);
-                var fontPromise = new Promise();
-                setTimeout(function () {
-                  fontPromise.resolve();
-                  document.body.removeChild(testDiv);
-                }, 200);
-                promiseQueue.push(fontPromise);
-              }
-            }
-            className = 'flash.text.Font';
-            props.name = symbol.name;
-            props.uniqueName = symbol.uniqueName;
-            props.charset = symbol.charset;
-            props.bold = symbol.bold;
-            props.italic = symbol.italic;
-            props.metrics = symbol.metrics;
-            this._registerFont(className, props);
-            break;
-          case 'image':
-            var img = new Image();
-            var imgPromise = new Promise();
-            img.onload = function () {
-              if (symbol.mask) {
-                var maskCanvas = document.createElement('canvas');
-                maskCanvas.width = symbol.width;
-                maskCanvas.height = symbol.height;
-                var maskContext = maskCanvas.getContext('2d');
-                maskContext.drawImage(img, 0, 0);
-                var maskImageData = maskContext.getImageData(0, 0, symbol.width, symbol.height);
-                var maskImageDataBytes = maskImageData.data;
-                var symbolMaskBytes = symbol.mask;
-                var length = maskImageData.width * maskImageData.height;
-                for (var i = 0, j = 3; i < length; i++, j += 4) {
-                  maskImageDataBytes[j] = symbolMaskBytes[i];
-                }
-                maskContext.putImageData(maskImageData, 0, 0);
-                props.img = maskCanvas;
-              }
-              imgPromise.resolve();
-            };
-            img.src = URL.createObjectURL(symbol.data);
-            promiseQueue.push(imgPromise);
-            className = 'flash.display.Bitmap';
-            props.img = img;
-            props.width = symbol.width;
-            props.height = symbol.height;
-            break;
-          case 'label':
-            var drawFn = new Function('c,r,ct', symbol.data);
-            className = 'flash.text.StaticText';
-            props.bbox = symbol.bbox;
-            props.draw = drawFn;
-            break;
-          case 'text':
-            props.bbox = symbol.bbox;
-            props.html = symbol.html;
-            if (symbol.type === 'label') {
-              className = 'flash.text.StaticText';
-            } else {
-              className = 'flash.text.TextField';
-              props.tag = symbol.tag;
-              props.variableName = symbol.variableName;
-            }
-            break;
-          case 'shape':
-            className = symbol.morph ? 'flash.display.MorphShape' : 'flash.display.Shape';
-            props.bbox = symbol.bbox;
-            props.strokeBbox = symbol.strokeBbox;
-            props.paths = symbol.paths;
-            props.dictionary = dictionary;
-            break;
-          case 'sound':
-            if (!symbol.pcm && !PLAY_USING_AUDIO_TAG) {
-              var decodePromise = new Promise();
-              MP3DecoderSession.processAll(symbol.packaged.data, function (props, pcm, id3tags, error) {
-                props.pcm = pcm || new Uint8Array(0);
-                decodePromise.resolve();
-                if (error) {
-                  console.error('ERROR: ' + error);
-                }
-              }.bind(null, props));
-              promiseQueue.push(decodePromise);
-            }
-            className = 'flash.media.Sound';
-            props.sampleRate = symbol.sampleRate;
-            props.channels = symbol.channels;
-            props.pcm = symbol.pcm;
-            props.packaged = symbol.packaged;
-            break;
-          case 'binary':
-            props.data = symbol.data;
-            break;
-          case 'sprite':
-            var displayList = null;
-            var frameCount = symbol.frameCount;
-            var labelMap = {};
-            var frameNum = 1;
-            var frames = symbol.frames;
-            var timeline = [];
-            var startSoundRegistrations = [];
-            for (var i = 0, n = frames.length; i < n; i++) {
-              var frame = frames[i];
-              var frameNum = timeline.length + 1;
-              if (frame.labelName) {
-                labelMap[frame.labelName] = frameNum;
-              }
-              if (frame.startSounds) {
-                startSoundRegistrations[frameNum] = frame.startSounds;
-                for (var j = 0; j < frame.startSounds.length; j++) {
-                  var itemPromise = dictionary[frame.startSounds[j].soundId];
-                  if (itemPromise && !itemPromise.resolved)
-                    promiseQueue.push(itemPromise);
-                }
-              }
-              displayList = this._buildFrame(displayList, timeline, promiseQueue, frame, frameNum);
-            }
-            var frameScripts = {};
-            if (!this._isAvm2Enabled) {
-              if (symbol.frameScripts) {
-                var data = symbol.frameScripts;
-                for (var i = 0; i < data.length; i += 2) {
-                  var frameNum = data[i] + 1;
-                  var block = data[i + 1];
-                  var script = function (block, loader) {
-                      return function () {
-                        var avm1Context = loader._avm1Context;
-                        return executeActions(block, avm1Context, this._getAS2Object());
-                      };
-                    }(block, this);
-                  if (!frameScripts[frameNum])
-                    frameScripts[frameNum] = [
-                      script
-                    ];
-                  else
-                    frameScripts[frameNum].push(script);
-                }
-              }
-            }
-            className = 'flash.display.MovieClip';
-            props.timeline = timeline;
-            props.framesLoaded = frameCount;
-            props.labelMap = labelMap;
-            props.frameScripts = frameScripts;
-            props.totalFrames = frameCount;
-            props.startSoundRegistrations = startSoundRegistrations;
-            break;
-          }
-          dictionary[symbol.id] = symbolPromise;
-          Promise.when.apply(Promise, promiseQueue).then(function () {
-            symbolPromise.resolve({
-              className: className,
-              props: props
-            });
-          });
-        },
-        _registerFont: function (className, props) {
-          this._vmPromise.then(function () {
-            var fontClass = avm2.applicationDomain.getClass(className);
-            var font = fontClass.createAsSymbol(props);
-            fontClass.instanceConstructor.call(font);
-          });
-        },
-        _init: function (info) {
-          var loader = this;
-          var loaderInfo = loader.contentLoaderInfo;
-          loaderInfo._swfVersion = info.swfVersion;
-          var bbox = info.bbox;
-          loaderInfo._width = bbox.xMax - bbox.xMin;
-          loaderInfo._height = bbox.yMax - bbox.yMin;
-          loaderInfo._frameRate = info.frameRate;
-          var documentPromise = new Promise();
-          var vmPromise = new Promise();
-          vmPromise.then(function () {
-            documentPromise.resolve({
-              className: 'flash.display.MovieClip',
-              props: {
-                totalFrames: info.frameCount
-              }
-            });
-          });
-          loader._dictionary[0] = documentPromise;
-          loader._lastPromise = documentPromise;
-          loader._vmPromise = vmPromise;
-          loader._isAvm2Enabled = info.fileAttributes.doAbc;
-          this._setup();
-        },
-        _load: function (request, checkPolicyFile, applicationDomain, securityDomain, deblockingFilter) {
-          if (!isWorker && flash.net.URLRequest.class.isInstanceOf(request)) {
-            this._contentLoaderInfo._url = request._url;
-          }
-          if (!isWorker && WORKERS_ENABLED) {
-            var loader = this;
-            var worker = loader._worker = new Worker(SHUMWAY_ROOT + LOADER_PATH);
-            worker.onmessage = function (evt) {
-              loader._commitData(evt.data);
-            };
-            if (flash.net.URLRequest.class.isInstanceOf(request)) {
-              var session = FileLoadingService.createSession();
-              session.onprogress = function (data, progress) {
-                worker.postMessage({
-                  data: data,
-                  progress: progress
-                });
-              };
-              session.onerror = function (error) {
-                loader._commitData({
-                  command: 'error',
-                  error: error
-                });
-              };
-              session.onopen = function () {
-                worker.postMessage('pipe:');
-              };
-              session.onclose = function () {
-                worker.postMessage({
-                  data: null
-                });
-              };
-              session.open(request._toFileRequest());
-            } else {
-              worker.postMessage(request);
-            }
-          } else {
-            loadFromWorker(this, request);
-          }
-        },
-        _setup: function () {
-          var loader = this;
-          var stage = loader._stage;
-          if (loader._isAvm2Enabled) {
-            var mouseClass = avm2.systemDomain.getClass('flash.ui.Mouse');
-            mouseClass._stage = stage;
-            loader._vmPromise.resolve();
-            return;
-          }
-          if (!avm2.loadAVM1) {
-            loader._vmPromise.reject('AVM1 loader is not found');
-            return;
-          }
-          var loaded = function () {
-            var loaderInfo = loader.contentLoaderInfo;
-            var avm1Context = new AS2Context(loaderInfo._swfVersion);
-            avm1Context.stage = stage;
-            loader._avm1Context = avm1Context;
-            avm1lib.AS2Key.class.$bind(stage);
-            avm1lib.AS2Mouse.class.$bind(stage);
-            stage._addEventListener('frameConstructed', avm1Context.flushPendingScripts.bind(avm1Context), false, Number.MAX_VALUE);
-            loader._vmPromise.resolve();
-          };
-          if (avm2.isAVM1Loaded) {
-            loaded();
-          } else {
-            avm2.isAVM1Loaded = true;
-            avm2.loadAVM1(loaded);
-          }
-        },
-        get contentLoaderInfo() {
-          return this._contentLoaderInfo;
-        },
-        get content() {
-          somewhatImplemented('Loader.content');
-          return this._content;
+      this.parseLoadedData(this.messenger, this.subscription);
+    } else {
+      this.parseLoadedData(this.messenger, data);
+    }
+  },
+  parseLoadedData: function (loader, request, context) {
+    function commitData(data, transferables) {
+      try {
+        loader.postMessage(data, transferables);
+      } catch (ex) {
+        if (ex != 'DataCloneError') {
+          throw ex;
         }
+        loader.postMessage(data);
+      }
+    }
+    if (request instanceof ArrayBuffer) {
+      parseBytes(request, commitData);
+    } else if ('subscribe' in request) {
+      var pipe = SWF.parseAsync(createParsingContext(commitData));
+      request.subscribe(function (data, progress) {
+        if (data) {
+          pipe.push(data, progress);
+        } else {
+          pipe.close();
+        }
+      });
+    } else if (typeof FileReaderSync !== 'undefined') {
+      var reader = new FileReaderSync();
+      var buffer = reader.readAsArrayBuffer(request);
+      parseBytes(buffer, commitData);
+    } else {
+      var reader = new FileReader();
+      reader.onload = function () {
+        parseBytes(this.result, commitData);
       };
-    def.__glue__ = {
-      native: {
-        instance: {
-          content: Object.getOwnPropertyDescriptor(def, 'content'),
-          contentLoaderInfo: Object.getOwnPropertyDescriptor(def, 'contentLoaderInfo'),
-          _getJPEGLoaderContextdeblockingfilter: function (context) {
-            return 0;
-          },
-          _load: def._load,
-          _loadBytes: function _loadBytes(bytes, checkPolicyFile, applicationDomain, securityDomain, requestedContentParent, parameters, deblockingFilter, allowLoadBytesCodeExecution, imageDecodingPolicy) {
-            def._load(bytes.a);
-          },
-          _unload: function _unload(halt, gc) {
-            somewhatImplemented('Loader._unload, do we even need to do anything here?');
-          },
-          _close: function _close() {
-            somewhatImplemented('Loader._close');
-          },
-          _getUncaughtErrorEvents: function _getUncaughtErrorEvents() {
-            somewhatImplemented('Loader._getUncaughtErrorEvents');
-            return this._uncaughtErrorEvents;
-          },
-          _setUncaughtErrorEvents: function _setUncaughtErrorEvents(value) {
-            somewhatImplemented('Loader._setUncaughtErrorEvents');
-            this._uncaughtErrorEvents = value;
-          }
-        }
-      }
-    };
-    return def;
-  }.call(this);
+      reader.readAsArrayBuffer(request);
+    }
+  }
+};
+if (isWorker) {
+  var loader = new ResourceLoader(this);
+}
 var codeLengthOrder = [
     16,
     17,
     18,
     0,
     8,
     7,
     9,
@@ -5221,16 +4626,29 @@ var tagHandler = function (global) {
       if (tagCode === 82) {
         $.name = readString($bytes, $stream, 0);
       } else {
         $.name = '';
       }
       $.data = readBinary($bytes, $stream, 0);
       return $;
     }
+    function exportAssets($bytes, $stream, $, swfVersion, tagCode) {
+      $ || ($ = {});
+      var exportsCount = readUi16($bytes, $stream);
+      var $0 = $.exports = [];
+      var $1 = exportsCount;
+      while ($1--) {
+        var $2 = {};
+        $2.symbolId = readUi16($bytes, $stream);
+        $2.className = readString($bytes, $stream, 0);
+        $0.push($2);
+      }
+      return $;
+    }
     function symbolClass($bytes, $stream, $, swfVersion, tagCode) {
       $ || ($ = {});
       var symbolCount = readUi16($bytes, $stream);
       var $0 = $.exports = [];
       var $1 = symbolCount;
       while ($1--) {
         var $2 = {};
         $2.symbolId = readUi16($bytes, $stream);
@@ -6036,17 +5454,17 @@ var tagHandler = function (global) {
       35: defineImage,
       36: defineBitmap,
       37: defineText,
       39: undefined,
       43: frameLabel,
       45: soundStreamHead,
       46: defineShape,
       48: defineFont2,
-      56: undefined,
+      56: exportAssets,
       57: undefined,
       58: undefined,
       59: doAction,
       60: undefined,
       61: undefined,
       62: undefined,
       64: undefined,
       65: undefined,
@@ -6090,68 +5508,89 @@ var readHeader = function readHeader($by
   $.frameRate = readUi8($bytes, $stream) + frameRateFraction / 256;
   $.frameCount = readUi16($bytes, $stream);
   return $;
 };
 (function (global) {
   global['tagHandler'] = tagHandler;
   global['readHeader'] = readHeader;
 }(this));
-function readTags(context, stream, swfVersion, onprogress) {
+function readTags(context, stream, swfVersion, final, onprogress) {
   var tags = context.tags;
   var bytes = stream.bytes;
   var lastSuccessfulPosition;
+  var tag = null;
+  if (context._readTag) {
+    tag = context._readTag;
+    delete context._readTag;
+  }
   try {
-    do {
+    while (stream.pos < stream.end) {
       lastSuccessfulPosition = stream.pos;
       stream.ensure(2);
       var tagCodeAndLength = readUi16(bytes, stream);
+      if (!tagCodeAndLength) {
+        final = true;
+        break;
+      }
       var tagCode = tagCodeAndLength >> 6;
       var length = tagCodeAndLength & 63;
       if (length === 63) {
         stream.ensure(4);
         length = readUi32(bytes, stream);
       }
+      if (tag) {
+        if (tagCode === 1 && tag.code === 1) {
+          tag.repeat++;
+          stream.pos += length;
+          continue;
+        }
+        tags.push(tag);
+        if (onprogress && tag.id !== undefined) {
+          onprogress(context);
+        }
+        tag = null;
+      }
       stream.ensure(length);
-      if (tagCode === 0) {
-        break;
-      }
       var substream = stream.substream(stream.pos, stream.pos += length);
       var subbytes = substream.bytes;
-      var tag = {
+      var nextTag = {
           code: tagCode
         };
       if (tagCode === 39) {
-        tag.type = 'sprite';
-        tag.id = readUi16(subbytes, substream);
-        tag.frameCount = readUi16(subbytes, substream);
-        tag.tags = [];
-        readTags(tag, substream, swfVersion);
+        nextTag.type = 'sprite';
+        nextTag.id = readUi16(subbytes, substream);
+        nextTag.frameCount = readUi16(subbytes, substream);
+        nextTag.tags = [];
+        readTags(nextTag, substream, swfVersion, true);
+      } else if (tagCode === 1) {
+        nextTag.repeat = 1;
       } else {
         var handler = tagHandler[tagCode];
         if (handler) {
-          handler(subbytes, substream, tag, swfVersion, tagCode);
+          handler(subbytes, substream, nextTag, swfVersion, tagCode);
         }
       }
+      tag = nextTag;
+    }
+    if (tag && final) {
+      tag.finalTag = true;
       tags.push(tag);
-      if (tagCode === 1) {
-        while (stream.pos + 2 <= stream.end && stream.getUint16(stream.pos, true) >> 6 === 1) {
-          tags.push(tag);
-          stream.pos += 2;
-        }
-        if (onprogress)
-          onprogress(context);
-      } else if (onprogress && tag.id !== undefined) {
+      if (onprogress) {
         onprogress(context);
       }
-    } while (stream.pos < stream.end);
+    } else {
+      context._readTag = tag;
+    }
   } catch (e) {
-    if (e !== StreamNoDataError)
+    if (e !== StreamNoDataError) {
       throw e;
+    }
     stream.pos = lastSuccessfulPosition;
+    context._readTag = tag;
   }
 }
 function HeadTailBuffer(defaultSize) {
   this.bufferSize = defaultSize || 16;
   this.buffer = new Uint8Array(this.bufferSize);
   this.pos = 0;
 }
 HeadTailBuffer.prototype = {
@@ -6290,22 +5729,24 @@ BodyParser.prototype = {
       if (options.onstart)
         options.onstart(swf);
       swf.tags = [];
       this.initialize = false;
     } else {
       buffer.push(data);
       stream = buffer.createStream();
     }
+    var finalBlock = false;
     if (progressInfo) {
       swf.bytesLoaded = progressInfo.bytesLoaded;
       swf.bytesTotal = progressInfo.bytesTotal;
+      finalBlock = progressInfo.bytesLoaded >= progressInfo.bytesTotal;
     }
     var readStartTime = performance.now();
-    readTags(swf, stream, swfVersion, options.onprogress);
+    readTags(swf, stream, swfVersion, finalBlock, options.onprogress);
     swf.parseTime += performance.now() - readStartTime;
     var read = stream.pos;
     buffer.removeHead(read);
     this.totalRead += read;
     if (this.totalRead >= this.length && options.oncomplete) {
       options.oncomplete(swf);
     }
   }
--- a/browser/extensions/shumway/content/shumway.js
+++ b/browser/extensions/shumway/content/shumway.js
@@ -239,16 +239,19 @@
           var argString = args.shift();
           var argument = null, value = argString;
           if (argString == '--') {
             leftoverArguments = leftoverArguments.concat(args);
             break;
           } else if (argString.slice(0, 1) == '-' || argString.slice(0, 2) == '--') {
             argument = nonPositionalArgumentMap[argString];
             true;
+            if (!argument) {
+              continue;
+            }
             if (argument.type !== 'boolean') {
               value = args.shift();
               true;
             } else {
               value = true;
             }
           } else if (positionalArgumentList.length) {
             argument = positionalArgumentList.shift();
@@ -320,16 +323,54 @@ var slice = Array.prototype.slice;
 var splice = Array.prototype.splice;
 function fail(msg, context) {
   throw new Error((context ? context + ': ' : '') + msg);
 }
 function assert(cond, msg, context) {
   if (!cond)
     fail(msg, context);
 }
+function scriptProperties(namespace, props) {
+  return props.reduce(function (o, p) {
+    o[p] = namespace + ' ' + p;
+    return o;
+  }, {});
+}
+function cloneObject(obj) {
+  var clone = Object.create(null);
+  for (var prop in obj)
+    clone[prop] = obj[prop];
+  return clone;
+}
+function sortByDepth(a, b) {
+  var levelA = a._level;
+  var levelB = b._level;
+  if (a._parent !== b._parent && a._index > -1 && b._index > -1) {
+    while (a._level > levelB) {
+      a = a._parent;
+    }
+    while (b._level > levelA) {
+      b = b._parent;
+    }
+    while (a._level > 1) {
+      if (a._parent === b._parent) {
+        break;
+      }
+      a = a._parent;
+      b = b._parent;
+    }
+  }
+  if (a === b) {
+    return levelA - levelB;
+  }
+  return a._index - b._index;
+}
+function sortNumeric(a, b) {
+  return a - b;
+}
 function rgbaObjToStr(color) {
   return 'rgba(' + color.red + ',' + color.green + ',' + color.blue + ',' + color.alpha / 255 + ')';
 }
 function rgbIntAlphaToStr(color, alpha) {
   color |= 0;
   if (alpha >= 1) {
     var colorStr = color.toString(16);
     while (colorStr.length < 6) {
@@ -359,24 +400,311 @@ function argbUintToStr(argb) {
       this.__name = name;
       return name;
     },
     configurable: true,
     enumerable: false
   });
 }());
 var randomStyleCache;
+var nextStyle = 0;
 function randomStyle() {
   if (!randomStyleCache) {
-    randomStyleCache = [];
-    for (var i = 0; i < 50; i++) {
-      randomStyleCache.push('#' + ('00000' + (Math.random() * (1 << 24) | 0).toString(16)).slice(-6));
-    }
-  }
-  return randomStyleCache[Math.random() * randomStyleCache.length | 0];
+    randomStyleCache = [
+      '#ff5e3a',
+      '#ff9500',
+      '#ffdb4c',
+      '#87fc70',
+      '#52edc7',
+      '#1ad6fd',
+      '#c644fc',
+      '#ef4db6',
+      '#4a4a4a',
+      '#dbddde',
+      '#ff3b30',
+      '#ff9500',
+      '#ffcc00',
+      '#4cd964',
+      '#34aadc',
+      '#007aff',
+      '#5856d6',
+      '#ff2d55',
+      '#8e8e93',
+      '#c7c7cc',
+      '#5ad427',
+      '#c86edf',
+      '#d1eefc',
+      '#e0f8d8',
+      '#fb2b69',
+      '#f7f7f7',
+      '#1d77ef',
+      '#d6cec3',
+      '#55efcb',
+      '#ff4981',
+      '#ffd3e0',
+      '#f7f7f7',
+      '#ff1300',
+      '#1f1f21',
+      '#bdbec2',
+      '#ff3a2d'
+    ];
+  }
+  return randomStyleCache[nextStyle++ % randomStyleCache.length];
+}
+var Promise = function PromiseClosure() {
+    function isPromise(obj) {
+      return typeof obj === 'object' && obj !== null && typeof obj.then === 'function';
+    }
+    function defaultOnFulfilled(value) {
+      return value;
+    }
+    function defaultOnRejected(reason) {
+      throw reason;
+    }
+    function propagateFulfilled(subject, value) {
+      subject.subpromisesValue = value;
+      var subpromises = subject.subpromises;
+      if (!subpromises) {
+        return;
+      }
+      for (var i = 0; i < subpromises.length; i++) {
+        subpromises[i].fulfill(value);
+      }
+      delete subject.subpromises;
+    }
+    function propagateRejected(subject, reason) {
+      subject.subpromisesReason = reason;
+      var subpromises = subject.subpromises;
+      if (!subpromises) {
+        if (!true) {
+          console.warn(reason);
+        }
+        return;
+      }
+      for (var i = 0; i < subpromises.length; i++) {
+        subpromises[i].reject(reason);
+      }
+      delete subject.subpromises;
+    }
+    function performCall(callback, arg, subject) {
+      try {
+        var value = callback(arg);
+        if (isPromise(value)) {
+          value.then(function Promise_queueCall_onFulfilled(value) {
+            propagateFulfilled(subject, value);
+          }, function Promise_queueCall_onRejected(reason) {
+            propagateRejected(subject, reason);
+          });
+          return;
+        }
+        propagateFulfilled(subject, value);
+      } catch (ex) {
+        propagateRejected(subject, ex);
+      }
+    }
+    var queue = [];
+    function processQueue() {
+      while (queue.length > 0) {
+        var task = queue[0];
+        if (task.directCallback) {
+          task.callback.call(task.subject, task.arg);
+        } else {
+          performCall(task.callback, task.arg, task.subject);
+        }
+        queue.shift();
+      }
+    }
+    function queueCall(callback, arg, subject, directCallback) {
+      if (queue.length === 0) {
+        setTimeout(processQueue, 0);
+      }
+      queue.push({
+        callback: callback,
+        arg: arg,
+        subject: subject,
+        directCallback: directCallback
+      });
+    }
+    function Promise(onFulfilled, onRejected) {
+      this.state = 'pending';
+      this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : defaultOnFulfilled;
+      this.onRejected = typeof onRejected === 'function' ? onRejected : defaultOnRejected;
+    }
+    Promise.prototype = {
+      fulfill: function Promise_resolve(value) {
+        if (this.state !== 'pending') {
+          return;
+        }
+        this.state = 'fulfilled';
+        this.value = value;
+        queueCall(this.onFulfilled, value, this, false);
+      },
+      reject: function Promise_reject(reason) {
+        if (this.state !== 'pending') {
+          return;
+        }
+        this.state = 'rejected';
+        this.reason = reason;
+        queueCall(this.onRejected, reason, this, false);
+      },
+      then: function Promise_then(onFulfilled, onRejected) {
+        var promise = new Promise(onFulfilled, onRejected);
+        if ('subpromisesValue' in this) {
+          queueCall(promise.fulfill, this.subpromisesValue, promise, true);
+        } else if ('subpromisesReason' in this) {
+          queueCall(promise.reject, this.subpromisesReason, promise, true);
+        } else {
+          var subpromises = this.subpromises || (this.subpromises = []);
+          subpromises.push(promise);
+        }
+        return promise;
+      },
+      get resolved() {
+        return this.state === 'fulfilled';
+      },
+      resolve: function (value) {
+        this.fulfill(value);
+      }
+    };
+    Promise.when = function Promise_when() {
+      var promise = new Promise();
+      if (arguments.length === 0) {
+        promise.resolve();
+        return promise;
+      }
+      var promises = slice.call(arguments, 0);
+      var result = [];
+      var i = 1;
+      function fulfill(value) {
+        result.push(value);
+        if (i < promises.length) {
+          promises[i++].then(fulfill, reject);
+        } else {
+          promise.resolve(result);
+        }
+        return value;
+      }
+      function reject(reason) {
+        promise.reject(reason);
+      }
+      promises[0].then(fulfill, reject);
+      return promise;
+    };
+    return Promise;
+  }();
+var QuadTree = function (x, y, width, height, level) {
+  this.x = x | 0;
+  this.y = y | 0;
+  this.width = width | 0;
+  this.height = height | 0;
+  this.level = level | 0;
+  this.stuckObjects = [];
+  this.objects = [];
+  this.nodes = [];
+};
+QuadTree.prototype._findIndex = function (xMin, yMin, xMax, yMax) {
+  var midX = this.x + (this.width / 2 | 0);
+  var midY = this.y + (this.height / 2 | 0);
+  var top = yMin < midY && yMax < midY;
+  var bottom = yMin > midY;
+  if (xMin < midX && xMax < midX) {
+    if (top) {
+      return 1;
+    } else if (bottom) {
+      return 2;
+    }
+  } else if (xMin > midX) {
+    if (top) {
+      return 0;
+    } else if (bottom) {
+      return 3;
+    }
+  }
+  return -1;
+};
+QuadTree.prototype.insert = function (obj) {
+  var nodes = this.nodes;
+  if (nodes.length) {
+    var index = this._findIndex(obj.xMin, obj.yMin, obj.xMax, obj.yMax);
+    if (index > -1) {
+      nodes[index].insert(obj);
+    } else {
+      this.stuckObjects.push(obj);
+      obj._qtree = this;
+    }
+    return;
+  }
+  var objects = this.objects;
+  objects.push(obj);
+  if (objects.length > 4 && this.level < 10) {
+    this._subdivide();
+    while (objects.length) {
+      this.insert(objects.shift());
+    }
+    return;
+  }
+  obj._qtree = this;
+};
+QuadTree.prototype.delete = function (obj) {
+  if (obj._qtree !== this) {
+    return;
+  }
+  var index = this.objects.indexOf(obj);
+  if (index > -1) {
+    this.objects.splice(index, 1);
+  } else {
+    index = this.stuckObjects.indexOf(obj);
+    this.stuckObjects.splice(index, 1);
+  }
+  obj._qtree = null;
+};
+QuadTree.prototype._stack = [];
+QuadTree.prototype._out = [];
+QuadTree.prototype.retrieve = function (xMin, yMin, xMax, yMax) {
+  var stack = this._stack;
+  var out = this._out;
+  out.length = 0;
+  var node = this;
+  do {
+    if (node.nodes.length) {
+      var index = node._findIndex(xMin, yMin, xMax, yMax);
+      if (index > -1) {
+        stack.push(node.nodes[index]);
+      } else {
+        stack.push.apply(stack, node.nodes);
+      }
+    }
+    out.push.apply(out, node.stuckObjects);
+    out.push.apply(out, node.objects);
+    node = stack.pop();
+  } while (node);
+  return out;
+};
+QuadTree.prototype._subdivide = function () {
+  var halfWidth = this.width / 2 | 0;
+  var halfHeight = this.height / 2 | 0;
+  var midX = this.x + halfWidth;
+  var midY = this.y + halfHeight;
+  var level = this.level + 1;
+  this.nodes[0] = new QuadTree(midX, this.y, halfWidth, halfHeight, level);
+  this.nodes[1] = new QuadTree(this.x, this.y, halfWidth, halfHeight, level);
+  this.nodes[2] = new QuadTree(this.x, midY, halfWidth, halfHeight, level);
+  this.nodes[3] = new QuadTree(midX, midY, halfWidth, halfHeight, level);
+};
+var EXTERNAL_INTERFACE_FEATURE = 1;
+var CLIPBOARD_FEATURE = 2;
+var SHAREDOBJECT_FEATURE = 3;
+var VIDEO_FEATURE = 4;
+var SOUND_FEATURE = 5;
+var NETCONNECTION_FEATURE = 6;
+if (!this.performance) {
+  this.performance = {};
+}
+if (!this.performance.now) {
+  this.performance.now = Date.now;
 }
 var SWF_TAG_CODE_CSM_TEXT_SETTINGS = 74;
 var SWF_TAG_CODE_DEFINE_BINARY_DATA = 87;
 var SWF_TAG_CODE_DEFINE_BITS = 6;
 var SWF_TAG_CODE_DEFINE_BITS_JPEG2 = 21;
 var SWF_TAG_CODE_DEFINE_BITS_JPEG3 = 35;
 var SWF_TAG_CODE_DEFINE_BITS_JPEG4 = 90;
 var SWF_TAG_CODE_DEFINE_BITS_LOSSLESS = 20;
@@ -1512,26 +1840,26 @@ function applySegmentToStyles(segment, s
     if (isMorph) {
     }
   }
   if (styles.line && styles.fill1) {
     path = linePaths[styles.line - 1];
     path.addSegment(commands, data, morphData);
   }
 }
-function convertRecordsToStyledPaths(records, fillPaths, linePaths, dictionary, dependencies, recordsMorph) {
+function convertRecordsToStyledPaths(records, fillPaths, linePaths, dictionary, dependencies, recordsMorph, transferables) {
   var isMorph = recordsMorph !== null;
   var styles = {
       fill0: 0,
       fill1: 0,
       line: 0
     };
   var segment = null;
-  var allFillPaths = fillPaths;
-  var allLinePaths = linePaths;
+  var allPaths;
+  var defaultPath;
   var numRecords = records.length - 1;
   var x = 0;
   var y = 0;
   var morphX = 0;
   var morphY = 0;
   var path;
   for (var i = 0, j = 0; i < numRecords; i++) {
     var record = records[i];
@@ -1539,20 +1867,27 @@ function convertRecordsToStyledPaths(rec
     if (isMorph) {
       morphRecord = recordsMorph[j++];
     }
     if (record.type === 0) {
       if (segment) {
         applySegmentToStyles(segment, styles, linePaths, fillPaths, isMorph);
       }
       if (record.hasNewStyles) {
+        if (!allPaths) {
+          allPaths = [];
+        }
+        push.apply(allPaths, fillPaths);
         fillPaths = createPathsList(record.fillStyles, false, dictionary, dependencies);
-        push.apply(allFillPaths, fillPaths);
+        push.apply(allPaths, linePaths);
         linePaths = createPathsList(record.lineStyles, true, dictionary, dependencies);
-        push.apply(allLinePaths, linePaths);
+        if (defaultPath) {
+          allPaths.push(defaultPath);
+          defaultPath = null;
+        }
         styles = {
           fill0: 0,
           fill1: 0,
           line: 0
         };
       }
       if (record.hasFillStyle0) {
         styles.fill0 = record.fillStyle0;
@@ -1586,17 +1921,43 @@ function convertRecordsToStyledPaths(rec
             morphX = x;
             morphY = y;
             j--;
           }
           segment.morphData.push(morphX, morphY);
         }
       }
     } else {
+      if (!segment) {
+        if (!defaultPath) {
+          var style = {
+              color: {
+                red: 0,
+                green: 0,
+                blue: 0,
+                alpha: 255
+              },
+              width: 20
+            };
+          defaultPath = new SegmentedPath(null, processStyle(style, true));
+        }
+        segment = defaultPath.addSegment([], [], isMorph ? [] : null);
+        segment.commands.push(SHAPE_MOVE_TO);
+        segment.data.push(x, y);
+        if (isMorph) {
+          segment.morphData.push(morphX, morphY);
+        }
+      }
       if (isMorph) {
+        while (morphRecord && morphRecord.type === 0) {
+          morphRecord = recordsMorph[j++];
+        }
+        if (!morphRecord) {
+          morphRecord = record;
+        }
       }
       if (record.isStraight && (!isMorph || morphRecord.isStraight)) {
         x += record.deltaX | 0;
         y += record.deltaY | 0;
         segment.commands.push(SHAPE_LINE_TO);
         segment.data.push(x, y);
         if (isMorph) {
           morphX += morphRecord.deltaX | 0;
@@ -1636,30 +1997,38 @@ function convertRecordsToStyledPaths(rec
             morphY += deltaY;
           }
           segment.morphData.push(cx, cy, morphX, morphY);
         }
       }
     }
   }
   applySegmentToStyles(segment, styles, linePaths, fillPaths, isMorph);
-  push.apply(allFillPaths, allLinePaths);
+  if (allPaths) {
+    push.apply(allPaths, fillPaths);
+  } else {
+    allPaths = fillPaths;
+  }
+  push.apply(allPaths, linePaths);
+  if (defaultPath) {
+    allPaths.push(defaultPath);
+  }
   var removeCount = 0;
-  for (i = 0; i < allFillPaths.length; i++) {
-    path = allFillPaths[i];
+  for (i = 0; i < allPaths.length; i++) {
+    path = allPaths[i];
     if (!path.head()) {
       removeCount++;
       continue;
     }
-    allFillPaths[i - removeCount] = segmentedPathToShapePath(path, isMorph);
-  }
-  allFillPaths.length -= removeCount;
-  return allFillPaths;
-}
-function segmentedPathToShapePath(path, isMorph) {
+    allPaths[i - removeCount] = segmentedPathToShapePath(path, isMorph, transferables);
+  }
+  allPaths.length -= removeCount;
+  return allPaths;
+}
+function segmentedPathToShapePath(path, isMorph, transferables) {
   var start = path.head();
   var end = start;
   var finalRoot = null;
   var finalHead = null;
   var skippedMoves = 0;
   var current = start.prev;
   while (start) {
     while (current) {
@@ -1704,31 +2073,28 @@ function segmentedPathToShapePath(path, 
   var totalCommandsLength = -skippedMoves;
   var totalDataLength = -skippedMoves << 1;
   current = finalRoot;
   while (current) {
     totalCommandsLength += current.commands.length;
     totalDataLength += current.data.length;
     current = current.next;
   }
-  var shape = new ShapePath(path.fillStyle, path.lineStyle, totalCommandsLength, totalDataLength, isMorph);
+  var shape = new ShapePath(path.fillStyle, path.lineStyle, totalCommandsLength, totalDataLength, isMorph, transferables);
   var allCommands = shape.commands;
   var allData = shape.data;
   var allMorphData = shape.morphData;
   var commandsIndex = 0;
   var dataIndex = 0;
   current = finalRoot;
   while (current) {
-    var offset = 0;
     var commands = current.commands;
     var data = current.data;
     var morphData = current.morphData;
-    if (data[0] === allData[dataIndex - 2] && data[1] === allData[dataIndex - 1]) {
-      offset = 1;
-    }
+    var offset = +(data[0] === allData[dataIndex - 2] && data[1] === allData[dataIndex - 1]);
     for (var i = offset; i < commands.length; i++, commandsIndex++) {
       allCommands[commandsIndex] = commands[i];
     }
     for (i = offset << 1; i < data.length; i++, dataIndex++) {
       allData[dataIndex] = data[i];
       if (isMorph) {
         allMorphData[dataIndex] = morphData[i];
       }
@@ -1746,17 +2112,17 @@ var JOIN_STYLE_TYPES = [
     'round',
     'bevel',
     'miter'
   ];
 function processStyle(style, isLineStyle, dictionary, dependencies) {
   if (isLineStyle) {
     style.lineCap = CAPS_STYLE_TYPES[style.endCapStyle | 0];
     style.lineJoin = JOIN_STYLE_TYPES[style.joinStyle | 0];
-    style.miterLimit = style.miterLimitFactor * 2;
+    style.miterLimit = (style.miterLimitFactor || 1.5) * 2;
     if (!style.color && style.hasFill) {
       var fillStyle = processStyle(style.fillStyle, false, dictionary, dependencies);
       style.style = fillStyle.style;
       style.type = fillStyle.type;
       style.transform = fillStyle.transform;
       style.records = fillStyle.records;
       style.focalPoint = fillStyle.focalPoint;
       style.bitmapId = fillStyle.bitmapId;
@@ -1815,19 +2181,20 @@ function createPathsList(styles, isLineS
     } else {
       paths[i] = new SegmentedPath(null, style);
     }
   }
   return paths;
 }
 function defineShape(tag, dictionary) {
   var dependencies = [];
+  var transferables = [];
   var fillPaths = createPathsList(tag.fillStyles, false, dictionary, dependencies);
   var linePaths = createPathsList(tag.lineStyles, true, dictionary, dependencies);
-  var paths = convertRecordsToStyledPaths(tag.records, fillPaths, linePaths, dictionary, dependencies, tag.recordsMorph || null);
+  var paths = convertRecordsToStyledPaths(tag.records, fillPaths, linePaths, dictionary, dependencies, tag.recordsMorph || null, transferables);
   if (tag.bboxMorph) {
     var mbox = tag.bboxMorph;
     extendBoundsByPoint(tag.bbox, mbox.xMin, mbox.yMin);
     extendBoundsByPoint(tag.bbox, mbox.xMax, mbox.yMax);
     mbox = tag.strokeBboxMorph;
     if (mbox) {
       extendBoundsByPoint(tag.strokeBbox, mbox.xMin, mbox.yMin);
       extendBoundsByPoint(tag.strokeBbox, mbox.xMax, mbox.yMax);
@@ -1837,18 +2204,25 @@ function defineShape(tag, dictionary) {
     type: 'shape',
     id: tag.id,
     strokeBbox: tag.strokeBbox,
     strokeBboxMorph: tag.strokeBboxMorph,
     bbox: tag.bbox,
     bboxMorph: tag.bboxMorph,
     isMorph: tag.isMorph,
     paths: paths,
-    require: dependencies.length ? dependencies : null
-  };
+    require: dependencies.length ? dependencies : null,
+    transferables: transferables
+  };
+}
+function logShape(paths, bbox) {
+  var output = '{"bounds":' + JSON.stringify(bbox) + ',"paths":[' + paths.map(function (path) {
+      return path.serialize();
+    }).join() + ']}';
+  console.log(output);
 }
 function SegmentedPath(fillStyle, lineStyle) {
   this.fillStyle = fillStyle;
   this.lineStyle = lineStyle;
   this._head = null;
 }
 SegmentedPath.prototype = {
   addSegment: function (commands, data, morphData) {
@@ -1893,31 +2267,44 @@ SegmentedPath.prototype = {
 var SHAPE_MOVE_TO = 1;
 var SHAPE_LINE_TO = 2;
 var SHAPE_CURVE_TO = 3;
 var SHAPE_WIDE_MOVE_TO = 4;
 var SHAPE_WIDE_LINE_TO = 5;
 var SHAPE_CUBIC_CURVE_TO = 6;
 var SHAPE_CIRCLE = 7;
 var SHAPE_ELLIPSE = 8;
-function ShapePath(fillStyle, lineStyle, commandsCount, dataLength, isMorph) {
+function ShapePath(fillStyle, lineStyle, commandsCount, dataLength, isMorph, transferables) {
   this.fillStyle = fillStyle;
   this.lineStyle = lineStyle;
   if (commandsCount) {
     this.commands = new Uint8Array(commandsCount);
     this.data = new Int32Array(dataLength);
     this.morphData = isMorph ? new Int32Array(dataLength) : null;
   } else {
     this.commands = [];
     this.data = [];
   }
   this.bounds = null;
   this.strokeBounds = null;
-  this.isMorph = isMorph;
+  this.isMorph = !(!isMorph);
   this.fullyInitialized = false;
+  if (inWorker) {
+    this.buffers = [
+      this.commands.buffer,
+      this.data.buffer
+    ];
+    transferables.push(this.commands.buffer, this.data.buffer);
+    if (isMorph) {
+      this.buffers.push(this.morphData.buffer);
+      transferables.push(this.morphData.buffer);
+    }
+  } else {
+    this.buffers = null;
+  }
 }
 ShapePath.prototype = {
   moveTo: function (x, y) {
     if (this.commands[this.commands.length - 1] === SHAPE_MOVE_TO) {
       this.data[this.data.length - 2] = x;
       this.data[this.data.length - 1] = y;
       return;
     }
@@ -1956,18 +2343,18 @@ ShapePath.prototype = {
     }
     ctx.beginPath();
     var commands = this.commands;
     var data = this.data;
     var morphData = this.morphData;
     var formOpen = false;
     var formOpenX = 0;
     var formOpenY = 0;
-    for (var j = 0, k = 0; j < commands.length; j++) {
-      if (!this.isMorph) {
+    if (!this.isMorph) {
+      for (var j = 0, k = 0; j < commands.length; j++) {
         switch (commands[j]) {
         case SHAPE_MOVE_TO:
           formOpen = true;
           formOpenX = data[k++] / 20;
           formOpenY = data[k++] / 20;
           ctx.moveTo(formOpenX, formOpenY);
           break;
         case SHAPE_WIDE_MOVE_TO:
@@ -2022,19 +2409,24 @@ ShapePath.prototype = {
           }
           ctx.moveTo((x + radius) / 20, y / 20);
           ctx.arc(x / 20, y / 20, radius / 20, 0, Math.PI * 2, false);
           if (rX !== rY) {
             ctx.restore();
           }
           break;
         default:
+          if (commands[j] === 0 && j === commands.length - 1) {
+            break;
+          }
           console.warn('Unknown drawing command encountered: ' + commands[j]);
         }
-      } else {
+      }
+    } else {
+      for (var j = 0, k = 0; j < commands.length; j++) {
         switch (commands[j]) {
         case SHAPE_MOVE_TO:
           ctx.moveTo(morph(data[k] / 20, morphData[k++] / 20, ratio), morph(data[k] / 20, morphData[k++] / 20, ratio));
           break;
         case SHAPE_LINE_TO:
           ctx.lineTo(morph(data[k] / 20, morphData[k++] / 20, ratio), morph(data[k] / 20, morphData[k++] / 20, ratio));
           break;
         case SHAPE_CURVE_TO:
@@ -2507,17 +2899,38 @@ ShapePath.prototype = {
         xMax: bounds.xMax + halfLineWidth,
         yMax: bounds.yMax + halfLineWidth
       };
       return this.strokeBounds;
     } else {
       this.strokeBounds = bounds;
     }
     return bounds;
-  }
+  },
+  serialize: function () {
+    var output = '{';
+    if (this.fillStyle) {
+      output += '"fill":' + JSON.stringify(this.fillStyle) + ',';
+    }
+    if (this.lineStyle) {
+      output += '"stroke":' + JSON.stringify(this.lineStyle) + ',';
+    }
+    output += '"commands":[' + Array.apply([], this.commands).join() + '],';
+    output += '"data":[' + Array.apply([], this.data).join() + ']';
+    return output + '}';
+  }
+};
+ShapePath.fromPlainObject = function (obj) {
+  var path = new ShapePath(obj.fill || null, obj.stroke || null);
+  path.commands = new Uint8Array(obj.commands);
+  path.data = new Int32Array(obj.data);
+  if (!inWorker) {
+    finishShapePath(path);
+  }
+  return path;
 };
 function distanceSq(x1, y1, x2, y2) {
   var dX = x2 - x1;
   var dY = y2 - y1;
   return dX * dX + dY * dY;
 }
 function intersectsLine(x, y, x1, y1, x2, y2) {
   return y2 > y !== y1 > y && x < (x1 - x2) * (y - y2) / (y1 - y2) + x2;
@@ -2726,64 +3139,89 @@ function extendBoundsByY(bounds, y) {
     bounds.yMin = y;
   } else if (y > bounds.yMax) {
     bounds.yMax = y;
   }
 }
 function morph(start, end, ratio) {
   return start + (end - start) * ratio;
 }
-function finishShapePaths(paths, dictionary) {
-  for (var i = 0; i < paths.length; i++) {
-    var path = paths[i];
-    if (path.fullyInitialized) {
-      continue;
-    }
-    if (!(path instanceof ShapePath)) {
-      var untypedPath = path;
-      path = paths[i] = new ShapePath(path.fillStyle, path.lineStyle, 0, 0, path.isMorph);
-      path.commands = untypedPath.commands;
-      path.data = untypedPath.data;
-      path.morphData = untypedPath.morphData;
-    }
-    path.fillStyle && initStyle(path.fillStyle, dictionary);
-    path.lineStyle && initStyle(path.lineStyle, dictionary);
-    path.fullyInitialized = true;
-  }
+function finishShapePath(path, dictionary) {
+  if (path.fullyInitialized) {
+    return path;
+  }
+  if (!(path instanceof ShapePath)) {
+    var untypedPath = path;
+    path = new ShapePath(path.fillStyle, path.lineStyle, 0, 0, path.isMorph);
+    path.commands = new Uint8Array(untypedPath.buffers[0]);
+    path.data = new Int32Array(untypedPath.buffers[1]);
+    if (untypedPath.isMorph) {
+      path.morphData = new Int32Array(untypedPath.buffers[2]);
+    }
+    path.buffers = null;
+  }
+  path.fillStyle && initStyle(path.fillStyle, dictionary);
+  path.lineStyle && initStyle(path.lineStyle, dictionary);
+  path.fullyInitialized = true;
+  return path;
 }
 var inWorker = typeof window === 'undefined';
 var factoryCtx = !inWorker ? document.createElement('canvas').getContext('2d') : null;
 function buildLinearGradientFactory(colorStops) {
   var defaultGradient = factoryCtx.createLinearGradient(-1, 0, 1, 0);
   for (var i = 0; i < colorStops.length; i++) {
     defaultGradient.addColorStop(colorStops[i].ratio, colorStops[i].color);
   }
   var fn = function createLinearGradient(ctx, colorTransform) {
     var gradient = ctx.createLinearGradient(-1, 0, 1, 0);
     for (var i = 0; i < colorStops.length; i++) {
       colorTransform.addGradientColorStop(gradient, colorStops[i].ratio, colorStops[i].color);
     }
     return gradient;
   };
-  fn.defaultGradient = defaultGradient;
+  fn.defaultFillStyle = defaultGradient;
   return fn;
 }
 function buildRadialGradientFactory(focalPoint, colorStops) {
   var defaultGradient = factoryCtx.createRadialGradient(focalPoint, 0, 0, 0, 0, 1);
   for (var i = 0; i < colorStops.length; i++) {
     defaultGradient.addColorStop(colorStops[i].ratio, colorStops[i].color);
   }
   var fn = function createRadialGradient(ctx, colorTransform) {
     var gradient = ctx.createRadialGradient(focalPoint, 0, 0, 0, 0, 1);
     for (var i = 0; i < colorStops.length; i++) {
       colorTransform.addGradientColorStop(gradient, colorStops[i].ratio, colorStops[i].color);
     }
     return gradient;
   };
-  fn.defaultGradient = defaultGradient;
+  fn.defaultFillStyle = defaultGradient;
+  return fn;
+}
+function buildBitmapPatternFactory(img, repeat) {
+  var defaultPattern = factoryCtx.createPattern(img, repeat);
+  var cachedTransform, cachedTransformKey;
+  var fn = function createBitmapPattern(ctx, colorTransform) {
+    if (!colorTransform.mode) {
+      return defaultPattern;
+    }
+    var key = colorTransform.getTransformFingerprint();
+    if (key === cachedTransformKey) {
+      return cachedTransform;
+    }
+    var canvas = document.createElement('canvas');
+    canvas.width = img.width;
+    canvas.height = img.height;
+    var ctx = canvas.getContext('2d');
+    colorTransform.setAlpha(ctx, true);
+    ctx.drawImage(img, 0, 0);
+    cachedTransform = ctx.createPattern(canvas, repeat);
+    cachedTransformKey = key;
+    return cachedTransform;
+  };
+  fn.defaultFillStyle = defaultPattern;
   return fn;
 }
 function initStyle(style, dictionary) {
   if (style.type === undefined) {
     return;
   }
   switch (style.type) {
   case GRAPHICS_FILL_SOLID:
@@ -2810,17 +3248,17 @@ function initStyle(style, dictionary) {
     style.style = gradientConstructor;
     break;
   case GRAPHICS_FILL_REPEATING_BITMAP:
   case GRAPHICS_FILL_CLIPPED_BITMAP:
   case GRAPHICS_FILL_NONSMOOTHED_REPEATING_BITMAP:
   case GRAPHICS_FILL_NONSMOOTHED_CLIPPED_BITMAP:
     var bitmap = dictionary[style.bitmapId];
     var repeat = style.type === GRAPHICS_FILL_REPEATING_BITMAP || style.type === GRAPHICS_FILL_NONSMOOTHED_REPEATING_BITMAP;
-    style.style = factoryCtx.createPattern(bitmap.value.props.img, repeat ? 'repeat' : 'no-repeat');
+    style.style = buildBitmapPatternFactory(bitmap.value.props.img, repeat ? 'repeat' : 'no-repeat');
     break;
   default:
     fail('invalid fill style', 'shape');
   }
 }
 var SOUND_SIZE_8_BIT = 0;
 var SOUND_SIZE_16_BIT = 1;
 var SOUND_TYPE_MONO = 0;
@@ -3457,107 +3895,130 @@ if (isWorker) {
     session.pushAsync(data);
     session.close();
   };
 }
 SWF.embed = function (file, doc, container, options) {
   var canvas = doc.createElement('canvas');
   var ctx = canvas.getContext('2d');
   var loader = new flash.display.Loader();
-  var loaderInfo = loader.contentLoaderInfo;
+  var loaderInfo = loader._contentLoaderInfo;
   var stage = new flash.display.Stage();
+  var pixelRatio = 1;
+  var forceHidpiSetting = forceHidpi.value;
   stage._loader = loader;
   loaderInfo._parameters = options.movieParams;
   loaderInfo._url = options.url || (typeof file === 'string' ? file : null);
   loaderInfo._loaderURL = options.loaderURL || loaderInfo._url;
-  var pixelRatio = 'devicePixelRatio' in window ? window.devicePixelRatio : 1;
-  var canvasHolder = null;
-  canvas._pixelRatio = pixelRatio;
-  if (pixelRatio > 1) {
-    var cssScale = 'scale(' + 1 / pixelRatio + ', ' + 1 / pixelRatio + ')';
-    canvas.setAttribute('style', '-moz-transform: ' + cssScale + ';' + '-webkit-transform: ' + cssScale + ';' + 'transform: ' + cssScale + ';' + '-moz-transform-origin: 0% 0%;' + '-webkit-transform-origin: 0% 0%;' + 'transform-origin: 0% 0%;');
-    canvasHolder = doc.createElement('div');
-    canvasHolder.setAttribute('style', 'display: inline-block; overflow: hidden;');
-    canvasHolder.appendChild(canvas);
-  }
-  stage._contentsScaleFactor = pixelRatio;
   loader._parent = stage;
   loader._stage = stage;
-  function fitCanvas(container, canvas) {
-    if (canvasHolder) {
-      canvasHolder.style.width = container.clientWidth + 'px';
-      canvasHolder.style.height = container.clientHeight + 'px';
-    }
-    canvas.width = container.clientWidth * pixelRatio;
-    canvas.height = container.clientHeight * pixelRatio;
+  function setCanvasSize(width, height) {
+    if (pixelRatio === 1) {
+      canvas.width = width | 0;
+      canvas.height = height | 0;
+      return;
+    }
+    var canvasWidth = Math.floor(width * pixelRatio);
+    var canvasHeight = Math.floor(height * pixelRatio);
+    canvas.style.width = canvasWidth / pixelRatio + 'px';
+    canvas.style.height = canvasHeight / pixelRatio + 'px';
+    canvas.width = canvasWidth;
+    canvas.height = canvasHeight;
+  }
+  function fitCanvas(container) {
+    setCanvasSize(container.clientWidth, container.clientHeight);
     stage._invalid = true;
   }
   loaderInfo._addEventListener('init', function () {
+    if (forceHidpiSetting || loaderInfo._swfVersion >= 18) {
+      pixelRatio = 'devicePixelRatio' in window ? window.devicePixelRatio : 1;
+    }
+    canvas._pixelRatio = pixelRatio;
+    stage._contentsScaleFactor = pixelRatio;
     if (container.clientHeight) {
-      fitCanvas(container, canvas);
+      fitCanvas(container);
       window.addEventListener('resize', function () {
-        fitCanvas(container, canvas);
-      });
-    } else {
-      if (canvasHolder) {
-        canvasHolder.style.width = stage._stageWidth / 20 + 'px';
-        canvasHolder.style.height = stage._stageHeight / 20 + 'px';
-      }
-      canvas.width = stage._stageWidth * pixelRatio / 20;
-      canvas.height = stage._stageHeight * pixelRatio / 20;
+        fitCanvas(container);
+      });
+    } else {
+      setCanvasSize(stage._stageWidth / 20, stage._stageHeight / 20);
     }
     container.setAttribute('style', 'position: relative');
     canvas.addEventListener('click', function () {
       ShumwayKeyboardListener.focus = stage;
       stage._mouseTarget._dispatchEvent('click');
     });
     canvas.addEventListener('dblclick', function () {
       if (stage._mouseTarget._doubleClickEnabled) {
         stage._mouseTarget._dispatchEvent('doubleClick');
       }
     });
     canvas.addEventListener('mousedown', function () {
-      if (stage._mouseTarget._buttonMode) {
-        stage._mouseTarget._gotoButtonState('down');
-      }
-      stage._mouseTarget._dispatchEvent('mouseDown');
+      stage._mouseEvents.push('mousedown');
     });
     canvas.addEventListener('mousemove', function (domEvt) {
       var node = this;
       var left = 0;
       var top = 0;
       if (node.offsetParent) {
         do {
           left += node.offsetLeft;
           top += node.offsetTop;
         } while (node = node.offsetParent);
       }
       var m = stage._concatenatedTransform;
-      var mouseX = ((domEvt.pageX - left) * pixelRatio - m.tx) / m.a;
-      var mouseY = ((domEvt.pageY - top) * pixelRatio - m.ty) / m.d;
+      var mouseX = ((domEvt.pageX - left) * pixelRatio - m.tx / 20) / m.a;
+      var mouseY = ((domEvt.pageY - top) * pixelRatio - m.ty / 20) / m.d;
       if (mouseX !== stage._mouseX || mouseY !== stage._mouseY) {
         stage._mouseMoved = true;
         stage._mouseX = mouseX * 20;
         stage._mouseY = mouseY * 20;
       }
     });
     canvas.addEventListener('mouseup', function () {
-      if (stage._mouseTarget._buttonMode) {
-        stage._mouseTarget._gotoButtonState('over');
-      }
-      stage._mouseTarget._dispatchEvent('mouseUp');
+      stage._mouseEvents.push('mouseup');
     });
     canvas.addEventListener('mouseover', function () {
       stage._mouseMoved = true;
       stage._mouseOver = true;
     });
     canvas.addEventListener('mouseout', function () {
       stage._mouseMoved = true;
       stage._mouseOver = false;
     });
+    window.addEventListener('message', function (evt) {
+      var data = evt.data;
+      if (typeof data !== 'object' || data === null) {
+        return;
+      }
+      var type = data.type;
+      switch (type) {
+      case 'mousemove':
+      case 'mouseup':
+      case 'mousedown':
+        var isMouseMove = type === 'mousemove';
+        stage._mouseMoved = true;
+        stage._mouseOver = true;
+        stage._mouseX = data.x * 20;
+        stage._mouseY = data.y * 20;
+        if (!isMouseMove) {
+          stage._mouseEvents.push(type);
+        }
+        break;
+      case 'mouseover':
+      case 'mouseout':
+        stage._mouseMoved = true;
+        stage._mouseOver = type === 'mouseover';
+        break;
+      case 'keyup':
+      case 'keydown':
+        stage._dispatchEvent(new flash.events.KeyboardEvent(type === 'keyup' ? 'keyUp' : 'keyDown', true, false, data.charCode, data.keyCode, data.keyLocation, data.ctrlKey || false, data.altKey || false, data.shiftKey || false));
+        break;
+      }
+    }, false);
     var bgcolor = loaderInfo._backgroundColor;
     if (options.objectParams) {
       var m;
       if (options.objectParams.bgcolor && (m = /#([0-9A-F]{6})/i.exec(options.objectParams.bgcolor))) {
         var hexColor = parseInt(m[1], 16);
         bgcolor = {
           red: hexColor >> 16 & 255,
           green: hexColor >> 8 & 255,
@@ -3573,20 +4034,19 @@ SWF.embed = function (file, doc, contain
           alpha: 0
         };
       }
     }
     stage._color = bgcolor;
     ctx.fillStyle = rgbaObjToStr(bgcolor);
     ctx.fillRect(0, 0, canvas.width, canvas.height);
     var root = loader._content;
-    stage._children[0] = root;
-    root._dispatchEvent('added');
+    root._dispatchEvent('added', undefined, true);
     root._dispatchEvent('addedToStage');
-    container.appendChild(canvasHolder || canvas);
+    container.appendChild(canvas);
     if (options.onStageInitialized) {
       options.onStageInitialized(stage);
     }
     renderStage(stage, ctx, options);
   });
   if (options.onComplete) {
     loaderInfo._addEventListener('complete', function () {
       options.onComplete();
@@ -3599,21 +4059,29 @@ var rendererOptions = coreOptions.regist
 var traceRenderer = rendererOptions.register(new Option('tr', 'traceRenderer', 'number', 0, 'trace renderer execution'));
 var disablePreVisitor = rendererOptions.register(new Option('dpv', 'disablePreVisitor', 'boolean', false, 'disable pre visitor'));
 var disableRenderVisitor = rendererOptions.register(new Option('drv', 'disableRenderVisitor', 'boolean', false, 'disable render visitor'));
 var disableMouseVisitor = rendererOptions.register(new Option('dmv', 'disableMouseVisitor', 'boolean', false, 'disable mouse visitor'));
 var showRedrawRegions = rendererOptions.register(new Option('rr', 'showRedrawRegions', 'boolean', false, 'show redraw regions'));
 var renderAsWireframe = rendererOptions.register(new Option('raw', 'renderAsWireframe', 'boolean', false, 'render as wireframe'));
 var showQuadTree = rendererOptions.register(new Option('qt', 'showQuadTree', 'boolean', false, 'show quad tree'));
 var turboMode = rendererOptions.register(new Option('', 'turbo', 'boolean', false, 'turbo mode'));
+var forceHidpi = rendererOptions.register(new Option('', 'forceHidpi', 'boolean', false, 'force hidpi'));
+var enableConstructChildren = rendererOptions.register(new Option('', 'constructChildren', 'boolean', true, 'Construct Children'));
+var enableEnterFrame = rendererOptions.register(new Option('', 'enterFrame', 'boolean', true, 'Enter Frame'));
+var enableAdvanceFrame = rendererOptions.register(new Option('', 'advanceFrame', 'boolean', true, 'Advance Frame'));
 if (typeof FirefoxCom !== 'undefined') {
   turboMode.value = FirefoxCom.requestSync('getBoolPref', {
     pref: 'shumway.turboMode',
     def: false
   });
+  forceHidpi.value = FirefoxCom.requestSync('getBoolPref', {
+    pref: 'shumway.force_hidpi',
+    def: false
+  });
 }
 var CanvasCache = {
     cache: [],
     getCanvas: function getCanvas(protoCanvas) {
       var tempCanvas = this.cache.shift();
       if (!tempCanvas) {
         tempCanvas = {
           canvas: document.createElement('canvas')
@@ -3643,18 +4111,17 @@ function visitContainer(container, visit
   var children = container._children;
   visitor.childrenStart(container);
   for (var i = 0, n = children.length; i < n; i++) {
     var child = children[i];
     if (!child) {
       continue;
     }
     if (visitor.ignoreVisibleAttribute || child._visible && !child._maskedObject) {
-      var isContainer = flash.display.DisplayObjectContainer.class.isInstanceOf(child) || flash.display.SimpleButton.class.isInstanceOf(child);
-      visitor.visit(child, isContainer, visitContainer, context);
+      visitor.visit(child, visitContainer, context);
     }
   }
   visitor.childrenEnd(container);
 }
 var BlendModeNameMap = {
     'normal': 'normal',
     'multiply': 'multiply',
     'screen': 'screen',
@@ -3676,30 +4143,46 @@ function RenderVisitor(root, ctx, invali
   this.clipDepth = null;
   this.clipStack = null;
 }
 RenderVisitor.prototype = {
   ignoreVisibleAttribute: false,
   start: function () {
     visitContainer(this.root, this, new RenderingContext(this.refreshStage, this.invalidPath));
   },
-  startFragment: function () {
-    var isContainer = flash.display.DisplayObjectContainer.class.isInstanceOf(this.root) || flash.display.SimpleButton.class.isInstanceOf(this.root);
-    var t = this.root._currentTransform;
+  startFragment: function (matrix) {
+    var root = this.root;
+    var currentTransform = root._currentTransform;
+    var t = currentTransform;
+    if (matrix) {
+      t = root._currentTransform = {
+        a: matrix.a,
+        b: matrix.b,
+        c: matrix.c,
+        d: matrix.d,
+        tx: matrix.tx * 20 | 0,
+        ty: matrix.ty * 20 | 0
+      };
+      root._invalidateTransform();
+    }
     var inverse;
     if (t) {
       inverse = new flash.geom.Matrix(t.a, t.b, t.c, t.d, t.tx / 20, t.ty / 20);
       inverse.invert();
       this.ctx.save();
       this.ctx.transform(inverse.a, inverse.b, inverse.c, inverse.d, inverse.tx, inverse.ty);
     }
-    this.visit(this.root, isContainer, visitContainer, new RenderingContext(this.refreshStage, this.invalidPath));
+    this.visit(root, visitContainer, new RenderingContext(this.refreshStage, this.invalidPath));
     if (t) {
       this.ctx.restore();
     }
+    if (matrix) {
+      root._currentTransform = currentTransform;
+      root._invalidateTransform();
+    }
   },
   childrenStart: function (parent) {
     if (this.depth === 0) {
       var ctx = this.ctx;
       ctx.save();
       if (this.invalidPath && !this.refreshStage && !renderAsWireframe.value) {
         this.invalidPath.draw(ctx);
         ctx.clip();
@@ -3728,114 +4211,142 @@ RenderVisitor.prototype = {
         next: this.clipStack
       };
       this.clipDepth = null;
     }
   },
   childrenEnd: function (parent) {
     if (this.clipDepth) {
       while (this.clipDepth.length > 0) {
-        this.clipDepth.pop();
-        this.ctx.restore();
+        var clipDepthInfo = this.clipDepth.pop();
+        this.clipEnd(clipDepthInfo);
+        this.ctx = clipDepthInfo.ctx;
       }
       this.clipDepth = null;
     }
     if (this.clipStack && this.clipStack.depth === this.depth) {
       this.clipDepth = this.clipStack.clip;
       this.clipStack = this.clipStack.next;
     }
     this.depth--;
     if (this.depth === 0) {
       this.ctx.restore();
       this.invalidPath = null;
     }
   },
-  visit: function (child, isContainer, visitContainer, context) {
+  visit: function (child, visitContainer, context) {
     var ctx = this.ctx;
     var parentHasClippingMask = context.isClippingMask;
     var parentColorTransform = context.colorTransform;
     var clippingMask = parentHasClippingMask === true;
     if (child._cxform) {
       context.colorTransform = parentColorTransform.applyCXForm(child._cxform);
     }
     if (!clippingMask) {
-      while (this.clipDepth && this.clipDepth.length > 0 && child._depth > this.clipDepth[0]) {
-        this.clipDepth.shift();
-        ctx.restore();
+      while (this.clipDepth && this.clipDepth.length > 0 && child._depth > this.clipDepth[0].clipDepth) {
+        var clipDepthInfo = this.clipDepth.shift();
+        this.clipEnd(clipDepthInfo);
+        ctx = this.ctx = clipDepthInfo.ctx;
       }
       if (child._clipDepth) {
+        context.isClippingMask = clippingMask = true;
+        var clipDepthInfo = this.clipStart(child);
         if (!this.clipDepth) {
-          this.clipDepth = [];
-        }
-        context.isClippingMask = clippingMask = true;
-        this.clipDepth.unshift(child._clipDepth);
-        ctx.save();
-      }
-    }
-    if (clippingMask && isContainer) {
+          this.clipDepth = [
+            clipDepthInfo
+          ];
+        } else {
+          this.clipDepth.unshift(clipDepthInfo);
+        }
+        ctx = this.ctx = clipDepthInfo.mask.ctx;
+      } else {
+        if (this.clipDepth && this.clipDepth.length > 0 && child._depth <= this.clipDepth[0].clipDepth) {
+          ctx = this.ctx = this.clipDepth[0].maskee.ctx;
+        }
+      }
+    }
+    if (clippingMask && child._isContainer) {
       ctx.save();
       renderDisplayObject(child, ctx, context);
       for (var i = 0, n = child._children.length; i < n; i++) {
         var child1 = child._children[i];
         if (!child1) {
           continue;
         }
         if (this.ignoreVisibleAttribute || child1._visible && !child1._maskedObject) {
-          var isContainer = flash.display.DisplayObjectContainer.class.isInstanceOf(child1) || flash.display.SimpleButton.class.isInstanceOf(child1);
-          this.visit(child1, isContainer, visitContainer, context);
+          this.visit(child1, visitContainer, context);
         }
       }
       ctx.restore();
-      ctx.clip();
+      ctx.fill();
       context.isClippingMask = parentHasClippingMask;
       context.colorTransform = parentColorTransform;
       return;
     }
     ctx.save();
     ctx.globalCompositeOperation = getBlendModeName(child._blendMode);
     if (child._mask) {
-      var m = child._parent._getConcatenatedTransform(true);
-      var tempCanvas, tempCtx, maskCanvas, maskCtx;
-      maskCanvas = CanvasCache.getCanvas(ctx.canvas);
-      maskCtx = maskCanvas.ctx;
-      maskCtx.setTransform(m.a, m.b, m.c, m.d, m.tx, m.ty);
-      var isMaskContainer = flash.display.DisplayObjectContainer.class.isInstanceOf(child._mask) || flash.display.SimpleButton.class.isInstanceOf(child._mask);
-      this.ctx = maskCtx;
-      this.visit(child._mask, isMaskContainer, visitContainer, new RenderingContext(this.refreshStage));
+      var clipInfo = this.clipStart(child);
+      var mask = clipInfo.mask;
+      var maskee = clipInfo.maskee;
+      var savedClipDepth = this.clipDepth;
+      this.clipDepth = null;
+      this.ctx = mask.ctx;
+      this.visit(child._mask, visitContainer, new RenderingContext(this.refreshStage));
       this.ctx = ctx;
-      tempCanvas = CanvasCache.getCanvas(ctx.canvas);
-      tempCtx = tempCanvas.ctx;
-      tempCtx.setTransform(m.a, m.b, m.c, m.d, m.tx, m.ty);
-      renderDisplayObject(child, tempCtx, context);
-      if (isContainer) {
-        this.ctx = tempCtx;
+      this.clipDepth = savedClipDepth;
+      renderDisplayObject(child, maskee.ctx, context);
+      if (child._isContainer) {
+        this.ctx = maskee.ctx;
         visitContainer(child, this, context);
         this.ctx = ctx;
       }
-      tempCtx.globalCompositeOperation = 'destination-in';
-      tempCtx.setTransform(1, 0, 0, 1, 0, 0);
-      tempCtx.drawImage(maskCanvas.canvas, 0, 0);
-      ctx.save();
-      ctx.setTransform(1, 0, 0, 1, 0, 0);
-      ctx.drawImage(tempCanvas.canvas, 0, 0);
-      ctx.restore();
-      CanvasCache.releaseCanvas(tempCanvas);
-      CanvasCache.releaseCanvas(maskCanvas);
+      this.clipEnd(clipInfo);
     } else {
       renderDisplayObject(child, ctx, context);
-      if (isContainer) {
+      if (child._isContainer) {
         visitContainer(child, this, context);
       }
     }
     ctx.restore();
     if (clippingMask) {
-      ctx.clip();
+      ctx.fill();
     }
     context.isClippingMask = parentHasClippingMask;
     context.colorTransform = parentColorTransform;
+  },
+  clipStart: function (child) {
+    var m = child._parent._getConcatenatedTransform(true);
+    var tx = m.tx / 20;
+    var ty = m.ty / 20;
+    var mask = CanvasCache.getCanvas(this.ctx.canvas);
+    mask.ctx.setTransform(m.a, m.b, m.c, m.d, tx, ty);
+    var maskee = CanvasCache.getCanvas(this.ctx.canvas);
+    maskee.ctx.setTransform(m.a, m.b, m.c, m.d, tx, ty);
+    var clipInfo = {
+        ctx: this.ctx,
+        mask: mask,
+        maskee: maskee,
+        clipDepth: child._clipDepth
+      };
+    return clipInfo;
+  },
+  clipEnd: function (clipInfo) {
+    var ctx = clipInfo.ctx;
+    var mask = clipInfo.mask;
+    var maskee = clipInfo.maskee;
+    maskee.ctx.globalCompositeOperation = 'destination-in';
+    maskee.ctx.setTransform(1, 0, 0, 1, 0, 0);
+    maskee.ctx.drawImage(mask.canvas, 0, 0);
+    ctx.save();
+    ctx.setTransform(1, 0, 0, 1, 0, 0);
+    ctx.drawImage(maskee.canvas, 0, 0);
+    ctx.restore();
+    CanvasCache.releaseCanvas(mask);
+    CanvasCache.releaseCanvas(maskee);
   }
 };
 function RenderingColorTransform() {
   this.mode = null;
   this.transform = [
     1,
     1,
     1,
@@ -3872,27 +4383,27 @@ RenderingColorTransform.prototype = {
     return clone;
   },
   setFillStyle: function (ctx, style) {
     if (this.mode === 'complex') {
       style = typeof style === 'function' ? style(ctx, this) : this.convertColor(style);
     } else if (typeof style === 'number') {
       style = this.convertNumericColor(style);
     } else if (typeof style === 'function') {
-      style = style.defaultGradient;
+      style = style.defaultFillStyle;
     }
     ctx.fillStyle = style;
   },
   setStrokeStyle: function (ctx, style) {
     if (this.mode === 'complex') {
       style = typeof style === 'function' ? style(ctx, this) : this.convertColor(style);
     } else if (typeof style === 'number') {
       style = this.convertNumericColor(style);
     } else if (typeof style === 'function') {
-      style = style.defaultGradient;
+      style = style.defaultFillStyle;
     }
     ctx.strokeStyle = style;
   },
   addGradientColorStop: function (gradient, ratio, style) {
     if (this.mode === 'complex') {
       style = this.convertColor(style);
     } else if (typeof style === 'number') {
       style = this.convertNumericColor(style);
@@ -3939,16 +4450,19 @@ RenderingColorTransform.prototype = {
     default:
       return style;
     }
     var r = Math.min(255, Math.max(0, m[1] * t[0] + t[4])) | 0;
     var g = Math.min(255, Math.max(0, m[2] * t[1] + t[5])) | 0;
     var b = Math.min(255, Math.max(0, m[3] * t[2] + t[6])) | 0;
     var a = Math.min(1, Math.max(0, m[4] * t[3] + t[7] / 256));
     return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';
+  },
+  getTransformFingerprint: function () {
+    return this.transform.join('|');
   }
 };
 function RenderingContext(refreshStage, invalidPath) {
   this.refreshStage = refreshStage === true;
   this.invalidPath = invalidPath;
   this.isClippingMask = false;
   this.colorTransform = new RenderingColorTransform();
 }
@@ -4008,17 +4522,16 @@ function renderDisplayObject(child, ctx,
 }
 function renderQuadTree(ctx, qtree) {
   ctx.strokeRect(qtree.x / 20, qtree.y / 20, qtree.width / 20, qtree.height / 20);
   var nodes = qtree.nodes;
   for (var i = 0; i < nodes.length; i++) {
     renderQuadTree(ctx, nodes[i]);
   }
 }
-var fps;
 var renderingTerminated = false;
 var samplesLeftPlusOne = 0;
 function triggerSampling(count) {
   samplesLeftPlusOne = -count - 1;
 }
 function sampleStart() {
   if (!samplesLeftPlusOne) {
     return;
@@ -4035,16 +4548,28 @@ function sampleEnd() {
   if (!samplesLeftPlusOne) {
     return;
   }
   samplesLeftPlusOne--;
   if (samplesLeftPlusOne === 1) {
     console.profileEnd('Sample');
   }
 }
+var timeline;
+function timelineEnter(name) {
+  timeline && timeline.enter(name);
+}
+function timelineLeave(name) {
+  timeline && timeline.leave(name);
+}
+function timelineWrapBroadcastMessage(domain, message) {
+  timelineEnter(message);
+  domain.broadcastMessage(message);
+  timelineLeave(message);
+}
 function renderStage(stage, ctx, events) {
   var frameWidth, frameHeight;
   function updateRenderTransform() {
     frameWidth = ctx.canvas.width;
     frameHeight = ctx.canvas.height;
     var scaleX = frameWidth / stage._stageWidth * 20;
     var scaleY = frameHeight / stage._stageHeight * 20;
     switch (stage._scaleMode) {
@@ -4085,18 +4610,18 @@ function renderStage(stage, ctx, events)
       offsetY = frameHeight - scaleY * stage._stageHeight / 20;
     } else {
       offsetY = (frameHeight - scaleY * stage._stageHeight / 20) / 2;
     }
     ctx.setTransform(scaleX, 0, 0, scaleY, offsetX, offsetY);
     var m = stage._concatenatedTransform;
     m.a = scaleX;
     m.d = scaleY;
-    m.tx = offsetX;
-    m.ty = offsetY;
+    m.tx = offsetX * 20;
+    m.ty = offsetY * 20;
   }
   updateRenderTransform();
   var frameTime = 0;
   var maxDelay = 1000 / stage._frameRate;
   var nextRenderAt = performance.now();
   var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || window.setTimeout;
   var renderDummyBalls;
   var dummyBalls;
@@ -4175,90 +4700,94 @@ function renderStage(stage, ctx, events)
       updateRenderTransform();
       stage._invalid = false;
       refreshStage = true;
     }
     var mouseMoved = false;
     if (stage._mouseMoved) {
       stage._mouseMoved = false;
       mouseMoved = stage._mouseOver;
+    } else {
+      stage._handleMouseButtons();
     }
     if (renderFrame || refreshStage || mouseMoved) {
       FrameCounter.clear();
       var frameStartTime = performance.now();
       traceRenderer.value && appendToFrameTerminal('Begin Frame #' + frameCount++, 'purple');
       var domain = avm2.systemDomain;
       if (renderFrame) {
         frameTime = now;
         maxDelay = 1000 / stage._frameRate;
         if (!turboMode.value) {
           while (nextRenderAt < now) {
             nextRenderAt += maxDelay;
           }
         }
-        fps && fps.enter('EVENTS');
+        timelineEnter('EVENTS');
         if (firstRun) {
           firstRun = false;
         } else {
-          domain.broadcastMessage('advanceFrame');
-          domain.broadcastMessage('enterFrame');
-          domain.broadcastMessage('constructChildren');
-        }
-        domain.broadcastMessage('frameConstructed');
-        domain.broadcastMessage('executeFrame');
-        domain.broadcastMessage('exitFrame');
-        fps && fps.leave('EVENTS');
+          enableAdvanceFrame.value && timelineWrapBroadcastMessage(domain, 'advanceFrame');
+          enableEnterFrame.value && timelineWrapBroadcastMessage(domain, 'enterFrame');
+          enableConstructChildren.value && timelineWrapBroadcastMessage(domain, 'constructChildren');
+        }
+        timelineWrapBroadcastMessage(domain, 'frameConstructed');
+        timelineWrapBroadcastMessage(domain, 'executeFrame');
+        timelineWrapBroadcastMessage(domain, 'exitFrame');
+        timelineLeave('EVENTS');
       }
       if (stage._deferRenderEvent) {
         stage._deferRenderEvent = false;
         domain.broadcastMessage('render', 'render');
       }
       if (isCanvasVisible(ctx.canvas) && (refreshStage || renderFrame)) {
         var invalidPath = null;
         if (!disablePreVisitor.value) {
           traceRenderer.value && frameWriter.enter('> Pre Visitor');
-          fps && fps.enter('PRE');
+          timelineEnter('PRE');
           invalidPath = stage._processInvalidRegions(true);
-          fps && fps.leave('PRE');
+          timelineLeave('PRE');
           traceRenderer.value && frameWriter.leave('< Pre Visitor');
         } else {
           stage._processInvalidRegions(false);
         }
         if (!disableRenderVisitor.value) {
-          fps && fps.enter('RENDER');
+          timelineEnter('RENDER');
           traceRenderer.value && frameWriter.enter('> Render Visitor');
           new RenderVisitor(stage, ctx, invalidPath, refreshStage).start();
           traceRenderer.value && frameWriter.leave('< Render Visitor');
-          fps && fps.leave('RENDER');
+          timelineLeave('RENDER');
         }
         if (showQuadTree.value) {
           ctx.strokeStyle = 'green';
           renderQuadTree(ctx, stage._qtree);
         }
         if (invalidPath && !refreshStage && showRedrawRegions.value) {
           ctx.strokeStyle = 'red';
           invalidPath.draw(ctx);
           ctx.stroke();
         }
       }
       if (mouseMoved && !disableMouseVisitor.value) {
-        fps && renderFrame && fps.enter('MOUSE');
+        renderFrame && timelineEnter('MOUSE');
         traceRenderer.value && frameWriter.enter('> Mouse Visitor');
         stage._handleMouse();
         traceRenderer.value && frameWriter.leave('< Mouse Visitor');
-        fps && renderFrame && fps.leave('MOUSE');
+        renderFrame && timelineLeave('MOUSE');
         ctx.canvas.style.cursor = stage._cursor;
       }
       if (renderFrame && events.onAfterFrame) {
         events.onAfterFrame();
       }
       if (traceRenderer.value) {
+        frameWriter.enter('> Frame Counters');
         for (var name in FrameCounter.counts) {
-          appendToFrameTerminal(name + ': ' + FrameCounter.counts[name], 'gray');
-        }
+          frameWriter.writeLn(name + ': ' + FrameCounter.counts[name]);
+        }
+        frameWriter.leave('< Frame Counters');
         var frameElapsedTime = performance.now() - frameStartTime;
         var frameFPS = 1000 / frameElapsedTime;
         frameFPSAverage.push(frameFPS);
         traceRenderer.value && appendToFrameTerminal('End Frame Time: ' + frameElapsedTime.toFixed(2) + ' (' + frameFPS.toFixed(2) + ' fps, ' + frameFPSAverage.average().toFixed(2) + ' average fps)', 'purple');
       }
     } else {
       traceRenderer.value && appendToFrameTerminal('Skip Frame', 'black');
     }
@@ -4819,16 +5348,29 @@ var tagHandler = function (global) {
       if (tagCode === 82) {
         $.name = readString($bytes, $stream, 0);
       } else {
         $.name = '';
       }
       $.data = readBinary($bytes, $stream, 0);
       return $;
     }
+    function exportAssets($bytes, $stream, $, swfVersion, tagCode) {
+      $ || ($ = {});
+      var exportsCount = readUi16($bytes, $stream);
+      var $0 = $.exports = [];
+      var $1 = exportsCount;
+      while ($1--) {
+        var $2 = {};
+        $2.symbolId = readUi16($bytes, $stream);
+        $2.className = readString($bytes, $stream, 0);
+        $0.push($2);
+      }
+      return $;
+    }
     function symbolClass($bytes, $stream, $, swfVersion, tagCode) {
       $ || ($ = {});
       var symbolCount = readUi16($bytes, $stream);
       var $0 = $.exports = [];
       var $1 = symbolCount;
       while ($1--) {
         var $2 = {};
         $2.symbolId = readUi16($bytes, $stream);
@@ -5634,17 +6176,17 @@ var tagHandler = function (global) {
       35: defineImage,
       36: defineBitmap,
       37: defineText,
       39: undefined,
       43: frameLabel,
       45: soundStreamHead,
       46: defineShape,
       48: defineFont2,
-      56: undefined,
+      56: exportAssets,
       57: undefined,
       58: undefined,
       59: doAction,
       60: undefined,
       61: undefined,
       62: undefined,
       64: undefined,
       65: undefined,
@@ -5684,68 +6226,89 @@ var readHeader = function readHeader($by
   $0.yMin = yMin;
   $0.yMax = yMax;
   align($bytes, $stream);
   var frameRateFraction = readUi8($bytes, $stream);
   $.frameRate = readUi8($bytes, $stream) + frameRateFraction / 256;
   $.frameCount = readUi16($bytes, $stream);
   return $;
 };
-function readTags(context, stream, swfVersion, onprogress) {
+function readTags(context, stream, swfVersion, final, onprogress) {
   var tags = context.tags;
   var bytes = stream.bytes;
   var lastSuccessfulPosition;
+  var tag = null;
+  if (context._readTag) {
+    tag = context._readTag;
+    delete context._readTag;
+  }
   try {
-    do {
+    while (stream.pos < stream.end) {
       lastSuccessfulPosition = stream.pos;
       stream.ensure(2);
       var tagCodeAndLength = readUi16(bytes, stream);
+      if (!tagCodeAndLength) {
+        final = true;
+        break;
+      }
       var tagCode = tagCodeAndLength >> 6;
       var length = tagCodeAndLength & 63;
       if (length === 63) {
         stream.ensure(4);
         length = readUi32(bytes, stream);
       }
+      if (tag) {
+        if (tagCode === 1 && tag.code === 1) {
+          tag.repeat++;
+          stream.pos += length;
+          continue;
+        }
+        tags.push(tag);
+        if (onprogress && tag.id !== undefined) {
+          onprogress(context);
+        }
+        tag = null;
+      }
       stream.ensure(length);
-      if (tagCode === 0) {
-        break;
-      }
       var substream = stream.substream(stream.pos, stream.pos += length);
       var subbytes = substream.bytes;
-      var tag = {
+      var nextTag = {
           code: tagCode
         };
       if (tagCode === 39) {
-        tag.type = 'sprite';
-        tag.id = readUi16(subbytes, substream);
-        tag.frameCount = readUi16(subbytes, substream);
-        tag.tags = [];
-        readTags(tag, substream, swfVersion);
+        nextTag.type = 'sprite';
+        nextTag.id = readUi16(subbytes, substream);
+        nextTag.frameCount = readUi16(subbytes, substream);
+        nextTag.tags = [];
+        readTags(nextTag, substream, swfVersion, true);
+      } else if (tagCode === 1) {
+        nextTag.repeat = 1;
       } else {
         var handler = tagHandler[tagCode];
         if (handler) {
-          handler(subbytes, substream, tag, swfVersion, tagCode);
-        }
-      }
+          handler(subbytes, substream, nextTag, swfVersion, tagCode);
+        }
+      }
+      tag = nextTag;
+    }
+    if (tag && final) {
+      tag.finalTag = true;
       tags.push(tag);
-      if (tagCode === 1) {
-        while (stream.pos + 2 <= stream.end && stream.getUint16(stream.pos, true) >> 6 === 1) {
-          tags.push(tag);
-          stream.pos += 2;
-        }
-        if (onprogress)
-          onprogress(context);
-      } else if (onprogress && tag.id !== undefined) {
+      if (onprogress) {
         onprogress(context);
       }
-    } while (stream.pos < stream.end);
+    } else {
+      context._readTag = tag;
+    }
   } catch (e) {
-    if (e !== StreamNoDataError)
+    if (e !== StreamNoDataError) {
       throw e;
+    }
     stream.pos = lastSuccessfulPosition;
+    context._readTag = tag;
   }
 }
 function HeadTailBuffer(defaultSize) {
   this.bufferSize = defaultSize || 16;
   this.buffer = new Uint8Array(this.bufferSize);
   this.pos = 0;
 }
 HeadTailBuffer.prototype = {
@@ -5884,22 +6447,24 @@ BodyParser.prototype = {
       if (options.onstart)
         options.onstart(swf);
       swf.tags = [];
       this.initialize = false;
     } else {
       buffer.push(data);
       stream = buffer.createStream();
     }
+    var finalBlock = false;
     if (progressInfo) {
       swf.bytesLoaded = progressInfo.bytesLoaded;
       swf.bytesTotal = progressInfo.bytesTotal;
+      finalBlock = progressInfo.bytesLoaded >= progressInfo.bytesTotal;
     }
     var readStartTime = performance.now();
-    readTags(swf, stream, swfVersion, options.onprogress);
+    readTags(swf, stream, swfVersion, finalBlock, options.onprogress);
     swf.parseTime += performance.now() - readStartTime;
     var read = stream.pos;
     buffer.removeHead(read);
     this.totalRead += read;
     if (this.totalRead >= this.length && options.oncomplete) {
       options.oncomplete(swf);
     }
   }
@@ -6002,16 +6567,418 @@ SWF.parse = function (buffer, options) {
   var pipe = SWF.parseAsync(options);
   var bytes = new Uint8Array(buffer);
   var progressInfo = {
       bytesLoaded: bytes.length,
       bytesTotal: bytes.length
     };
   pipe.push(bytes, progressInfo);
 };
+var $RELEASE = false;
+var isWorker = typeof window === 'undefined';
+if (isWorker && !true) {
+  importScripts.apply(null, [
+    '../../lib/DataView.js/DataView.js',
+    '../flash/util.js',
+    'config.js',
+    'swf.js',
+    'types.js',
+    'structs.js',
+    'tags.js',
+    'inflate.js',
+    'stream.js',
+    'templates.js',
+    'generator.js',
+    'handlers.js',
+    'parser.js',
+    'bitmap.js',
+    'button.js',
+    'font.js',
+    'image.js',
+    'label.js',
+    'shape.js',
+    'sound.js',
+    'text.js'
+  ]);
+}
+function defineSymbol(swfTag, symbols) {
+  var symbol;
+  switch (swfTag.code) {
+  case SWF_TAG_CODE_DEFINE_BITS:
+  case SWF_TAG_CODE_DEFINE_BITS_JPEG2:
+  case SWF_TAG_CODE_DEFINE_BITS_JPEG3:
+  case SWF_TAG_CODE_DEFINE_BITS_JPEG4:
+  case SWF_TAG_CODE_JPEG_TABLES:
+    symbol = defineImage(swfTag, symbols);
+    break;
+  case SWF_TAG_CODE_DEFINE_BITS_LOSSLESS:
+  case SWF_TAG_CODE_DEFINE_BITS_LOSSLESS2:
+    symbol = defineBitmap(swfTag);
+    break;
+  case SWF_TAG_CODE_DEFINE_BUTTON:
+  case SWF_TAG_CODE_DEFINE_BUTTON2:
+    symbol = defineButton(swfTag, symbols);
+    break;
+  case SWF_TAG_CODE_DEFINE_EDIT_TEXT:
+    symbol = defineText(swfTag, symbols);
+    break;
+  case SWF_TAG_CODE_DEFINE_FONT:
+  case SWF_TAG_CODE_DEFINE_FONT2:
+  case SWF_TAG_CODE_DEFINE_FONT3:
+  case SWF_TAG_CODE_DEFINE_FONT4:
+    symbol = defineFont(swfTag, symbols);
+    break;
+  case SWF_TAG_CODE_DEFINE_MORPH_SHAPE:
+  case SWF_TAG_CODE_DEFINE_MORPH_SHAPE2:
+  case SWF_TAG_CODE_DEFINE_SHAPE:
+  case SWF_TAG_CODE_DEFINE_SHAPE2:
+  case SWF_TAG_CODE_DEFINE_SHAPE3:
+  case SWF_TAG_CODE_DEFINE_SHAPE4:
+    symbol = defineShape(swfTag, symbols);
+    break;
+  case SWF_TAG_CODE_DEFINE_SOUND:
+    symbol = defineSound(swfTag, symbols);
+    break;
+  case SWF_TAG_CODE_DEFINE_BINARY_DATA:
+    symbol = {
+      type: 'binary',
+      id: swfTag.id,
+      data: swfTag.data
+    };
+    break;
+  case SWF_TAG_CODE_DEFINE_SPRITE:
+    var depths = {};
+    var frame = {
+        type: 'frame'
+      };
+    var frames = [];
+    var tags = swfTag.tags;
+    var frameScripts = null;
+    var frameIndex = 0;
+    var soundStream = null;
+    for (var i = 0, n = tags.length; i < n; i++) {
+      var tag = tags[i];
+      switch (tag.code) {
+      case SWF_TAG_CODE_DO_ACTION:
+        if (!frameScripts)
+          frameScripts = [];
+        frameScripts.push(frameIndex);
+        frameScripts.push(tag.actionsData);
+        break;
+      case SWF_TAG_CODE_START_SOUND:
+        var startSounds = frame.startSounds || (frame.startSounds = []);
+        startSounds.push(tag);
+        break;
+      case SWF_TAG_CODE_SOUND_STREAM_HEAD:
+        try {
+          soundStream = createSoundStream(tag);
+          frame.soundStream = soundStream.info;
+        } catch (e) {
+        }
+        break;
+      case SWF_TAG_CODE_SOUND_STREAM_BLOCK:
+        if (soundStream) {
+          frame.soundStreamBlock = soundStream.decode(tag.data);
+        }
+        break;
+      case SWF_TAG_CODE_FRAME_LABEL:
+        frame.labelName = tag.name;
+        break;
+      case SWF_TAG_CODE_PLACE_OBJECT:
+      case SWF_TAG_CODE_PLACE_OBJECT2:
+      case SWF_TAG_CODE_PLACE_OBJECT3:
+        depths[tag.depth] = tag;
+        break;
+      case SWF_TAG_CODE_REMOVE_OBJECT:
+      case SWF_TAG_CODE_REMOVE_OBJECT2:
+        depths[tag.depth] = null;
+        break;
+      case SWF_TAG_CODE_SHOW_FRAME:
+        frameIndex += tag.repeat;
+        frame.repeat = tag.repeat;
+        frame.depths = depths;
+        frames.push(frame);
+        depths = {};
+        frame = {
+          type: 'frame'
+        };
+        break;
+      }
+    }
+    symbol = {
+      type: 'sprite',
+      id: swfTag.id,
+      frameCount: swfTag.frameCount,
+      frames: frames,
+      frameScripts: frameScripts
+    };
+    break;
+  case SWF_TAG_CODE_DEFINE_TEXT:
+  case SWF_TAG_CODE_DEFINE_TEXT2:
+    symbol = defineLabel(swfTag, symbols);
+    break;
+  }
+  if (!symbol) {
+    return {
+      command: 'error',
+      message: 'unknown symbol type: ' + swfTag.code
+    };
+  }
+  symbol.isSymbol = true;
+  symbols[swfTag.id] = symbol;
+  return symbol;
+}
+function createParsingContext(commitData) {
+  var depths = {};
+  var symbols = {};
+  var frame = {
+      type: 'frame'
+    };
+  var tagsProcessed = 0;
+  var soundStream = null;
+  var lastProgressSent = 0;
+  return {
+    onstart: function (result) {
+      commitData({
+        command: 'init',
+        result: result
+      });
+    },
+    onprogress: function (result) {
+      if (Date.now() - lastProgressSent > 1000 / 24 || result.bytesLoaded === result.bytesTotal) {
+        commitData({
+          command: 'progress',
+          result: {
+            bytesLoaded: result.bytesLoaded,
+            bytesTotal: result.bytesTotal
+          }
+        });
+        lastProgressSent = Date.now();
+      }
+      var tags = result.tags;
+      for (var n = tags.length; tagsProcessed < n; tagsProcessed++) {
+        var tag = tags[tagsProcessed];
+        if ('id' in tag) {
+          var symbol = defineSymbol(tag, symbols);
+          commitData(symbol, symbol.transferables);
+          continue;
+        }
+        switch (tag.code) {
+        case SWF_TAG_CODE_DEFINE_SCENE_AND_FRAME_LABEL_DATA:
+          frame.sceneData = tag;
+          break;
+        case SWF_TAG_CODE_DEFINE_SCALING_GRID:
+          var symbolUpdate = {
+              isSymbol: true,
+              id: tag.symbolId,
+              updates: {
+                scale9Grid: tag.splitter
+              }
+            };
+          commitData(symbolUpdate);
+          break;
+        case SWF_TAG_CODE_DO_ABC:
+        case SWF_TAG_CODE_DO_ABC_:
+          var abcBlocks = frame.abcBlocks;
+          if (abcBlocks)
+            abcBlocks.push({
+              data: tag.data,
+              flags: tag.flags
+            });
+          else
+            frame.abcBlocks = [
+              {
+                data: tag.data,
+                flags: tag.flags
+              }
+            ];
+          break;
+        case SWF_TAG_CODE_DO_ACTION:
+          var actionBlocks = frame.actionBlocks;
+          if (actionBlocks)
+            actionBlocks.push(tag.actionsData);
+          else
+            frame.actionBlocks = [
+              tag.actionsData
+            ];
+          break;
+        case SWF_TAG_CODE_DO_INIT_ACTION:
+          var initActionBlocks = frame.initActionBlocks || (frame.initActionBlocks = []);
+          initActionBlocks.push({
+            spriteId: tag.spriteId,
+            actionsData: tag.actionsData
+          });
+          break;
+        case SWF_TAG_CODE_START_SOUND:
+          var startSounds = frame.startSounds;
+          if (!startSounds)
+            frame.startSounds = startSounds = [];
+          startSounds.push(tag);
+          break;
+        case SWF_TAG_CODE_SOUND_STREAM_HEAD:
+          try {
+            soundStream = createSoundStream(tag);
+            frame.soundStream = soundStream.info;
+          } catch (e) {
+          }
+          break;
+        case SWF_TAG_CODE_SOUND_STREAM_BLOCK:
+          if (soundStream) {
+            frame.soundStreamBlock = soundStream.decode(tag.data);
+          }
+          break;
+        case SWF_TAG_CODE_EXPORT_ASSETS:
+          var exports = frame.exports;
+          if (exports)
+            frame.exports = exports.concat(tag.exports);
+          else
+            frame.exports = tag.exports.slice(0);
+          break;
+        case SWF_TAG_CODE_SYMBOL_CLASS:
+          var symbolClasses = frame.symbolClasses;
+          if (symbolClasses)
+            frame.symbolClasses = symbolClasses.concat(tag.exports);
+          else
+            frame.symbolClasses = tag.exports.slice(0);
+          break;
+        case SWF_TAG_CODE_FRAME_LABEL:
+          frame.labelName = tag.name;
+          break;
+        case SWF_TAG_CODE_PLACE_OBJECT:
+        case SWF_TAG_CODE_PLACE_OBJECT2:
+        case SWF_TAG_CODE_PLACE_OBJECT3:
+          depths[tag.depth] = tag;
+          break;
+        case SWF_TAG_CODE_REMOVE_OBJECT:
+        case SWF_TAG_CODE_REMOVE_OBJECT2:
+          depths[tag.depth] = null;
+          break;
+        case SWF_TAG_CODE_SET_BACKGROUND_COLOR:
+          frame.bgcolor = tag.color;
+          break;
+        case SWF_TAG_CODE_SHOW_FRAME:
+          frame.repeat = tag.repeat;
+          frame.depths = depths;
+          frame.complete = !(!tag.finalTag);
+          commitData(frame);
+          depths = {};
+          frame = {
+            type: 'frame'
+          };
+          break;
+        }
+      }
+    },
+    oncomplete: function (result) {
+      commitData(result);
+      var stats;
+      if (typeof result.swfVersion === 'number') {
+        var bbox = result.bbox;
+        stats = {
+          topic: 'parseInfo',
+          parseTime: result.parseTime,
+          bytesTotal: result.bytesTotal,
+          swfVersion: result.swfVersion,
+          frameRate: result.frameRate,
+          width: (bbox.xMax - bbox.xMin) / 20,
+          height: (bbox.yMax - bbox.yMin) / 20,
+          isAvm2: !(!result.fileAttributes.doAbc)
+        };
+      }
+      commitData({
+        command: 'complete',
+        stats: stats
+      });
+    }
+  };
+}
+function parseBytes(bytes, commitData) {
+  SWF.parse(bytes, createParsingContext(commitData));
+}
+function ResourceLoader(scope) {
+  this.subscription = null;
+  var self = this;
+  if (!isWorker) {
+    this.messenger = {
+      postMessage: function (data) {
+        self.onmessage({
+          data: data
+        });
+      }
+    };
+  } else {
+    this.messenger = scope;
+    scope.onmessage = function (event) {
+      self.listener(event.data);
+    };
+  }
+}
+ResourceLoader.prototype = {
+  terminate: function () {
+    this.messenger = null;
+    this.listener = null;
+  },
+  onmessage: function (event) {
+    this.listener(event.data);
+  },
+  postMessage: function (data) {
+    this.listener && this.listener(data);
+  },
+  listener: function (data) {
+    if (this.subscription) {
+      this.subscription.callback(data.data, data.progress);
+    } else if (data === 'pipe:') {
+      this.subscription = {
+        subscribe: function (callback) {
+          this.callback = callback;
+        }
+      };
+      this.parseLoadedData(this.messenger, this.subscription);
+    } else {
+      this.parseLoadedData(this.messenger, data);
+    }
+  },
+  parseLoadedData: function (loader, request, context) {
+    function commitData(data, transferables) {
+      try {
+        loader.postMessage(data, transferables);
+      } catch (ex) {
+        if (ex != 'DataCloneError') {
+          throw ex;
+        }
+        loader.postMessage(data);
+      }
+    }
+    if (request instanceof ArrayBuffer) {
+      parseBytes(request, commitData);
+    } else if ('subscribe' in request) {
+      var pipe = SWF.parseAsync(createParsingContext(commitData));
+      request.subscribe(function (data, progress) {
+        if (data) {
+          pipe.push(data, progress);
+        } else {
+          pipe.close();
+        }
+      });
+    } else if (typeof FileReaderSync !== 'undefined') {
+      var reader = new FileReaderSync();
+      var buffer = reader.readAsArrayBuffer(request);
+      parseBytes(buffer, commitData);
+    } else {
+      var reader = new FileReader();
+      reader.onload = function () {
+        parseBytes(this.result, commitData);
+      };
+      reader.readAsArrayBuffer(request);
+    }
+  }
+};
+if (isWorker) {
+  var loader = new ResourceLoader(this);
+}
 function ActionsDataStream(array, swfVersion) {
   this.array = array;
   this.position = 0;
   this.end = array.length;
   if (swfVersion >= 6) {
     this.readString = this.readUTF8String;
   } else {
     this.readString = this.readANSIString;
@@ -6157,22 +7124,18 @@ function AS2Context(swfVersion) {
   this.stackDepth = 0;
   this.isTryCatchListening = false;
   this.errorsIgnored = 0;
   this.deferScriptExecution = true;
   this.pendingScripts = [];
 }
 AS2Context.instance = null;
 AS2Context.prototype = {
-  addAssets: function (assets) {
-    for (var i = 0; i < assets.length; i++) {
-      if (assets[i].className) {
-        this.assets[assets[i].className] = assets[i];
-      }
-    }
+  addAsset: function (className, symbolProps) {
+    this.assets[className] = symbolProps;
   },
   resolveTarget: function (target) {
     if (!target) {
       target = this.defaultTarget;
     } else if (typeof target === 'string') {
       target = lookupAS2Children(target, this.defaultTarget, this.globals.asGetPublicProperty('_root'));
     }
     if (typeof target !== 'object' || target === null || !('$nativeObject' in target)) {
@@ -6252,29 +7215,27 @@ function as2ToBoolean(value) {
   }
 }
 function as2ToNumber(value) {
   value = as2ToPrimitive(value);
   switch (as2GetType(value)) {
   case 'undefined':
   case 'null':
     return AS2Context.instance.swfVersion >= 7 ? NaN : 0;
-  default:
-    return AS2Context.instance.swfVersion >= 5 ? NaN : 0;
-  case 'null':
-    return NaN;
   case 'boolean':
     return value ? 1 : +0;
   case 'number':
     return value;
   case 'string':
     if (value === '' && AS2Context.instance.swfVersion < 5) {
       return 0;
     }
     return +value;
+  default:
+    return AS2Context.instance.swfVersion >= 5 ? NaN : 0;
   }
 }
 function as2ToInteger(value) {
   var result = as2ToNumber(value);
   if (isNaN(result)) {
     return 0;
   }
   if (!isFinite(result) || result === 0) {
@@ -6293,18 +7254,16 @@ function as2ToString(value) {
   case 'null':
     return 'null';
   case 'boolean':
     return value ? 'true' : 'false';
   case 'number':
     return value.toString();
   case 'string':
     return value;
-  case 'undefined':
-    return 'undefined';
   case 'movieclip':
     return value.$targetPath;
   case 'object':
     var result = value.toString !== Function.prototype.toString ? value.toString() : value;
     if (typeof result === 'string') {
       return result;
     }
     return typeof value === 'function' ? '[type Function]' : '[type Object]';
@@ -6391,27 +7350,24 @@ function as2CreatePrototypeProxy(obj) {
     delete: function (name) {
       return delete prototype[name];
     },
     fix: function () {
       return undefined;
     }
   });
 }
-function executeActions(actionsData, context, scope, assets) {
+function executeActions(actionsData, context, scope) {
   var actionTracer = ActionTracerFactory.get();
   var scopeContainer = context.initialScope.create(scope);
   var savedContext = AS2Context.instance;
   try {
     AS2Context.instance = context;
     context.defaultTarget = scope;
     context.globals.asSetPublicProperty('this', scope);
-    if (assets) {
-      context.addAssets(assets);
-    }
     actionTracer.message('ActionScript Execution Starts');
     actionTracer.indent();
     interpretActions(actionsData, scopeContainer, null, []);
   } finally {
     context.instructionsExecuted = 0;
     context.errorsIgnored = 0;
     actionTracer.unindent();
     actionTracer.message('ActionScript Execution Stops');
@@ -7640,79 +8596,66 @@ var ActionNamesMap = {
     158: 'ActionCall',
     159: 'ActionGotoFrame2'
   };
 if (typeof GLOBAL !== 'undefined') {
   GLOBAL.createBuiltinType = createBuiltinType;
   GLOBAL.executeActions = executeActions;
   GLOBAL.AS2Context = AS2Context;
 }
-var debug = true;
 var $DEBUG;
-var release = false;
-var compatibility = true;
+var release = true;
+var checkArguments = true;
 var useSurrogates = true;
 var useAsAdd = true;
 var sealConstTraits = false;
 var c4CoerceNonPrimitiveParameters = false;
 var c4CoerceNonPrimitive = false;
 var c4AsTypeLate = true;
 var inBrowser = typeof console != 'undefined';
-if (!inBrowser) {
-  console = {
-    info: print,
-    warn: function (x) {
-      if (traceWarnings.value) {
-        print(x);
-      }
-    }
-  };
-}
 if (!this.performance) {
   this.performance = {};
 }
 if (!this.performance.now) {
-  this.performance.now = Date.now;
+  this.performance.now = dateNow;
 }
 function backtrace() {
   try {
     throw new Error();
   } catch (e) {
     return e.stack ? e.stack.split('\n').slice(2).join('\n') : '';
   }
 }
 function error(message) {
   if (!inBrowser) {
-    console.info(backtrace());
+    console.warn(backtrace());
   }
   throw new Error(message);
 }
 function assert(condition) {
   if (condition === '') {
     condition = true;
   }
   if (!condition) {
     var message = Array.prototype.slice.call(arguments);
     message.shift();
     error(message.join(''));
   }
 }
-function assertFalse(condition, message) {
-  if (condition) {
-    error(message);
-  }
-}
 function assertNotImplemented(condition, message) {
   if (!condition) {
     error('NotImplemented: ' + message);
   }
 }
 function warning(message) {
   true;
 }
+function notUsed(message) {
+  true;
+}
 function notImplemented(message) {
   true;
 }
 function somewhatImplemented(message) {
   warning('somewhatImplemented: ' + message);
 }
 function unexpected(message) {
 }
@@ -7891,33 +8834,36 @@ function toKeyValueArray(o) {
     }
   }
   return a;
 }
 function isNumeric(x) {
   if (typeof x === 'number') {
     return x === (x | 0);
   }
-  if (typeof x === 'string' && x.length) {
-    if (x === '0') {
-      return true;
-    }
-    if (x[0] >= '1' && x[0] <= '9') {
-      for (var i = 1; i < x.length; i++) {
-        if (!(x[i] >= '1' && x[i] <= '9')) {
-          return false;
-        }
-      }
-      return true;
-    }
+  if (typeof x !== 'string' || x.length === 0) {
+    return false;
+  }
+  if (x === '0') {
+    return true;
+  }
+  var c = x.charCodeAt(0);
+  if (c >= 49 && c <= 57) {
+    for (var i = 1, j = x.length; i < j; i++) {
+      c = x.charCodeAt(i);
+      if (!(c >= 48 && c <= 57)) {
+        return false;
+      }
+    }
+    return true;
   }
   return false;
 }
 function boxValue(value) {
-  if (isNullOrUndefined(value)) {
+  if (isNullOrUndefined(value) || isObject(value)) {
     return value;
   }
   return Object(value);
 }
 function isObject(value) {
   return typeof value === 'object' || typeof value === 'function';
 }
 function isString(value) {
@@ -8173,16 +9119,19 @@ function getFlags(value, flags) {
 function bitCount(i) {
   i = i - (i >> 1 & 1431655765);
   i = (i & 858993459) + (i >> 2 & 858993459);
   return (i + (i >> 4) & 252645135) * 16843009 >> 24;
 }
 function escapeString(str) {
   if (str !== undefined) {
     str = str.replace(/[^\w$]/gi, '$');
+    if (/^\d/.test(str)) {
+      str = '$' + str;
+    }
   }
   return str;
 }
 function BitSetFunctor(length) {
   var ADDRESS_BITS_PER_WORD = 5;
   var BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD;
   var BIT_INDEX_MASK = BITS_PER_WORD - 1;
   var SIZE = length + (BITS_PER_WORD - 1) >> ADDRESS_BITS_PER_WORD << ADDRESS_BITS_PER_WORD;
@@ -8842,33 +9791,16 @@ var Callback = function () {
           Counter.count('callback(' + type + ').notify1');
         }
         var callback = queue[i];
         callback(type, value);
       }
     };
     return callback;
   }();
-function dumpBytes(buffer, start, length) {
-  var s = '';
-  bytes = new Uint8Array(buffer, start, length);
-  var end = length;
-  for (var i = 0; i < end; i++) {
-    if (i % 16 === 0) {
-      s += '\n' + (start + i) + ': ';
-    }
-    s += bytes[i] + ' ';
-  }
-  return s;
-}
-function addProfileMarker(marker) {
-  if (typeof FirefoxCom !== 'undefined') {
-    FirefoxCom.requestSync('addProfilerMarker', marker);
-  }
-}
 var CircularBuffer = function () {
     var mask = 4095, size = 4096;
     function circularBuffer(Type) {
       this.index = 0;
       this.start = 0;
       this.array = new Type(size);
     }
     circularBuffer.prototype.get = function (i) {
@@ -8896,22 +9828,35 @@ var CircularBuffer = function () {
     circularBuffer.prototype.isFull = function () {
       return this.index + 1 & mask === this.start;
     };
     circularBuffer.prototype.isEmpty = function () {
       return this.index === this.start;
     };
     return circularBuffer;
   }();
+function lazyClass(holder, name, initialize) {
+  Object.defineProperty(holder, name, {
+    get: function () {
+      var start = performance.now();
+      var value = initialize();
+      print('Initialized Class: ' + name + ' ' + (performance.now() - start).toFixed(4));
+      Object.defineProperty(holder, name, {
+        value: value,
+        writable: true
+      });
+      return value;
+    },
+    configurable: true
+  });
+}
+function createNewCompartment() {
+  return newGlobal('new-compartment');
+}
 (function (exports) {
-  if (!performance) {
-    performance = {
-      now: Date.now
-    };
-  }
   var Timer = function () {
       var base = new timer(null, 'Total'), top = base;
       var flat = new timer(null, 'Flat'), flatStack = [];
       function timer(parent, name) {
         this.parent = parent;
         this.timers = {};
         this.name = name;
         this.begin = 0;
@@ -8960,17 +9905,17 @@ var CircularBuffer = function () {
       };
       timer.prototype.trace = function (writer, json) {
         if (json) {
           writer.writeLn('SHUMWAY$JSON ' + JSON.stringify({
             timer: this
           }));
           return;
         }
-        writer.enter(this.name + ': ' + this.total + ' ms' + ', count: ' + this.count + ', average: ' + (this.total / this.count).toFixed(2) + ' ms');
+        writer.enter(this.name + ': ' + this.total.toFixed(2) + ' ms' + ', count: ' + this.count + ', average: ' + (this.total / this.count).toFixed(2) + ' ms');
         for (var name in this.timers) {
           this.timers[name].trace(writer);
         }
         writer.outdent();
       };
       timer.trace = function (writer, json) {
         base.trace(writer, json);
         flat.trace(writer, json);
@@ -9309,2387 +10254,79 @@ var INT_MAX_VALUE = 2147483647;
 var UINT_MIN_VALUE = 0;
 var UINT_MAX_VALUE = 4294967295;
 var SORT_CASEINSENSITIVE = 1;
 var SORT_DESCENDING = 2;
 var SORT_UNIQUESORT = 4;
 var SORT_RETURNINDEXEDARRAY = 8;
 var SORT_NUMERIC = 16;
 var Errors = {
-    OutOfMemoryError: {
-      code: 1000,
-      message: 'The system is out of memory.'
-    },
-    NotImplementedError: {
-      code: 1001,
-      message: 'The method %1 is not implemented.'
-    },
-    InvalidPrecisionError: {
-      code: 1002,
-      message: 'Number.toPrecision has a range of 1 to 21. Number.toFixed and Number.toExponential have a range of 0 to 20. Specified value is not within expected range.'
-    },
-    InvalidRadixError: {
-      code: 1003,
-      message: 'The radix argument must be between 2 and 36; got %1.'
-    },
-    InvokeOnIncompatibleObjectError: {
-      code: 1004,
-      message: 'Method %1 was invoked on an incompatible object.'
-    },
-    ArrayIndexNotIntegerError: {
-      code: 1005,
-      message: 'Array index is not a positive integer (%1).'
-    },
     CallOfNonFunctionError: {
       code: 1006,
       message: '%1 is not a function.'
     },
-    ConstructOfNonFunctionError: {
-      code: 1007,
-      message: 'Instantiation attempted on a non-constructor.'
-    },
-    AmbiguousBindingError: {
-      code: 1008,
-      message: '%1 is ambiguous; Found more than one matching binding.'
-    },
     ConvertNullToObjectError: {
       code: 1009,
       message: 'Cannot access a property or method of a null object reference.'
     },
     ConvertUndefinedToObjectError: {
       code: 1010,
       message: 'A term is undefined and has no properties.'
     },
-    IllegalOpcodeError: {
-      code: 1011,
-      message: 'Method %1 contained illegal opcode %2 at offset %3.'
-    },
-    LastInstExceedsCodeSizeError: {
-      code: 1012,
-      message: 'The last instruction exceeded code size.'
-    },
-    FindVarWithNoScopeError: {
-      code: 1013,
-      message: 'Cannot call OP_findproperty when scopeDepth is 0.'
-    },
     ClassNotFoundError: {
       code: 1014,
       message: 'Class %1 could not be found.'
     },
-    IllegalSetDxns: {
-      code: 1015,
-      message: 'Method %1 cannot set default xml namespace'
-    },
-    DescendentsError: {
-      code: 1016,
-      message: 'Descendants operator (..) not supported on type %1.'
-    },
-    ScopeStackOverflowError: {
-      code: 1017,
-      message: 'Scope stack overflow occurred.'
-    },
-    ScopeStackUnderflowError: {
-      code: 1018,
-      message: 'Scope stack underflow occurred.'
-    },
-    GetScopeObjectBoundsError: {
-      code: 1019,
-      message: 'Getscopeobject %1 is out of bounds.'
-    },
-    CannotFallOffMethodError: {
-      code: 1020,
-      message: 'Code cannot fall off the end of a method.'
-    },
-    InvalidBranchTargetError: {
-      code: 1021,
-      message: 'At least one branch target was not on a valid instruction in the method.'
-    },
-    IllegalVoidError: {
-      code: 1022,
-      message: 'Type void may only be used as a function return type.'
-    },
-    StackOverflowError: {
-      code: 1023,
-      message: 'Stack overflow occurred.'
-    },
-    StackUnderflowError: {
-      code: 1024,
-      message: 'Stack underflow occurred.'
-    },
-    InvalidRegisterError: {
-      code: 1025,
-      message: 'An invalid register %1 was accessed.'
-    },
-    SlotExceedsCountError: {
-      code: 1026,
-      message: 'Slot %1 exceeds slotCount=%2 of %3.'
-    },
-    MethodInfoExceedsCountError: {
-      code: 1027,
-      message: 'Method_info %1 exceeds method_count=%2.'
-    },
-    DispIdExceedsCountError: {
-      code: 1028,
-      message: 'Disp_id %1 exceeds max_disp_id=%2 of %3.'
-    },
-    DispIdUndefinedError: {
-      code: 1029,
-      message: 'Disp_id %1 is undefined on %2.'
-    },
-    StackDepthUnbalancedError: {
-      code: 1030,
-      message: 'Stack depth is unbalanced. %1 != %2.'
-    },
-    ScopeDepthUnbalancedError: {
-      code: 1031,
-      message: 'Scope depth is unbalanced. %1 != %2.'
-    },
-    CpoolIndexRangeError: {
-      code: 1032,
-      message: 'Cpool index %1 is out of range %2.'
-    },
-    CpoolEntryWrongTypeError: {
-      code: 1033,
-      message: 'Cpool entry %1 is wrong type.'
-    },
     CheckTypeFailedError: {
       code: 1034,
       message: 'Type Coercion failed: cannot convert %1 to %2.'
     },
-    IllegalSuperCallError: {
-      code: 1035,
-      message: 'Illegal super expression found in method %1.'
-    },
-    CannotAssignToMethodError: {
-      code: 1037,
-      message: 'Cannot assign to a method %1 on %2.'
-    },
-    RedefinedError: {
-      code: 1038,
-      message: '%1 is already defined.'
-    },
-    CannotVerifyUntilReferencedError: {
-      code: 1039,
-      message: 'Cannot verify method until it is referenced.'
-    },
-    CantUseInstanceofOnNonObjectError: {
-      code: 1040,
-      message: 'The right-hand side of instanceof must be a class or function.'
-    },
-    IsTypeMustBeClassError: {
-      code: 1041,
-      message: 'The right-hand side of operator must be a class.'
-    },
-    InvalidMagicError: {
-      code: 1042,
-      message: 'Not an ABC file.  major_version=%1 minor_version=%2.'
-    },
-    InvalidCodeLengthError: {
-      code: 1043,
-      message: 'Invalid code_length=%1.'
-    },
-    InvalidMethodInfoFlagsError: {
-      code: 1044,
-      message: 'MethodInfo-%1 unsupported flags=%2.'
-    },
-    UnsupportedTraitsKindError: {
-      code: 1045,
-      message: 'Unsupported traits kind=%1.'
-    },
-    MethodInfoOrderError: {
-      code: 1046,
-      message: 'MethodInfo-%1 referenced before definition.'
-    },
-    MissingEntryPointError: {
-      code: 1047,
-      message: 'No entry point was found.'
-    },
-    PrototypeTypeError: {
-      code: 1049,
-      message: 'Prototype objects must be vanilla Objects.'
-    },
-    ConvertToPrimitiveError: {
-      code: 1050,
-      message: 'Cannot convert %1 to primitive.'
-    },
-    IllegalEarlyBindingError: {
-      code: 1051,
-      message: 'Illegal early binding access to %1.'
-    },
-    InvalidURIError: {
-      code: 1052,
-      message: 'Invalid URI passed to %1 function.'
-    },
-    IllegalOverrideError: {
-      code: 1053,
-      message: 'Illegal override of %1 in %2.'
-    },
-    IllegalExceptionHandlerError: {
-      code: 1054,
-      message: 'Illegal range or target offsets in exception handler.'
-    },
-    WriteSealedError: {
-      code: 1056,
-      message: 'Cannot create property %1 on %2.'
-    },
-    IllegalSlotError: {
-      code: 1057,
-      message: '%1 can only contain methods.'
-    },
-    IllegalOperandTypeError: {
-      code: 1058,
-      message: 'Illegal operand type: %1 must be %2.'
-    },
-    ClassInfoOrderError: {
-      code: 1059,
-      message: 'ClassInfo-%1 is referenced before definition.'
-    },
-    ClassInfoExceedsCountError: {
-      code: 1060,
-      message: 'ClassInfo %1 exceeds class_count=%2.'
-    },
-    NumberOutOfRangeError: {
-      code: 1061,
-      message: 'The value %1 cannot be converted to %2 without losing precision.'
-    },
     WrongArgumentCountError: {
       code: 1063,
       message: 'Argument count mismatch on %1. Expected %2, got %3.'
     },
-    CannotCallMethodAsConstructor: {
-      code: 1064,
-      message: 'Cannot call method %1 as constructor.'
-    },
-    UndefinedVarError: {
-      code: 1065,
-      message: 'Variable %1 is not defined.'
-    },
-    FunctionConstructorError: {
-      code: 1066,
-      message: 'The form function(\'function body\') is not supported.'
-    },
-    IllegalNativeMethodBodyError: {
-      code: 1067,
-      message: 'Native method %1 has illegal method body.'
-    },
-    CannotMergeTypesError: {
-      code: 1068,
-      message: '%1 and %2 cannot be reconciled.'
-    },
-    ReadSealedError: {
-      code: 1069,
-      message: 'Property %1 not found on %2 and there is no default value.'
-    },
-    CallNotFoundError: {
-      code: 1070,
-      message: 'Method %1 not found on %2'
-    },
-    AlreadyBoundError: {
-      code: 1071,
-      message: 'Function %1 has already been bound to %2.'
-    },
-    ZeroDispIdError: {
-      code: 1072,
-      message: 'Disp_id 0 is illegal.'
-    },
-    DuplicateDispIdError: {
-      code: 1073,
-      message: 'Non-override method %1 replaced because of duplicate disp_id %2.'
-    },
-    ConstWriteError: {
-      code: 1074,
-      message: 'Illegal write to read-only property %1 on %2.'
-    },
-    MathNotFunctionError: {
-      code: 1075,
-      message: 'Math is not a function.'
-    },
-    MathNotConstructorError: {
-      code: 1076,
-      message: 'Math is not a constructor.'
-    },
-    WriteOnlyError: {
-      code: 1077,
-      message: 'Illegal read of write-only property %1 on %2.'
-    },
-    IllegalOpMultinameError: {
-      code: 1078,
-      message: 'Illegal opcode/multiname combination: %1<%2>.'
-    },
-    IllegalNativeMethodError: {
-      code: 1079,
-      message: 'Native methods are not allowed in loaded code.'
-    },
-    IllegalNamespaceError: {
-      code: 1080,
-      message: 'Illegal value for namespace.'
-    },
-    ReadSealedErrorNs: {
-      code: 1081,
-      message: 'Property %1 not found on %2 and there is no default value.'
-    },
-    NoDefaultNamespaceError: {
-      code: 1082,
-      message: 'No default namespace has been set.'
-    },
-    XMLPrefixNotBound: {
-      code: 1083,
-      message: 'The prefix "%1" for element "%2" is not bound.'
-    },
-    XMLBadQName: {
-      code: 1084,
-      message: 'Element or attribute ("%1") does not match QName production: QName::=(NCName\':\')?NCName.'
-    },
-    XMLUnterminatedElementTag: {
-      code: 1085,
-      message: 'The element type "%1" must be terminated by the matching end-tag "</%2>".'
-    },
-    XMLOnlyWorksWithOneItemLists: {
-      code: 1086,
-      message: 'The %1 method only works on lists containing one item.'
-    },
-    XMLAssignmentToIndexedXMLNotAllowed: {
-      code: 1087,
-      message: 'Assignment to indexed XML is not allowed.'
-    },
     XMLMarkupMustBeWellFormed: {
       code: 1088,
       message: 'The markup in the document following the root element must be well-formed.'
     },
-    XMLAssigmentOneItemLists: {
-      code: 1089,
-      message: 'Assignment to lists with more than one item is not supported.'
-    },
-    XMLMalformedElement: {
-      code: 1090,
-      message: 'XML parser failure: element is malformed.'
-    },
-    XMLUnterminatedCData: {
-      code: 1091,
-      message: 'XML parser failure: Unterminated CDATA section.'
-    },
-    XMLUnterminatedXMLDecl: {
-      code: 1092,
-      message: 'XML parser failure: Unterminated XML declaration.'
-    },
-    XMLUnterminatedDocTypeDecl: {
-      code: 1093,
-      message: 'XML parser failure: Unterminated DOCTYPE declaration.'
-    },
-    XMLUnterminatedComment: {
-      code: 1094,
-      message: 'XML parser failure: Unterminated comment.'
-    },
-    XMLUnterminatedAttribute: {
-      code: 1095,
-      message: 'XML parser failure: Unterminated attribute.'
-    },
-    XMLUnterminatedElement: {
-      code: 1096,
-      message: 'XML parser failure: Unterminated element.'
-    },
-    XMLUnterminatedProcessingInstruction: {
-      code: 1097,
-      message: 'XML parser failure: Unterminated processing instruction.'
-    },
-    XMLNamespaceWithPrefixAndNoURI: {
-      code: 1098,
-      message: 'Illegal prefix %1 for no namespace.'
-    },
-    RegExpFlagsArgumentError: {
-      code: 1100,
-      message: 'Cannot supply flags when constructing one RegExp from another.'
-    },
-    NoScopeError: {
-      code: 1101,
-      message: 'Cannot verify method %1 with unknown scope.'
-    },
-    IllegalDefaultValue: {
-      code: 1102,
-      message: 'Illegal default value for type %1.'
-    },
-    CannotExtendFinalClass: {
-      code: 1103,
-      message: 'Class %1 cannot extend final base class.'
-    },
-    XMLDuplicateAttribute: {
-      code: 1104,
-      message: 'Attribute "%1" was already specified for element "%2".'
-    },
-    CorruptABCError: {
-      code: 1107,
-      message: 'The ABC data is corrupt, attempt to read out of bounds.'
-    },
-    InvalidBaseClassError: {
-      code: 1108,
-      message: 'The OP_newclass opcode was used with the incorrect base class.'
-    },
-    DanglingFunctionError: {
-      code: 1109,
-      message: 'Attempt to directly call unbound function %1 from method %2.'
-    },
-    CannotExtendError: {
-      code: 1110,
-      message: '%1 cannot extend %2.'
-    },
-    CannotImplementError: {
-      code: 1111,
-      message: '%1 cannot implement %2.'
-    },
-    CoerceArgumentCountError: {
-      code: 1112,
-      message: 'Argument count mismatch on class coercion.  Expected 1, got %1.'
-    },
-    InvalidNewActivationError: {
-      code: 1113,
-      message: 'OP_newactivation used in method without NEED_ACTIVATION flag.'
-    },
-    NoGlobalScopeError: {
-      code: 1114,
-      message: 'OP_getglobalslot or OP_setglobalslot used with no global scope.'
-    },
-    NotConstructorError: {
-      code: 1115,
-      message: '%1 is not a constructor.'
-    },
-    ApplyError: {
-      code: 1116,
-      message: 'second argument to Function.prototype.apply must be an array.'
-    },
-    XMLInvalidName: {
-      code: 1117,
-      message: 'Invalid XML name: %1.'
-    },
-    XMLIllegalCyclicalLoop: {
-      code: 1118,
-      message: 'Illegal cyclical loop between nodes.'
-    },
-    DeleteTypeError: {
-      code: 1119,
-      message: 'Delete operator is not supported with operand of type %1.'
-    },
-    DeleteSealedError: {
-      code: 1120,
-      message: 'Cannot delete property %1 on %2.'
-    },
-    DuplicateMethodBodyError: {
-      code: 1121,
-      message: 'Method %1 has a duplicate method body.'
-    },
-    IllegalInterfaceMethodBodyError: {
-      code: 1122,
-      message: 'Interface method %1 has illegal method body.'
-    },
-    FilterError: {
-      code: 1123,
-      message: 'Filter operator not supported on type %1.'
-    },
-    InvalidHasNextError: {
-      code: 1124,
-      message: 'OP_hasnext2 requires object and index to be distinct registers.'
-    },
     OutOfRangeError: {
       code: 1125,
       message: 'The index %1 is out of range %2.'
     },
     VectorFixedError: {
       code: 1126,
       message: 'Cannot change the length of a fixed Vector.'
     },
-    TypeAppOfNonParamType: {
-      code: 1127,
-      message: 'Type application attempted on a non-parameterized type.'
-    },
-    WrongTypeArgCountError: {
-      code: 1128,
-      message: 'Incorrect number of type parameters for %1. Expected %2, got %3.'
-    },
-    JSONCyclicStructure: {
-      code: 1129,
-      message: 'Cyclic structure cannot be converted to JSON string.'
-    },
-    JSONInvalidReplacer: {
-      code: 1131,
-      message: 'Replacer argument to JSON stringifier must be an array or a two parameter function.'
-    },
-    JSONInvalidParseInput: {
-      code: 1132,
-      message: 'Invalid JSON parse input.'
-    },
-    FileOpenError: {
-      code: 1500,
-      message: 'Error occurred opening file %1.'
-    },
-    FileWriteError: {
-      code: 1501,
-      message: 'Error occurred writing to file %1.'
-    },
-    ScriptTimeoutError: {
-      code: 1502,
-      message: 'A script has executed for longer than the default timeout period of 15 seconds.'
-    },
-    ScriptTerminatedError: {
-      code: 1503,
-      message: 'A script failed to exit after 30 seconds and was terminated.'
-    },
-    EndOfFileError: {
-      code: 1504,
-      message: 'End of file.'
-    },
-    StringIndexOutOfBoundsError: {
-      code: 1505,
-      message: 'The string index %1 is out of bounds; must be in range %2 to %3.'
-    },
-    InvalidRangeError: {
-      code: 1506,
-      message: 'The specified range is invalid.'
-    },
-    NullArgumentError: {
-      code: 1507,
-      message: 'Argument %1 cannot be null.'
-    },
-    InvalidArgumentError: {
-      code: 1508,
-      message: 'The value specified for argument %1 is invalid.'
-    },
-    ArrayFilterNonNullObjectError: {
-      code: 1510,
-      message: 'When the callback argument is a method of a class, the optional this argument must be null.'
-    },
     InvalidParamError: {
       code: 2004,
       message: 'One of the parameters is invalid.'
     },
     ParamRangeError: {
       code: 2006,
       message: 'The supplied index is out of bounds.'
     },
     NullPointerError: {
       code: 2007,
       message: 'Parameter %1 must be non-null.'
     },
     InvalidEnumError: {
       code: 2008,
       message: 'Parameter %1 must be one of the accepted values.'
     },
-    CantInstantiateError: {
-      code: 2012,
-      message: '%1 class cannot be instantiated.'
-    },
     ArgumentError: {
       code: 2015,
       message: 'Invalid BitmapData.'
     },
-    EOFError: {
-      code: 2030,
-      message: 'End of file was encountered.'
-    },
-    CompressedDataError: {
-      code: 2058,
-      message: 'There was an error decompressing the data.'
-    },
-    EmptyStringError: {
-      code: 2085,
-      message: 'Parameter %1 must be non-empty string.'
-    },
-    ProxyGetPropertyError: {
-      code: 2088,
-      message: 'The Proxy class does not implement getProperty. It must be overridden by a subclass.'
-    },
-    ProxySetPropertyError: {
-      code: 2089,
-      message: 'The Proxy class does not implement setProperty. It must be overridden by a subclass.'
-    },
-    ProxyCallPropertyError: {
-      code: 2090,
-      message: 'The Proxy class does not implement callProperty. It must be overridden by a subclass.'
-    },
-    ProxyHasPropertyError: {
-      code: 2091,
-      message: 'The Proxy class does not implement hasProperty. It must be overridden by a subclass.'
-    },
-    ProxyDeletePropertyError: {
-      code: 2092,
-      message: 'The Proxy class does not implement deleteProperty. It must be overridden by a subclass.'
-    },
-    ProxyGetDescendantsError: {
-      code: 2093,
-      message: 'The Proxy class does not implement getDescendants. It must be overridden by a subclass.'
-    },
-    ProxyNextNameIndexError: {
-      code: 2105,
-      message: 'The Proxy class does not implement nextNameIndex. It must be overridden by a subclass.'
-    },
-    ProxyNextNameError: {
-      code: 2106,
-      message: 'The Proxy class does not implement nextName. It must be overridden by a subclass.'
-    },
-    ProxyNextValueError: {
-      code: 2107,
-      message: 'The Proxy class does not implement nextValue. It must be overridden by a subclass.'
-    },
-    InvalidArrayLengthError: {
-      code: 2108,
-      message: 'The value %1 is not a valid Array length.'
-    },
-    ReadExternalNotImplementedError: {
-      code: 2173,
-      message: 'Unable to read object in stream.  The class %1 does not implement flash.utils.IExternalizable but is aliased to an externalizable class.'
-    },
-    NoSecurityContextError: {
-      code: 2000,
-      message: 'No active security context.'
-    },
-    TooFewArgumentsError: {
-      code: 2001,
-      message: 'Too few arguments were specified; got %1, %2 expected.'
-    },
-    InvalidSocketError: {
-      code: 2002,
-      message: 'Operation attempted on invalid socket.'
-    },
-    InvalidSocketPortError: {
-      code: 2003,
-      message: 'Invalid socket port number specified.'
-    },
-    ParamTypeError: {
-      code: 2005,
-      message: 'Parameter %1 is of the incorrect type. Should be type %2.'
-    },
-    HasStyleSheetError: {
-      code: 2009,
-      message: 'This method cannot be used on a text field with a style sheet.'
-    },
-    SocketLocalFileSecurityError: {
-      code: 2010,
-      message: 'Local-with-filesystem SWF files are not permitted to use sockets.'
-    },
-    SocketConnectError: {
-      code: 2011,
-      message: 'Socket connection failed to %1:%2.'
-    },
-    AuthoringOnlyFeatureError: {
-      code: 2013,
-      message: 'Feature can only be used in Flash Authoring.'
-    },
-    FeatureNotAvailableError: {
-      code: 2014,
-      message: 'Feature is not available at this time.'
-    },
-    InvalidBitmapDataError: {
-      code: 2015,
-      message: 'Invalid BitmapData.'
-    },
-    SystemExitSecurityError: {
-      code: 2017,
-      message: 'Only trusted local files may cause the Flash Player to exit.'
-    },
-    SystemExitUnsupportedError: {
-      code: 2018,
-      message: 'System.exit is only available in the standalone Flash Player.'
-    },
-    InvalidDepthError: {
-      code: 2019,
-      message: 'Depth specified is invalid.'
-    },
-    MovieClipSwapError: {
-      code: 2020,
-      message: 'MovieClips objects with different parents cannot be swapped.'
-    },
-    ObjectCreationError: {
-      code: 2021,
-      message: 'Object creation failed.'
-    },
-    NotDisplayObjectError: {
-      code: 2022,
-      message: 'Class %1 must inherit from DisplayObject to link to a symbol.'
-    },
-    NotSpriteError: {
-      code: 2023,
-      message: 'Class %1 must inherit from Sprite to link to the root.'
-    },
     CantAddSelfError: {
       code: 2024,
       message: 'An object cannot be added as a child of itself.'
     },
     NotAChildError: {
       code: 2025,
       message: 'The supplied DisplayObject must be a child of the caller.'
-    },
-    NavigateURLError: {
-      code: 2026,
-      message: 'An error occurred navigating to the URL %1.'
-    },
-    MustBeNonNegativeError: {
-      code: 2027,
-      message: 'Parameter %1 must be a non-negative number; got %2.'
-    },
-    LocalSecurityError: {
-      code: 2028,
-      message: 'Local-with-filesystem SWF file %1 cannot access Internet URL %2.'
-    },
-    InvalidStreamError: {
-      code: 2029,
-      message: 'This URLStream object does not have a stream opened.'
-    },
-    SocketError: {
-      code: 2031,
-      message: 'Socket Error.'
-    },
-    StreamError: {
-      code: 2032,
-      message: 'Stream Error.'
-    },
-    KeyGenerationError: {
-      code: 2033,
-      message: 'Key Generation Failed.'
-    },
-    InvalidKeyError: {
-      code: 2034,
-      message: 'An invalid digest was supplied.'
-    },
-    URLNotFoundError: {
-      code: 2035,
-      message: 'URL Not Found.'
-    },
-    LoadNeverCompletedError: {
-      code: 2036,
-      message: 'Load Never Completed.'
-    },
-    InvalidCallError: {
-      code: 2037,
-      message: 'Functions called in incorrect sequence, or earlier call was unsuccessful.'
-    },
-    FileIOError: {
-      code: 2038,
-      message: 'File I/O Error.'
-    },
-    RemoteURLError: {
-      code: 2039,
-      message: 'Invalid remote URL protocol. The remote URL protocol must be HTTP or HTTPS.'
-    },
-    BrowseInProgressError: {
-      code: 2041,
-      message: 'Only one file browsing session may be performed at a time.'
-    },
-    DigestNotSupportedError: {
-      code: 2042,
-      message: 'The digest property is not supported by this load operation.'
-    },
-    UnhandledError: {
-      code: 2044,
-      message: 'Unhandled %1:.'
-    },
-    FileVerificationError: {
-      code: 2046,
-      message: 'The loaded file did not have a valid signature.'
-    },
-    DisplayListSecurityError: {
-      code: 2047,
-      message: 'Security sandbox violation: %1: %2 cannot access %3.'
-    },
-    DownloadSecurityError: {
-      code: 2048,
-      message: 'Security sandbox violation: %1 cannot load data from %2.'
-    },
-    UploadSecurityError: {
-      code: 2049,
-      message: 'Security sandbox violation: %1 cannot upload data to %2.'
-    },
-    OutboundScriptingSecurityError: {
-      code: 2051,
-      message: 'Security sandbox violation: %1 cannot evaluate scripting URLs within %2 (allowScriptAccess is %3). Attempted URL was %4.'
-    },
-    AllowDomainArgumentError: {
-      code: 2052,
-      message: 'Only String arguments are permitted for allowDomain and allowInsecureDomain.'
-    },
-    IntervalSecurityError: {
-      code: 2053,
-      message: 'Security sandbox violation: %1 cannot clear an interval timer set by %2.'
-    },
-    ExactSettingsError: {
-      code: 2054,
-      message: 'The value of Security.exactSettings cannot be changed after it has been used.'
-    },
-    PrintJobStartError: {
-      code: 2055,
-      message: 'The print job could not be started.'
-    },
-    PrintJobSendError: {
-      code: 2056,
-      message: 'The print job could not be sent to the printer.'
-    },
-    PrintJobAddPageError: {
-      code: 2057,
-      message: 'The page could not be added to the print job.'
-    },
-    ExternalCallbackSecurityError: {
-      code: 2059,
-      message: 'Security sandbox violation: %1 cannot overwrite an ExternalInterface callback added by %2.'
-    },
-    ExternalInterfaceSecurityError: {
-      code: 2060,
-      message: 'Security sandbox violation: ExternalInterface caller %1 cannot access %2.'
-    },
-    ExternalInterfaceNoCallbackError: {
-      code: 2061,
-      message: 'No ExternalInterface callback %1 registered.'
-    },
-    NoCloneMethodError: {
-      code: 2062,
-      message: 'Children of Event must override clone() {return new MyEventClass (...);}.'
-    },
-    IMEError: {
-      code: 2063,
-      message: 'Error attempting to execute IME command.'
-    },
-    FocusNotSetError: {
-      code: 2065,
-      message: 'The focus cannot be set for this target.'
-    },
-    DelayRangeError: {
-      code: 2066,
-      message: 'The Timer delay specified is out of range.'
-    },
-    ExternalInterfaceNotAvailableError: {
-      code: 2067,
-      message: 'The ExternalInterface is not available in this container. ExternalInterface requires Internet Explorer ActiveX, Firefox, Mozilla 1.7.5 and greater, or other browsers that support NPRuntime.'
-    },
-    InvalidSoundError: {
-      code: 2068,
-      message: 'Invalid sound.'
-    },
-    InvalidLoaderMethodError: {
-      code: 2069,
-      message: 'The Loader class does not implement this method.'
-    },
-    StageOwnerSecurityError: {
-      code: 2070,
-      message: 'Security sandbox violation: caller %1 cannot access Stage owned by %2.'
-    },
-    InvalidStageMethodError: {
-      code: 2071,
-      message: 'The Stage class does not implement this property or method.'
-    },
-    ProductManagerDiskError: {
-      code: 2073,
-      message: 'There was a problem saving the application to disk.'
-    },
-    ProductManagerStageError: {
-      code: 2074,
-      message: 'The stage is too small to fit the download ui.'
-    },
-    ProductManagerVerifyError: {
-      code: 2075,
-      message: 'The downloaded file is invalid.'
-    },
-    FilterFailedError: {
-      code: 2077,
-      message: 'This filter operation cannot be performed with the specified input parameters.'
-    },
-    TimelineObjectNameSealedError: {
-      code: 2078,
-      message: 'The name property of a Timeline-placed object cannot be modified.'
-    },
-    BitmapNotAssociatedWithBitsCharError: {
-      code: 2079,
-      message: 'Classes derived from Bitmap can only be associated with defineBits characters (bitmaps).'
-    },
-    AlreadyConnectedError: {
-      code: 2082,
-      message: 'Connect failed because the object is already connected.'
-    },
-    CloseNotConnectedError: {
-      code: 2083,
-      message: 'Close failed because the object is not connected.'
-    },
-    ArgumentSizeError: {
-      code: 2084,
-      message: 'The AMF encoding of the arguments cannot exceed 40K.'
-    },
-    FileReferenceProhibitedError: {
-      code: 2086,
-      message: 'A setting in the mms.cfg file prohibits this FileReference request.'
-    },
-    DownloadFileNameProhibitedError: {
-      code: 2087,
-      message: 'The FileReference.download() file name contains prohibited characters.'
-    },
-    EventDispatchRecursionError: {
-      code: 2094,
-      message: 'Event dispatch recursion overflow.'
-    },
-    AsyncError: {
-      code: 2095,
-      message: '%1 was unable to invoke callback %2.'
-    },
-    DisallowedHTTPHeaderError: {
-      code: 2096,
-      message: 'The HTTP request header %1 cannot be set via ActionScript.'
-    },
-    FileFilterError: {
-      code: 2097,
-      message: 'The FileFilter Array is not in the correct format.'
-    },
-    LoadingObjectNotSWFError: {
-      code: 2098,
-      message: 'The loading object is not a .swf file, you cannot request SWF properties from it.'
-    },
-    LoadingObjectNotInitializedError: {
-      code: 2099,
-      message: 'The loading object is not sufficiently loaded to provide this information.'
-    },
-    EmptyByteArrayError: {
-      code: 2100,
-      message: 'The ByteArray parameter in Loader.loadBytes() must have length greater than 0.'
-    },
-    DecodeParamError: {
-      code: 2101,
-      message: 'The String passed to URLVariables.decode() must be a URL-encoded query string containing name/value pairs.'
-    },
-    NotAnXMLChildError: {
-      code: 2102,
-      message: 'The before XMLNode parameter must be a child of the caller.'
-    },
-    XMLRecursionError: {
-      code: 2103,
-      message: 'XML recursion failure: new child would create infinite loop.'
-    },
-    SceneNotFoundError: {
-      code: 2108,
-      message: 'Scene %1 was not found.'
-    },
-    FrameLabelNotFoundError: {
-      code: 2109,
-      message: 'Frame label %1 not found in scene %2.'
-    },
-    DisableAVM1LoadingError: {
-      code: 2110,
-      message: 'The value of Security.disableAVM1Loading cannot be set unless the caller can access the stage and is in an ActionScript 3.0 SWF file.'
-    },
-    AVM1LoadingError: {
-      code: 2111,
-      message: 'Security.disableAVM1Loading is true so the current load of the ActionScript 1.0/2.0 SWF file has been blocked.'
-    },
-    ApplicationDomainSecurityError: {
-      code: 2112,
-      message: 'Provided parameter LoaderContext.ApplicationDomain is from a disallowed domain.'
-    },
-    SecurityDomainSecurityError: {
-      code: 2113,
-      message: 'Provided parameter LoaderContext.SecurityDomain is from a disallowed domain.'
-    },
-    NonNullPointerError: {
-      code: 2114,
-      message: 'Parameter %1 must be null.'
-    },
-    TrueParamError: {
-      code: 2115,
-      message: 'Parameter %1 must be false.'
-    },
-    FalseParamError: {
-      code: 2116,
-      message: 'Parameter %1 must be true.'
-    },
-    InvalidLoaderInfoMethodError: {
-      code: 2118,
-      message: 'The LoaderInfo class does not implement this method.'
-    },
-    LoaderInfoAppDomainSecurityError: {
-      code: 2119,
-      message: 'Security sandbox violation: caller %1 cannot access LoaderInfo.applicationDomain owned by %2.'
-    },
-    SecuritySwfNotAllowedError: {
-      code: 2121,
-      message: 'Security sandbox violation: %1: %2 cannot access %3. This may be worked around by calling Security.allowDomain.'
-    },
-    SecurityNonSwfIncompletePolicyFilesError: {
-      code: 2122,
-      message: 'Security sandbox violation: %1: %2 cannot access %3. A policy file is required, but the checkPolicyFile flag was not set when this media was loaded.'
-    },
-    SecurityNonSwfNotAllowedError: {
-      code: 2123,
-      message: 'Security sandbox violation: %1: %2 cannot access %3. No policy files granted access.'
-    },
-    UnknownFileTypeError: {
-      code: 2124,
-      message: 'Loaded file is an unknown type.'
-    },
-    SecurityCrossVMNotAllowedError: {
-      code: 2125,
-      message: 'Security sandbox violation: %1 cannot use Runtime Shared Library %2 because crossing the boundary between ActionScript 3.0 and ActionScript 1.0/2.0 objects is not allowed.'
-    },
-    NotConnectedError: {
-      code: 2126,
-      message: 'NetConnection object must be connected.'
-    },
-    FileRefBadPostDataTypeError: {
-      code: 2127,
-      message: 'FileReference POST data cannot be type ByteArray.'
-    },
-    NetConnectionConnectError: {
-      code: 2129,
-      message: 'Connection to %1 failed.'
-    },
-    SharedObjectFlushFailedError: {
-      code: 2130,
-      message: 'Unable to flush SharedObject.'
-    },
-    DefinitionNotFoundError: {
-      code: 2131,
-      message: 'Definition %1 cannot be found.'
-    },
-    NetConnectionInvalidConnectFromNetStatusEventError: {
-      code: 2132,
-      message: 'NetConnection.connect cannot be called from a netStatus event handler.'
-    },
-    CallbackNotRegisteredError: {
-      code: 2133,
-      message: 'Callback %1 is not registered.'
-    },
-    SharedObjectCreateError: {
-      code: 2134,
-      message: 'Cannot create SharedObject.'
-    },
-    InvalidSWFError: {
-      code: 2136,
-      message: 'The SWF file %1 contains invalid data.'
-    },
-    NavigationSecurityError: {
-      code: 2137,
-      message: 'Security sandbox violation: %1 cannot navigate window %2 within %3 (allowScriptAccess is %4). Attempted URL was %5.'
-    },
-    NonParsableRichTextXMLError: {
-      code: 2138,
-      message: 'Rich text XML could not be parsed.'
-    },
-    SharedObjectConnectError: {
-      code: 2139,
-      message: 'SharedObject could not connect.'
-    },
-    LocalSecurityLoadingError: {
-      code: 2140,
-      message: 'Security sandbox violation: %1 cannot load %2. Local-with-filesystem and local-with-networking SWF files cannot load each other.'
-    },
-    MultiplePrintJobsError: {
-      code: 2141,
-      message: 'Only one PrintJob may be in use at a time.'
-    },
-    LocalImportSecurityError: {
-      code: 2142,
-      message: 'Security sandbox violation: local SWF files cannot use the LoaderContext.securityDomain property. %1 was attempting to load %2.'
-    },
-    AccOverrideRole: {
-      code: 2143,
-      message: 'AccessibilityImplementation.get_accRole() must be overridden from its default.'
-    },
-    AccOverrideState: {
-      code: 2144,
-      message: 'AccessibilityImplementation.get_accState() must be overridden from its default.'
-    },
-    URLRequestHeaderInvalidLengthError: {
-      code: 2145,
-      message: 'Cumulative length of requestHeaders must be less than 8192 characters.'
-    },
-    AllowNetworkingSecurityError: {
-      code: 2146,
-      message: 'Security sandbox violation: %1 cannot call %2 because the HTML/container parameter allowNetworking has the value %3.'
-    },
-    ForbiddenProtocolError: {
-      code: 2147,
-      message: 'Forbidden protocol in URL %1.'
-    },
-    RemoteToLocalSecurityError: {
-      code: 2148,
-      message: 'SWF file %1 cannot access local resource %2. Only local-with-filesystem and trusted local SWF files may access local resources.'
-    },
-    FsCommandSecurityError: {
-      code: 2149,
-      message: 'Security sandbox violation: %1 cannot make fscommand calls to %2 (allowScriptAccess is %3).'
-    },
-    CantAddParentError: {
-      code: 2150,
-      message: 'An object cannot be added as a child to one of it\'s children (or children\'s children, etc.).'
-    },
-    FullScreenSecurityError: {
-      code: 2151,
-      message: 'You cannot enter full screen mode when the settings dialog is visible.'
-    },
-    FullScreenNotAllowedError: {
-      code: 2152,
-      message: 'Full screen mode is not allowed.'
-    },
-    URLRequestInvalidHeader: {
-      code: 2153,
-      message: 'The URLRequest.requestHeaders array must contain only non-NULL URLRequestHeader objects.'
-    },
-    InvalidNetStreamObject: {
-      code: 2154,
-      message: 'The NetStream Object is invalid.  This may be due to a failed NetConnection.'
-    },
-    InvalidFunctionName: {
-      code: 2155,
-      message: 'The ExternalInterface.call functionName parameter is invalid.  Only alphanumeric characters are supported.'
-    },
-    ForbiddenPortForProtocolError: {
-      code: 2156,
-      message: 'Port %1 may not be accessed using protocol %2. Calling SWF was %3.'
-    },
-    NoAsfunctionErrror: {
-      code: 2157,
-      message: 'Rejecting URL %1 because the \'asfunction:\' protocol may only be used for link targets, not for networking APIs.'
-    },
-    InvalidNetConnectionObject: {
-      code: 2158,
-      message: 'The NetConnection Object is invalid.  This may be due to a dropped NetConnection.'
-    },
-    InvalidSharedObject: {
-      code: 2159,
-      message: 'The SharedObject Object is invalid.'
-    },
-    InvalidTextLineError: {
-      code: 2160,
-      message: 'The TextLine is INVALID and cannot be used to access the current state of the TextBlock.'
-    },
-    TextLayoutError: {
-      code: 2161,
-      message: 'An internal error occured while laying out the text.'
-    },
-    FragmentOutputType: {
-      code: 2162,
-      message: 'The Shader output type is not compatible for this operation.'
-    },
-    FragmentInputType: {
-      code: 2163,
-      message: 'The Shader input type %1 is not compatible for this operation.'
-    },
-    FragmentInputMissing: {
-      code: 2164,
-      message: 'The Shader input %1 is missing or an unsupported type.'
-    },
-    FragmentInputTooSmall: {
-      code: 2165,
-      message: 'The Shader input %1 does not have enough data.'
-    },
-    FragmentInputNoDimension: {
-      code: 2166,
-      message: 'The Shader input %1 lacks valid dimensions.'
-    },
-    FragmentNotEnoughInput: {
-      code: 2167,
-      message: 'The Shader does not have the required number of inputs for this operation.'
-    },
-    StaticTextLineError: {
-      code: 2168,
-      message: 'Static text lines have no atoms and no reference to a text block.'
-    },
-    SecurityQuestionableBrowserScriptingError: {
-      code: 2169,
-      message: 'The method %1 may not be used for browser scripting.  The URL %2 requested by %3 is being ignored.  If you intend to call browser script, use navigateToURL instead.'
-    },
-    HeaderSecurityError: {
-      code: 2170,
-      message: 'Security sandbox violation: %1 cannot send HTTP headers to %2.'
-    },
-    FragmentMissing: {
-      code: 2171,
-      message: 'The Shader object contains no byte code to execute.'
-    },
-    FragmentAlreadyRunning: {
-      code: 2172,
-      message: 'The ShaderJob is already running or finished.'
-    },
-    FileReferenceBusyError: {
-      code: 2174,
-      message: 'Only one download, upload, load or save operation can be active at a time on each FileReference.'
-    },
-    UnformattedElementError: {
-      code: 2175,
-      message: 'One or more elements of the content of the TextBlock has a null ElementFormat.'
-    },
-    UserActionRequiredError: {
-      code: 2176,
-      message: 'Certain actions, such as those that display a pop-up window, may only be invoked upon user interaction, for example by a mouse click or button press.'
-    },
-    FragmentInputTooLarge: {
-      code: 2177,
-      message: 'The Shader input %1 is too large.'
-    },
-    ClipboardConstNotAllowed: {
-      code: 2178,
-      message: 'The Clipboard.generalClipboard object must be used instead of creating a new Clipboard.'
-    },
-    ClipboardDisallowedRead: {
-      code: 2179,
-      message: 'The Clipboard.generalClipboard object may only be read while processing a flash.events.Event.PASTE event.'
-    },
-    CantMoveAVM1ContentLoadedIntoAVM2: {
-      code: 2180,
-      message: 'It is illegal to move AVM1 content (AS1 or AS2) to a different part of the displayList when it has been loaded into AVM2 (AS3) content.'
-    },
-    InvalidTextLineMethodError: {
-      code: 2181,
-      message: 'The TextLine class does not implement this property or method.'
-    },
-    PerspectiveFieldOfViewValueInvalid: {
-      code: 2182,
-      message: 'Invalid fieldOfView value.  The value must be greater than 0 and less than 180.'
-    },
-    Invalid3DScale: {
-      code: 2183,
-      message: 'Scale values must not be zero.'
-    },
-    LockedElementFormatError: {
-      code: 2184,
-      message: 'The ElementFormat object is locked and cannot be modified.'
-    },
-    LockedFontDescriptionError: {
-      code: 2185,
-      message: 'The FontDescription object is locked and cannot be modified.'
-    },
-    PerspectiveFocalLengthInvalid: {
-      code: 2186,
-      message: 'Invalid focalLength %1.'
-    },
-    Matrix3DDecomposeTypeInvalid: {
-      code: 2187,
-      message: 'Invalid orientation style %1.  Value must be one of \'Orientation3D.EULER_ANGLES\', \'Orientation3D.AXIS_ANGLE\', or \'Orientation3D.QUATERNION\'.'
-    },
-    MatrixNonInvertibleError: {
-      code: 2188,
-      message: 'Invalid raw matrix. Matrix must be invertible.'
-    },
-    Matrix3DRefCannontBeShared: {
-      code: 2189,
-      message: 'A Matrix3D can not be assigned to more than one DisplayObject.'
-    },
-    ForceDownloadSecurityError: {
-      code: 2190,
-      message: 'The attempted load of %1 failed as it had a Content-Disposition of attachment set.'
-    },
-    ClipboardDisallowedWrite: {
-      code: 2191,
-      message: 'The Clipboard.generalClipboard object may only be written to as the result of user interaction, for example by a mouse click or button press.'
-    },
-    MalformedUnicodeError: {
-      code: 2192,
-      message: 'An unpaired Unicode surrogate was encountered in the input.'
-    },
-    SecurityContentAccessDeniedError: {
-      code: 2193,
-      message: 'Security sandbox violation: %1: %2 cannot access %3.'
-    },
-    LoaderParamError: {
-      code: 2194,
-      message: 'Parameter %1 cannot be a Loader.'
-    },
-    LoaderAsyncError: {
-      code: 2195,
-      message: 'Error thrown as Loader called %1.'
-    },
-    ObjectWithStringsParamError: {
-      code: 2196,
-      message: 'Parameter %1 must be an Object with only String values.'
-    },
-    SystemUpdaterPlayerNotSupportedError: {
-      code: 2200,
-      message: 'The SystemUpdater class is not supported by this player.'
-    },
-    SystemUpdaterOSNotSupportedError: {
-      code: 2201,
-      message: 'The requested update type is not supported on this operating system.'
-    },
-    SystemUpdaterBusy: {
-      code: 2202,
-      message: 'Only one SystemUpdater action is allowed at a time.'
-    },
-    SystemUpdaterFailed: {
-      code: 2203,
-      message: 'The requested SystemUpdater action cannot be completed.'
-    },
-    SystemUpdaterCannotCancel: {
-      code: 2204,
-      message: 'This operation cannot be canceled because it is waiting for user interaction.'
-    },
-    SystemUpdaterUnknownTarget: {
-      code: 2205,
-      message: 'Invalid update type %1.'
-    },
-    SignedSWfLoadingError: {
-      code: 2500,
-      message: 'An error occurred decrypting the signed swf file. The swf will not be loaded.'
-    },
-    NotScreenSharingError: {
-      code: 2501,
-      message: 'This property can only be accessed during screen sharing.'
-    },
-    NotSharingMonitorError: {
-      code: 2502,
-      message: 'This property can only be accessed if sharing the entire screen.'
-    },
-    FileBadPathName: {
-      code: 3000,
-      message: 'Illegal path name.'
-    },
-    FileAccessDenied: {
-      code: 3001,
-      message: 'File or directory access denied.'
-    },
-    FileExists: {
-      code: 3002,
-      message: 'File or directory exists.'
-    },
-    FileDoesNotExist: {
-      code: 3003,
-      message: 'File or directory does not exist.'
-    },
-    FileInsufficientSpace: {
-      code: 3004,
-      message: 'Insufficient file space.'
-    },
-    FileSystemResources: {
-      code: 3005,
-      message: 'Insufficient system resources.'
-    },
-    FileNotAFile: {
-      code: 3006,
-      message: 'Not a file.'
-    },
-    FileNotADir: {
-      code: 3007,
-      message: 'Not a directory.'
-    },
-    FileReadOnlyFileSys: {
-      code: 3008,
-      message: 'Read-only or write-protected media.'
-    },
-    FileNotSameDevice: {
-      code: 3009,
-      message: 'Cannot move file or directory to a different device.'
-    },
-    DirNotEmpty: {
-      code: 3010,
-      message: 'Directory is not empty.'
-    },
-    FileDestinationExists: {
-      code: 3011,
-      message: 'Move or copy destination already exists.'
-    },
-    FileCantDelete: {
-      code: 3012,
-      message: 'Cannot delete file or directory.'
-    },
-    FileInUse: {
-      code: 3013,
-      message: 'File or directory is in use.'
-    },
-    FileCopyMoveAncestor: {
-      code: 3014,
-      message: 'Cannot copy or move a file or directory to overwrite a containing directory.'
-    },
-    LoadBytesCodeExecutionSecurityError: {
-      code: 3015,
-      message: 'Loader.loadBytes() is not permitted to load content with executable code.'
-    },
-    FileApplicationNotFound: {
-      code: 3016,
-      message: 'No application was found that can open this file.'
-    },
-    SQLConnectionCannotClose: {
-      code: 3100,
-      message: 'A SQLConnection cannot be closed while statements are still executing.'
-    },
-    SQLConnectionAlreadyOpen: {
-      code: 3101,
-      message: 'Database connection is already open.'
-    },
-    SQLConnectionInvalidName: {
-      code: 3102,
-      message: 'Name argument specified was invalid. It must not be null or empty.'
-    },
-    SQLConnectionInTransaction: {
-      code: 3103,
-      message: 'Operation cannot be performed while there is an open transaction on this connection.'
-    },
-    SQLConnectionNotOpen: {
-      code: 3104,
-      message: 'A SQLConnection must be open to perform this operation.'
-    },
-    SQLConnectionNoOpenTransaction: {
-      code: 3105,
-      message: 'Operation is only allowed if a connection has an open transaction.'
-    },
-    SQLStatementIsExecutingProperty: {
-      code: 3106,
-      message: 'Property cannot be changed while SQLStatement.executing is true.'
-    },
-    SQLStatementIvalidCall: {
-      code: 3107,
-      message: '%1 may not be called unless SQLResult.complete is false.'
-    },
-    SQLStatementInvalidText: {
-      code: 3108,
-      message: 'Operation is not permitted when the SQLStatement.text property is not set.'
-    },
-    SQLStatementInvalidConnection: {
-      code: 3109,
-      message: 'Operation is not permitted when the SQLStatement.sqlConnection property is not set.'
-    },
-    SQLStatementIsExecutingCall: {
-      code: 3110,
-      message: 'Operation cannot be performed while SQLStatement.executing is true.'
-    },
-    SQLStatementInvalidSchemaType: {
-      code: 3111,
-      message: 'An invalid schema type was specified.'
-    },
-    SQLConnectionInvalidLockType: {
-      code: 3112,
-      message: 'An invalid transaction lock type was specified.'
-    },
-    SQLConnectionNotFileReference: {
-      code: 3113,
-      message: 'Reference specified is not of type File.'
-    },
-    SQLConnectionInvalidModeSpecified: {
-      code: 3114,
-      message: 'An invalid open mode was specified.'
-    },
-    SQLGeneralEngineError: {
-      code: 3115,
-      message: 'SQL Error.'
-    },
-    SQLInternalEngineError: {
-      code: 3116,
-      message: 'An internal logic error occurred.'
-    },
-    SQLPermissionError: {
-      code: 3117,
-      message: 'Access permission denied.'
-    },
-    SQLOperationAbortedError: {
-      code: 3118,
-      message: 'Operation aborted.'
-    },
-    SQLDatabaseLockedError: {
-      code: 3119,
-      message: 'Database file is currently locked.'
-    },
-    SQLTableLockedError: {
-      code: 3120,
-      message: 'Table is locked.'
-    },
-    SQLOutOfMemoryError: {
-      code: 3121,
-      message: 'Out of memory.'
-    },
-    SQLDatabaseIsReadonlyError: {
-      code: 3122,
-      message: 'Attempt to write a readonly database.'
-    },
-    SQLDatabaseCorruptError: {
-      code: 3123,
-      message: 'Database disk image is malformed.'
-    },
-    SQLDatabaseFullError: {
-      code: 3124,
-      message: 'Insertion failed because database is full.'
-    },
-    SQLCannotOpenDatabaseError: {
-      code: 3125,
-      message: 'Unable to open the database file.'
-    },
-    SQLLockingProtocolError: {
-      code: 3126,
-      message: 'Database lock protocol error.'
-    },
-    SQLDatabaseEmptyError: {
-      code: 3127,
-      message: 'Database is empty.'
-    },
-    SQLDiskIOError: {
-      code: 3128,
-      message: 'Disk I/O error occurred.'
-    },
-    SQLSchemaChangedError: {
-      code: 3129,
-      message: 'The database schema changed.'
-    },
-    SQLTooMuchDataError: {
-      code: 3130,
-      message: 'Too much data for one row of a table.'
-    },
-    SQLConstraintError: {
-      code: 3131,
-      message: 'Abort due to constraint violation.'
-    },
-    SQLDataTypeMismatchError: {
-      code: 3132,
-      message: 'Data type mismatch.'
-    },
-    SQLConcurrencyError: {
-      code: 3133,
-      message: 'An internal error occurred.'
-    },
-    SQLNotSupportedOnOSError: {
-      code: 3134,
-      message: 'Feature not supported on this operating system.'
-    },
-    SQLAuthorizationDeniedError: {
-      code: 3135,
-      message: 'Authorization denied.'
-    },
-    SQLAuxDatabaseFormatError: {
-      code: 3136,
-      message: 'Auxiliary database format error.'
-    },
-    SQLBindingRangeError: {
-      code: 3137,
-      message: 'An index specified for a parameter was out of range.'
-    },
-    SQLInvalidDatabaseFileError: {
-      code: 3138,
-      message: 'File opened is not a database file.'
-    },
-    SQLInvalidPageSizeError: {
-      code: 3139,
-      message: 'The page size specified was not valid for this operation.'
-    },
-    SQLInvalidKeySizeError: {
-      code: 3140,
-      message: 'The encryption key size specified was not valid for this operation. Keys must be exactly 16 bytes in length'
-    },
-    SQLInvalidConfigurationError: {
-      code: 3141,
-      message: 'The requested database configuration is not supported.'
-    },
-    SQLCannotRekeyNonKeyedDatabase: {
-      code: 3143,
-      message: 'Unencrypted databases may not be reencrypted.'
-    },
-    NativeWindowClosedError: {
-      code: 3200,
-      message: 'Cannot perform operation on closed window.'
-    },
-    PDFNoReaderInstalled: {
-      code: 3201,
-      message: 'Adobe Reader cannot be found.'
-    },
-    PDFOldReaderInstalled: {
-      code: 3202,
-      message: 'Adobe Reader 8.1 or later cannot be found.'
-    },
-    PDFOldDefaultText: {
-      code: 3203,
-      message: 'Default Adobe Reader must be version 8.1 or later.'
-    },
-    PDFCannotLoadReader: {
-      code: 3204,
-      message: 'An error ocurred trying to load Adobe Reader.'
-    },
-    ApplicationFeatureSecurityError: {
-      code: 3205,
-      message: 'Only application-sandbox content can access this feature.'
-    },
-    LoaderInfoDoorSecurityError: {
-      code: 3206,
-      message: 'Caller %1 cannot set LoaderInfo property %2.'
-    },
-    ApplicationNonFeatureSecurityError: {
-      code: 3207,
-      message: 'Application-sandbox content cannot access this feature.'
-    },
-    InvalidClipboardAccess: {
-      code: 3208,
-      message: 'Attempt to access invalid clipboard.'
-    },
-    DeadClipboardAccess: {
-      code: 3209,
-      message: 'Attempt to access dead clipboard.'
-    },
-    DeadJavaScriptObjectAccess: {
-      code: 3210,
-      message: 'The application attempted to reference a JavaScript object in a HTML page that is no longer loaded.'
-    },
-    FilePromiseIOError: {
-      code: 3211,
-      message: 'Drag and Drop File Promise error: %1'
-    },
-    NativeProcessNotRunning: {
-      code: 3212,
-      message: 'Cannot perform operation on a NativeProcess that is not running.'
-    },
-    NativeProcessAlreadyRunning: {
-      code: 3213,
-      message: 'Cannot perform operation on a NativeProcess that is already running.'
-    },
-    NativeProcessBadExecutable: {
-      code: 3214,
-      message: 'NativeProcessStartupInfo.executable does not specify a valid executable file.'
-    },
-    NativeProcessBadWorkingDirectory: {
-      code: 3215,
-      message: 'NativeProcessStartupInfo.workingDirectory does not specify a valid directory.'
-    },
-    NativeProcessStdOutReadError: {
-      code: 3216,
-      message: 'Error while reading data from NativeProcess.standardOutput.'
-    },
-    NativeProcessStdErrReadError: {
-      code: 3217,
-      message: 'Error while reading data from NativeProcess.standardError.'
-    },
-    NativeProcessStdInWriteError: {
-      code: 3218,
-      message: 'Error while writing data to NativeProcess.standardInput.'
-    },
-    NativeProcessNotStarted: {
-      code: 3219,
-      message: 'The NativeProcess could not be started. \'%1\''
-    },
-    ActionNotAllowedSecurityError: {
-      code: 3220,
-      message: 'Action \'%1\' not allowed in current security context \'%2\'.'
-    },
-    SWFNoPlayerInstalled: {
-      code: 3221,
-      message: 'Adobe Flash Player cannot be found.'
-    },
-    SWFOldPlayerInstalled: {
-      code: 3222,
-      message: 'The installed version of Adobe Flash Player is too old.'
-    },
-    DNSResolverLookupError: {
-      code: 3223,
-      message: 'DNS lookup error: platform error %1'
-    },
-    SocketMessageTooLongError: {
-      code: 3224,
-      message: 'Socket message too long'
-    },
-    SocketCannotSendDataToAddressAfterConnect: {
-      code: 3225,
-      message: 'Cannot send data to a location when connected.'
-    },
-    AllowCodeImportError: {
-      code: 3226,
-      message: 'Cannot import a SWF file when LoaderContext.allowCodeImport is false.'
-    },
-    BackgroundLaunchError: {
-      code: 3227,
-      message: 'Cannot launch another application from background.'
-    },
-    StageWebViewLoadError: {
-      code: 3228,
-      message: 'StageWebView encountered an error during the load operation.'
-    },
-    StageWebViewProtocolNotSupported: {
-      code: 3229,
-      message: 'The protocol is not supported.:'
-    },
-    BrowseOperationUnsupported: {
-      code: 3230,
-      message: 'The browse operation is unsupported.'
-    },
-    InvalidVoucher: {
-      code: 3300,
-      message: 'Voucher is invalid.'
-    },
-    AuthenticationFailed: {
-      code: 3301,
-      message: 'User authentication failed.'
-    },
-    RequireSSLError: {
-      code: 3302,
-      message: 'Flash Access server does not support SSL.'
-    },
-    ContentExpiredError: {
-      code: 3303,
-      message: 'Content expired.'
-    },
-    AuthorizationFailed: {
-      code: 3304,
-      message: 'User authorization failed (for example, the user has not purchased the content).'
-    },
-    ServerConnectionFailed: {
-      code: 3305,
-      message: 'Can\'t connect to the server.'
-    },
-    ClientUpdateRequired: {
-      code: 3306,
-      message: 'Client update required (Flash Access server requires new client).'
-    },
-    InternalError: {
-      code: 3307,
-      message: 'Generic internal Flash Access failure.'
-    },
-    WrongVoucherKey: {
-      code: 3308,
-      message: 'Wrong voucher key.'
-    },
-    CorruptedFLV: {
-      code: 3309,
-      message: 'Video content is corrupted.'
-    },
-    AppIDMismatch: {
-      code: 3310,
-      message: 'The AIR application or Flash Player SWF does not match the one specified in the DRM policy.'
-    },
-    AppVersionMismatch: {
-      code: 3311,
-      message: 'The version of the application does not match the one specified in the DRM policy.'
-    },
-    VoucherIntegrityError: {
-      code: 3312,
-      message: 'Verification of voucher failed.'
-    },
-    WriteFileSystemFailed: {
-      code: 3313,
-      message: 'Write to the file system failed.'
-    },
-    FLVHeaderIntegrityFailed: {
-      code: 3314,
-      message: 'Verification of FLV/F4V header file failed.'
-    },
-    PermissionDenied: {
-      code: 3315,
-      message: 'The current security context does not allow this operation.'
-    },
-    LocalConnectionUserScopedLocked: {
-      code: 3316,
-      message: 'The value of LocalConnection.isPerUser cannot be changed because it has already been locked by a call to LocalConnection.connect, .send, or .close.'
-    },
-    LoadAdobeCPFailed: {
-      code: 3317,
-      message: 'Failed to load Flash Access module.'
-    },
-    IncompatibleAdobeCPVersion: {
-      code: 3318,
-      message: 'Incompatible version of Flash Access module found.'
-    },
-    MissingAdobeCPEntryPoint: {
-      code: 3319,
-      message: 'Missing Flash Access module API entry point.'
-    },
-    InternalErrorHA: {
-      code: 3320,
-      message: 'Generic internal Flash Access failure.'
-    },
-    IndividualizationFailed: {
-      code: 3321,
-      message: 'Individualization failed.'
-    },
-    DeviceBindingFailed: {
-      code: 3322,
-      message: 'Device binding failed.'
-    },
-    CorruptStore: {
-      code: 3323,
-      message: 'The internal stores are corrupted.'
-    },
-    MachineTokenInvalid: {
-      code: 3324,
-      message: 'Reset license files and the client will fetch a new machine token.'
-    },
-    CorruptServerStateStore: {
-      code: 3325,
-      message: 'Internal stores are corrupt.'
-    },
-    TamperingDetected: {
-      code: 3326,
-      message: 'Call customer support.'
-    },
-    ClockTamperingDetected: {
-      code: 3327,
-      message: 'Clock tampering detected.'
-    },
-    ServerErrorTryAgain: {
-      code: 3328,
-      message: 'Server error; retry the request.'
-    },
-    ApplicationSpecificError: {
-      code: 3329,
-      message: 'Error in application-specific namespace.'
-    },
-    NeedAuthentication: {
-      code: 3330,
-      message: 'Need to authenticate the user and reacquire the voucher.'
-    },
-    ContentNotYetValid: {
-      code: 3331,
-      message: 'Content is not yet valid.'
-    },
-    CachedVoucherExpired: {
-      code: 3332,
-      message: 'Cached voucher has expired. Reacquire the voucher from the server.'
-    },
-    PlaybackWindowExpired: {
-      code: 3333,
-      message: 'The playback window for this policy has expired.'
-    },
-    InvalidDRMPlatform: {
-      code: 3334,
-      message: 'This platform is not allowed to play this content.'
-    },
-    InvalidDRMVersion: {
-      code: 3335,
-      message: 'Invalid version of Flash Access module. Upgrade AIR or Flash Access module for the Flash Player.'
-    },
-    InvalidRuntimePlatform: {
-      code: 3336,
-      message: 'This platform is not allowed to play this content.'
-    },
-    InvalidRuntimeVersion: {
-      code: 3337,
-      message: 'Upgrade Flash Player or AIR  and retry playback.'
-    },
-    UnknownConnectionType: {
-      code: 3338,
-      message: 'Unknown connection type.'
-    },
-    NoAnalogPlaybackAllowed: {
-      code: 3339,
-      message: 'Can\'t play back on analog device. Connect to a digital device.'
-    },
-    NoAnalogProtectionAvail: {
-      code: 3340,
-      message: 'Can\'t play back because connected analog device doesn\'t have the correct capabilities.'
-    },
-    NoDigitalPlaybackAllowed: {
-      code: 3341,
-      message: 'Can\'t play back on digital device.'
-    },
-    NoDigitalProtectionAvail: {
-      code: 3342,
-      message: 'The connected digital device doesn\'t have the correct capabilities.'
-    },
-    InternalErrorIV: {