Merge fx-team to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Wed, 26 Feb 2014 16:25:05 -0500
changeset 171101 8b52fb24991d57ff8dd5205fd9334cf1e26b04d2
parent 171080 e840b5a70371d3776a6b2fa8c5e6bb6568e72780 (current diff)
parent 171100 b2baefa192ff24dff30a360c8a6770357fe4b58d (diff)
child 171161 bb9edb4d5144d414e355b8d09a74c94ba57096bf
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
milestone30.0a1
Merge fx-team to m-c.
browser/devtools/shared/event-emitter.js
browser/devtools/shared/test/browser_eventemitter_basic.js
services/common/hawk.js
services/common/tests/unit/test_hawk.js
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -384,17 +384,32 @@ panel[noactions] > richlistbox > richlis
   visibility: collapse;
 }
 
 #urlbar[pageproxystate="invalid"] > #identity-box {
   pointer-events: none;
 }
 
 #identity-icon-labels {
-  max-width: 12vw;
+  max-width: 18em;
+}
+@media (max-width: 700px) {
+  #identity-icon-labels {
+    max-width: 70px;
+  }
+}
+@media (max-width: 600px) {
+  #identity-icon-labels {
+    max-width: 60px;
+  }
+}
+@media (max-width: 500px) {
+  #identity-icon-labels {
+    max-width: 50px;
+  }
 }
 
 #identity-icon-country-label {
   direction: ltr;
 }
 
 #identity-box.verifiedIdentity > #identity-icon-labels > #identity-icon-label {
   -moz-margin-end: 0.25em !important;
--- a/browser/base/content/test/general/browser_windowopen_reflows.js
+++ b/browser/base/content/test/general/browser_windowopen_reflows.js
@@ -20,25 +20,27 @@ const EXPECTED_REFLOWS = [
   // Focusing the content area causes a reflow.
   "gBrowserInit._delayedStartup@chrome://browser/content/browser.js|",
 
   // Sometimes sessionstore collects data during this test, which causes a sync reflow
   // (https://bugzilla.mozilla.org/show_bug.cgi?id=892154 will fix this)
   "ssi_getWindowDimension@resource:///modules/sessionstore/SessionStore.jsm",
 ];
 
-if (Services.appinfo.OS == "Darwin") {
-  // TabsInTitlebar._update causes a reflow on OS X trying to do calculations
+if (Services.appinfo.OS == "WINNT" || Services.appinfo.OS == "Darwin") {
+  // TabsInTitlebar._update causes a reflow on OS X and Windows trying to do calculations
   // since layout info is already dirty. This doesn't seem to happen before
-  // MozAfterPaint on other platforms.
+  // MozAfterPaint on Linux.
   EXPECTED_REFLOWS.push("rect@chrome://browser/content/browser.js|" +
                           "TabsInTitlebar._update@chrome://browser/content/browser.js|" +
                           "updateAppearance@chrome://browser/content/browser.js|" +
                           "handleEvent@chrome://browser/content/tabbrowser.xml|");
+}
 
+if (Services.appinfo.OS == "Darwin") {
   // _onOverflow causes a reflow getting widths.
   EXPECTED_REFLOWS.push("OverflowableToolbar.prototype._onOverflow@resource:///modules/CustomizableUI.jsm|" +
                         "OverflowableToolbar.prototype.init@resource:///modules/CustomizableUI.jsm|" +
                         "OverflowableToolbar.prototype.observe@resource:///modules/CustomizableUI.jsm|" +
                         "gBrowserInit._delayedStartup@chrome://browser/content/browser.js|");
   // Same as above since in packaged builds there are no function names and the resource URI includes "app"
   EXPECTED_REFLOWS.push("@resource://app/modules/CustomizableUI.jsm|" +
                           "@resource://app/modules/CustomizableUI.jsm|" +
--- a/browser/components/customizableui/content/panelUI.xml
+++ b/browser/components/customizableui/content/panelUI.xml
@@ -212,17 +212,17 @@
           this._mainViewHeight = this._viewStack.clientHeight;
 
           this._transitioning = true;
           this._viewContainer.addEventListener("transitionend", function trans() {
             this._viewContainer.removeEventListener("transitionend", trans);
             this._transitioning = false;
           }.bind(this));
 
-          let newHeight = this._heightOfSubview(viewNode);
+          let newHeight = this._heightOfSubview(viewNode, this._subViews);
           this._viewContainer.style.height = newHeight + "px";
 
           this._subViewObserver.observe(viewNode, {
             attributes: true,
             characterData: true,
             childList: true,
             subtree: true
           });
@@ -319,17 +319,17 @@
           this._mainView.style.height =
             this.getBoundingClientRect().height + "px";
           this.ignoreMutations = false;
         ]]></body>
       </method>
       <method name="_syncContainerWithSubView">
         <body><![CDATA[
           if (!this.ignoreMutations && this.showingSubView) {
-            let newHeight = this._heightOfSubview(this._currentSubView);
+            let newHeight = this._heightOfSubview(this._currentSubView, this._subViews);
             this._viewContainer.style.height = newHeight + "px";
           }
         ]]></body>
       </method>
       <method name="_syncContainerWithMainView">
         <body><![CDATA[
           if (!this.ignoreMutations && !this.showingSubView && !this._transitioning) {
             let height;
@@ -340,26 +340,60 @@
             }
             this._viewContainer.style.height = height + "px";
           }
         ]]></body>
       </method>
 
       <method name="_heightOfSubview">
         <parameter name="aSubview"/>
+        <parameter name="aContainerToCheck"/>
         <body><![CDATA[
+          function getFullHeight(element) {
+            //XXXgijs: unfortunately, scrollHeight rounds values, and there's no alternative
+            // that works with overflow: auto elements. Fortunately for us,
+            // we have exactly 1 (potentially) scrolling element in here (the subview body),
+            // and rounding 1 value is OK - rounding more than 1 and adding them means we get
+            // off-by-1 errors. Now we might be off by a subpixel, but we care less about that.
+            // So, use scrollHeight *only* if the element is vertically scrollable.
+            let height;
+            let elementCS;
+            if (element.scrollTopMax) {
+              height = element.scrollHeight;
+              // Bounding client rects include borders, scrollHeight doesn't:
+              elementCS = win.getComputedStyle(element);
+              height += parseFloat(elementCS.borderTopWidth) +
+                        parseFloat(elementCS.borderBottomWidth);
+            } else {
+              height = element.getBoundingClientRect().height;
+              if (height > 0) {
+                elementCS = win.getComputedStyle(element);
+              }
+            }
+            if (elementCS) {
+              // Include margins - but not borders or paddings because they
+              // were dealt with above.
+              height += parseFloat(elementCS.marginTop) + parseFloat(elementCS.marginBottom);
+            }
+            return height;
+          }
+          let win = aSubview.ownerDocument.defaultView;
           let body = aSubview.querySelector(".panel-subview-body");
-          let height = body ? body.scrollHeight : aSubview.scrollHeight;
+          let height = getFullHeight(body || aSubview);
           if (body) {
             let header = aSubview.querySelector(".panel-subview-header");
             let footer = aSubview.querySelector(".panel-subview-footer");
-            height += (header ? header.scrollHeight : 0) +
-                      (footer ? footer.scrollHeight : 0);
+            height += (header ? getFullHeight(header) : 0) +
+                      (footer ? getFullHeight(footer) : 0);
           }
-          return height;
+          if (aContainerToCheck) {
+            let containerCS = win.getComputedStyle(aContainerToCheck);
+            height += parseFloat(containerCS.paddingTop) + parseFloat(containerCS.paddingBottom);
+          }
+          return Math.round(height);
         ]]></body>
       </method>
 
     </implementation>
   </binding>
 
   <binding id="panelview">
     <implementation>
--- a/browser/components/customizableui/src/CustomizeMode.jsm
+++ b/browser/components/customizableui/src/CustomizeMode.jsm
@@ -287,16 +287,22 @@ CustomizeMode.prototype = {
 
     // Entering; want to exit once we've done that.
     if (this._handler.isEnteringCustomizeMode) {
       LOG("Attempted to exit while we're in the middle of entering. " +
           "We'll exit after we've entered");
       return;
     }
 
+    if (this.resetting) {
+      LOG("Attempted to exit while we're resetting. " +
+          "We'll exit after resetting has finished.");
+      return;
+    }
+
     this._handler.isExitingCustomizeMode = true;
 
     CustomizableUI.removeListener(this);
 
     this.document.removeEventListener("keypress", this);
     this.window.PanelUI.menuButton.removeEventListener("mousedown", this);
     this.window.PanelUI.menuButton.open = false;
 
@@ -880,16 +886,19 @@ CustomizeMode.prototype = {
 
       this.persistCurrentSets(true);
 
       this._updateResetButton();
       this._updateUndoResetButton();
       this._updateEmptyPaletteNotice();
       this._showPanelCustomizationPlaceholders();
       this.resetting = false;
+      if (!this._wantToBeInCustomizeMode) {
+        this.exit();
+      }
     }.bind(this)).then(null, ERROR);
   },
 
   undoReset: function() {
     this.resetting = true;
 
     return Task.spawn(function() {
       this._removePanelCustomizationPlaceholders();
--- a/browser/devtools/app-manager/app-projects.js
+++ b/browser/devtools/app-manager/app-projects.js
@@ -1,13 +1,13 @@
 const {Cc,Ci,Cu} = require("chrome");
 const ObservableObject = require("devtools/shared/observable-object");
 const promise = require("sdk/core/promise");
 
-const {EventEmitter} = Cu.import("resource:///modules/devtools/shared/event-emitter.js");
+const {EventEmitter} = Cu.import("resource://gre/modules/devtools/event-emitter.js");
 const {generateUUID} = Cc['@mozilla.org/uuid-generator;1'].getService(Ci.nsIUUIDGenerator);
 
 /**
  * IndexedDB wrapper that just save project objects
  *
  * The only constraint is that project objects have to have
  * a unique `location` object.
  */
--- a/browser/devtools/app-manager/content/projects.js
+++ b/browser/devtools/app-manager/content/projects.js
@@ -11,17 +11,17 @@ const {devtools} = Cu.import("resource:/
 const {require} = devtools;
 const {ConnectionManager, Connection} = require("devtools/client/connection-manager");
 const {AppProjects} = require("devtools/app-manager/app-projects");
 const {AppValidator} = require("devtools/app-manager/app-validator");
 const {Services} = Cu.import("resource://gre/modules/Services.jsm");
 const {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm");
 const {installHosted, installPackaged, getTargetForApp,
        reloadApp, launchApp, closeApp} = require("devtools/app-actor-front");
-const {EventEmitter} = Cu.import("resource:///modules/devtools/shared/event-emitter.js");
+const {EventEmitter} = Cu.import("resource://gre/modules/devtools/event-emitter.js");
 
 const promise = require("sdk/core/promise");
 
 const MANIFEST_EDITOR_ENABLED = "devtools.appmanager.manifestEditor.enabled";
 
 window.addEventListener("message", function(event) {
   try {
     let json = JSON.parse(event.data);
--- a/browser/devtools/app-manager/content/utils.js
+++ b/browser/devtools/app-manager/content/utils.js
@@ -11,17 +11,17 @@
  *
  */
 
 let Utils = (function() {
   const Cu = Components.utils;
   const {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
   const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
   const {require} = devtools;
-  const EventEmitter = require("devtools/shared/event-emitter");
+  const EventEmitter = require("devtools/toolkit/event-emitter");
 
 
   function _createSetEventForwarder(key, finalStore) {
     return function(event, path, value) {
       finalStore.emit("set", [key].concat(path), value);
     };
   }
 
--- a/browser/devtools/commandline/BuiltinCommands.jsm
+++ b/browser/devtools/commandline/BuiltinCommands.jsm
@@ -12,17 +12,17 @@ const BRAND_SHORT_NAME = Cc["@mozilla.or
 this.EXPORTED_SYMBOLS = [ "CmdAddonFlags", "CmdCommands", "DEFAULT_DEBUG_PORT", "connect" ];
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js").Promise;
 Cu.import("resource://gre/modules/osfile.jsm");
 
 Cu.import("resource://gre/modules/devtools/gcli.jsm");
-Cu.import("resource:///modules/devtools/shared/event-emitter.js");
+Cu.import("resource://gre/modules/devtools/event-emitter.js");
 
 let devtools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
 let Telemetry = devtools.require("devtools/shared/telemetry");
 let telemetry = new Telemetry();
 
 XPCOMUtils.defineLazyModuleGetter(this, "gDevTools",
                                   "resource:///modules/devtools/gDevTools.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
--- a/browser/devtools/debugger/debugger-controller.js
+++ b/browser/devtools/debugger/debugger-controller.js
@@ -85,17 +85,17 @@ const FRAME_TYPE = {
   CONDITIONAL_BREAKPOINT_EVAL: 1,
   WATCH_EXPRESSIONS_EVAL: 2,
   PUBLIC_CLIENT_EVAL: 3
 };
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
-Cu.import("resource:///modules/devtools/shared/event-emitter.js");
+Cu.import("resource://gre/modules/devtools/event-emitter.js");
 Cu.import("resource:///modules/devtools/SimpleListWidget.jsm");
 Cu.import("resource:///modules/devtools/BreadcrumbsWidget.jsm");
 Cu.import("resource:///modules/devtools/SideMenuWidget.jsm");
 Cu.import("resource:///modules/devtools/VariablesView.jsm");
 Cu.import("resource:///modules/devtools/VariablesViewController.jsm");
 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
 
 const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
--- a/browser/devtools/debugger/panel.js
+++ b/browser/devtools/debugger/panel.js
@@ -2,17 +2,17 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* 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/. */
 "use strict";
 
 const { Cc, Ci, Cu, Cr } = require("chrome");
 const promise = require("sdk/core/promise");
-const EventEmitter = require("devtools/shared/event-emitter");
+const EventEmitter = require("devtools/toolkit/event-emitter");
 
 const { DevToolsUtils } = Cu.import("resource://gre/modules/devtools/DevToolsUtils.jsm", {});
 
 function DebuggerPanel(iframeWindow, toolbox) {
   this.panelWin = iframeWindow;
   this._toolbox = toolbox;
   this._destroyer = null;
 
--- a/browser/devtools/framework/gDevTools.jsm
+++ b/browser/devtools/framework/gDevTools.jsm
@@ -5,17 +5,17 @@
 "use strict";
 
 this.EXPORTED_SYMBOLS = [ "gDevTools", "DevTools", "gDevToolsBrowser" ];
 
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource:///modules/devtools/shared/event-emitter.js");
+Cu.import("resource://gre/modules/devtools/event-emitter.js");
 let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js").Promise;
 Cu.import("resource://gre/modules/devtools/Loader.jsm");
 
 var ProfilerController = devtools.require("devtools/profiler/controller");
 
 const FORBIDDEN_IDS = new Set(["toolbox", ""]);
 const MAX_ORDINAL = 99;
 
--- a/browser/devtools/framework/selection.js
+++ b/browser/devtools/framework/selection.js
@@ -2,17 +2,17 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* 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/. */
 
 "use strict";
 
 const {Cu, Ci} = require("chrome");
-let EventEmitter = require("devtools/shared/event-emitter");
+let EventEmitter = require("devtools/toolkit/event-emitter");
 
 /**
  * API
  *
  *   new Selection(walker=null, node=null, track={attributes,detached});
  *   destroy()
  *   node (readonly)
  *   setNode(node, origin="unknown")
--- a/browser/devtools/framework/sidebar.js
+++ b/browser/devtools/framework/sidebar.js
@@ -4,17 +4,17 @@
  * 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/. */
 
 const {Cu} = require("chrome");
 
 Cu.import("resource://gre/modules/Services.jsm");
 
 var promise = require("sdk/core/promise");
-var EventEmitter = require("devtools/shared/event-emitter");
+var EventEmitter = require("devtools/toolkit/event-emitter");
 var Telemetry = require("devtools/shared/telemetry");
 
 const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
 /**
  * ToolSidebar provides methods to register tabs in the sidebar.
  * It's assumed that the sidebar contains a xul:tabbox.
  *
--- a/browser/devtools/framework/target.js
+++ b/browser/devtools/framework/target.js
@@ -2,17 +2,17 @@
  * 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/. */
 
 "use strict";
 
 const {Cc, Ci, Cu} = require("chrome");
 
 var promise = require("sdk/core/promise");
-var EventEmitter = require("devtools/shared/event-emitter");
+var EventEmitter = require("devtools/toolkit/event-emitter");
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "DebuggerServer",
   "resource://gre/modules/devtools/dbg-server.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "DebuggerClient",
   "resource://gre/modules/devtools/dbg-client.jsm");
 
 const targets = new WeakMap();
@@ -347,16 +347,18 @@ TabTarget.prototype = {
     this._tab.removeEventListener("TabClose", this);
     this._tab.parentNode.removeEventListener("TabSelect", this);
   },
 
   /**
    * Setup listeners for remote debugging, updating existing ones as necessary.
    */
   _setupRemoteListeners: function TabTarget__setupRemoteListeners() {
+    this.client.addListener("closed", this.destroy);
+
     this._onTabDetached = (aType, aPacket) => {
       // We have to filter message to ensure that this detach is for this tab
       if (aPacket.from == this._form.actor) {
         this.destroy();
       }
     };
     this.client.addListener("tabDetached", this._onTabDetached);
 
@@ -379,16 +381,17 @@ TabTarget.prototype = {
     }.bind(this);
     this.client.addListener("tabNavigated", this._onTabNavigated);
   },
 
   /**
    * Teardown listeners for remote debugging.
    */
   _teardownRemoteListeners: function TabTarget__teardownRemoteListeners() {
+    this.client.removeListener("closed", this.destroy);
     this.client.removeListener("tabNavigated", this._onTabNavigated);
     this.client.removeListener("tabDetached", this._onTabDetached);
   },
 
   /**
    * Handle tabs events.
    */
   handleEvent: function (event) {
--- a/browser/devtools/framework/test/browser.ini
+++ b/browser/devtools/framework/test/browser.ini
@@ -5,16 +5,17 @@ support-files =
   browser_toolbox_options_disable_cache.sjs
   head.js
 
 [browser_devtools_api.js]
 [browser_dynamic_tool_enabling.js]
 [browser_keybindings.js]
 [browser_new_activation_workflow.js]
 [browser_target_events.js]
+[browser_target_remote.js]
 [browser_toolbox_dynamic_registration.js]
 [browser_toolbox_highlight.js]
 [browser_toolbox_hosts.js]
 [browser_toolbox_options.js]
 [browser_toolbox_options_disable_cache.js]
 [browser_toolbox_options_disable_js.js]
 # [browser_toolbox_raise.js] # Bug 962258
 # skip-if = os == "win"
--- a/browser/devtools/framework/test/browser_devtools_api.js
+++ b/browser/devtools/framework/test/browser_devtools_api.js
@@ -2,17 +2,17 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests devtools API
 
 const Cu = Components.utils;
 const toolId = "test-tool";
 
 let tempScope = {};
-Cu.import("resource:///modules/devtools/shared/event-emitter.js", tempScope);
+Cu.import("resource://gre/modules/devtools/event-emitter.js", tempScope);
 let EventEmitter = tempScope.EventEmitter;
 
 function test() {
   addTab("about:blank", function(aBrowser, aTab) {
     runTests(aTab);
   });
 }
 
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/test/browser_target_remote.js
@@ -0,0 +1,39 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+let { DebuggerServer } =
+  Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
+let { DebuggerClient } =
+  Cu.import("resource://gre/modules/devtools/dbg-client.jsm", {});
+let { devtools } =
+  Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
+
+// Ensure target is closed if client is closed directly
+function test() {
+  waitForExplicitFinish();
+
+  if (!DebuggerServer.initialized) {
+    DebuggerServer.init(function () { return true; });
+    DebuggerServer.addBrowserActors();
+  }
+
+  var client = new DebuggerClient(DebuggerServer.connectPipe());
+  client.connect(() => {
+    client.listTabs(response => {
+      let options = {
+        form: response,
+        client: client,
+        chrome: true
+      };
+
+      devtools.TargetFactory.forRemoteTab(options).then(target => {
+        target.on("close", () => {
+          ok(true, "Target was closed");
+          DebuggerServer.destroy();
+          finish();
+        });
+        client.close();
+      });
+    });
+  });
+}
--- a/browser/devtools/framework/toolbox-hosts.js
+++ b/browser/devtools/framework/toolbox-hosts.js
@@ -2,17 +2,17 @@
  * 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/. */
 
 "use strict";
 
 const {Cu} = require("chrome");
 
 let promise = require("sdk/core/promise");
-let EventEmitter = require("devtools/shared/event-emitter");
+let EventEmitter = require("devtools/toolkit/event-emitter");
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource:///modules/devtools/DOMHelpers.jsm");
 
 /**
  * A toolbox host represents an object that contains a toolbox (e.g. the
  * sidebar or a separate window). Any host object should implement the
  * following functions:
--- a/browser/devtools/framework/toolbox-options.js
+++ b/browser/devtools/framework/toolbox-options.js
@@ -2,17 +2,17 @@
  * 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/. */
 
 "use strict";
 
 const {Cu, Cc, Ci} = require("chrome");
 
 let promise = require("sdk/core/promise");
-let EventEmitter = require("devtools/shared/event-emitter");
+let EventEmitter = require("devtools/toolkit/event-emitter");
 
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource:///modules/devtools/gDevTools.jsm");
 
 exports.OptionsPanel = OptionsPanel;
 
 XPCOMUtils.defineLazyGetter(this, "l10n", function() {
--- a/browser/devtools/framework/toolbox.js
+++ b/browser/devtools/framework/toolbox.js
@@ -6,17 +6,17 @@
 
 const MAX_ORDINAL = 99;
 const ZOOM_PREF = "devtools.toolbox.zoomValue";
 const MIN_ZOOM = 0.5;
 const MAX_ZOOM = 2;
 
 let {Cc, Ci, Cu} = require("chrome");
 let promise = require("sdk/core/promise");
-let EventEmitter = require("devtools/shared/event-emitter");
+let EventEmitter = require("devtools/toolkit/event-emitter");
 let Telemetry = require("devtools/shared/telemetry");
 let HUDService = require("devtools/webconsole/hudservice");
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource:///modules/devtools/gDevTools.jsm");
 Cu.import("resource:///modules/devtools/scratchpad-manager.jsm");
 Cu.import("resource:///modules/devtools/DOMHelpers.jsm");
--- a/browser/devtools/inspector/inspector-panel.js
+++ b/browser/devtools/inspector/inspector-panel.js
@@ -4,17 +4,17 @@
  * 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/. */
 
 const {Cc, Ci, Cu, Cr} = require("chrome");
 
 Cu.import("resource://gre/modules/Services.jsm");
 
 let promise = require("sdk/core/promise");
-let EventEmitter = require("devtools/shared/event-emitter");
+let EventEmitter = require("devtools/toolkit/event-emitter");
 let {CssLogic} = require("devtools/styleinspector/css-logic");
 
 loader.lazyGetter(this, "MarkupView", () => require("devtools/markupview/markup-view").MarkupView);
 loader.lazyGetter(this, "HTMLBreadcrumbs", () => require("devtools/inspector/breadcrumbs").HTMLBreadcrumbs);
 loader.lazyGetter(this, "ToolSidebar", () => require("devtools/framework/sidebar").ToolSidebar);
 loader.lazyGetter(this, "SelectorSearch", () => require("devtools/inspector/selector-search").SelectorSearch);
 
 const LAYOUT_CHANGE_TIMER = 250;
--- a/browser/devtools/markupview/html-editor.js
+++ b/browser/devtools/markupview/html-editor.js
@@ -2,17 +2,17 @@
  * 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/. */
  "use strict";
 
 const {Cu} = require("chrome");
 const Editor = require("devtools/sourceeditor/editor");
 Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource:///modules/devtools/shared/event-emitter.js");
+Cu.import("resource://gre/modules/devtools/event-emitter.js");
 
 exports.HTMLEditor = HTMLEditor;
 
 function ctrl(k) {
   return (Services.appinfo.OS == "Darwin" ? "Cmd-" : "Ctrl-") + k;
 }
 function stopPropagation(e) {
   e.stopPropagation();
@@ -178,9 +178,9 @@ HTMLEditor.prototype = {
     this.doc.defaultView.removeEventListener("resize",
       this.refresh, true);
     this.container.removeEventListener("click", this.hide, false);
     this.editorInner.removeEventListener("click", stopPropagation, false);
 
     this.hide(false);
     this.container.parentNode.removeChild(this.container);
   }
-};
\ No newline at end of file
+};
--- a/browser/devtools/markupview/markup-view.js
+++ b/browser/devtools/markupview/markup-view.js
@@ -17,17 +17,17 @@ const CONTAINER_FLASHING_DURATION = 500;
 const NEW_SELECTION_HIGHLIGHTER_TIMER = 1000;
 
 const {UndoStack} = require("devtools/shared/undo");
 const {editableField, InplaceEditor} = require("devtools/shared/inplace-editor");
 const {gDevTools} = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
 const {HTMLEditor} = require("devtools/markupview/html-editor");
 const promise = require("sdk/core/promise");
 const {Tooltip} = require("devtools/shared/widgets/Tooltip");
-const EventEmitter = require("devtools/shared/event-emitter");
+const EventEmitter = require("devtools/toolkit/event-emitter");
 
 Cu.import("resource://gre/modules/devtools/LayoutHelpers.jsm");
 Cu.import("resource://gre/modules/devtools/Templater.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 loader.lazyGetter(this, "DOMParser", function() {
  return Cc["@mozilla.org/xmlextras/domparser;1"].createInstance(Ci.nsIDOMParser);
--- a/browser/devtools/netmonitor/netmonitor-controller.js
+++ b/browser/devtools/netmonitor/netmonitor-controller.js
@@ -101,17 +101,17 @@ Cu.import("resource://gre/modules/Servic
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource:///modules/devtools/SideMenuWidget.jsm");
 Cu.import("resource:///modules/devtools/VariablesView.jsm");
 Cu.import("resource:///modules/devtools/VariablesViewController.jsm");
 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
 
 const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
 const promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
-const EventEmitter = require("devtools/shared/event-emitter");
+const EventEmitter = require("devtools/toolkit/event-emitter");
 const Editor = require("devtools/sourceeditor/editor");
 const {Tooltip} = require("devtools/shared/widgets/Tooltip");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Chart",
   "resource:///modules/devtools/Chart.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Task",
   "resource://gre/modules/Task.jsm");
--- a/browser/devtools/netmonitor/panel.js
+++ b/browser/devtools/netmonitor/panel.js
@@ -2,17 +2,17 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* 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/. */
 "use strict";
 
 const { Cc, Ci, Cu, Cr } = require("chrome");
 const { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
-const EventEmitter = require("devtools/shared/event-emitter");
+const EventEmitter = require("devtools/toolkit/event-emitter");
 
 function NetMonitorPanel(iframeWindow, toolbox) {
   this.panelWin = iframeWindow;
   this._toolbox = toolbox;
   this._destroyer = null;
 
   this._view = this.panelWin.NetMonitorView;
   this._controller = this.panelWin.NetMonitorController;
--- a/browser/devtools/profiler/cleopatra.js
+++ b/browser/devtools/profiler/cleopatra.js
@@ -1,17 +1,17 @@
 /* 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/. */
 
 "use strict";
 
 let { Cu }       = require("chrome");
 let { defer }    = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
-let EventEmitter = require("devtools/shared/event-emitter");
+let EventEmitter = require("devtools/toolkit/event-emitter");
 
 const { PROFILE_IDLE, PROFILE_COMPLETED, PROFILE_RUNNING } = require("devtools/profiler/consts");
 
 /**
  * An implementation of a profile visualization that uses Cleopatra.
  * It consists of an iframe with Cleopatra loaded in it and some
  * surrounding meta-data (such as UIDs).
  *
--- a/browser/devtools/profiler/controller.js
+++ b/browser/devtools/profiler/controller.js
@@ -15,17 +15,17 @@ if (isJSM) {
   this["loader"] = { lazyGetter: XPCOMUtils.defineLazyGetter.bind(XPCOMUtils) };
   this["require"] = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
 } else {
   var { Cu } = require("chrome");
 }
 
 const { L10N_BUNDLE } = require("devtools/profiler/consts");
 
-var EventEmitter = require("devtools/shared/event-emitter");
+var EventEmitter = require("devtools/toolkit/event-emitter");
 
 Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
 Cu.import("resource://gre/modules/devtools/Console.jsm");
 Cu.import("resource://gre/modules/AddonManager.jsm");
 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
 
 loader.lazyGetter(this, "L10N", () => new ViewHelpers.L10N(L10N_BUNDLE));
 
--- a/browser/devtools/profiler/panel.js
+++ b/browser/devtools/profiler/panel.js
@@ -11,17 +11,17 @@ const {
   PROFILE_RUNNING,
   PROFILE_COMPLETED,
   SHOW_PLATFORM_DATA,
   L10N_BUNDLE
 } = require("devtools/profiler/consts");
 
 const { TextEncoder } = Cu.import("resource://gre/modules/commonjs/toolkit/loader.js", {});
 
-var EventEmitter = require("devtools/shared/event-emitter");
+var EventEmitter = require("devtools/toolkit/event-emitter");
 var Cleopatra    = require("devtools/profiler/cleopatra");
 var Sidebar      = require("devtools/profiler/sidebar");
 var ProfilerController = require("devtools/profiler/controller");
 var { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
 
 Cu.import("resource:///modules/devtools/gDevTools.jsm");
 Cu.import("resource://gre/modules/devtools/Console.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
--- a/browser/devtools/profiler/sidebar.js
+++ b/browser/devtools/profiler/sidebar.js
@@ -1,16 +1,16 @@
 /* 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/. */
 
 "use strict";
 
 let { Cu } = require("chrome");
-let EventEmitter = require("devtools/shared/event-emitter");
+let EventEmitter = require("devtools/toolkit/event-emitter");
 
 Cu.import("resource:///modules/devtools/SideMenuWidget.jsm");
 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
 
 const {
   PROFILE_IDLE,
   PROFILE_COMPLETED,
   PROFILE_RUNNING,
--- a/browser/devtools/responsivedesign/responsivedesign.jsm
+++ b/browser/devtools/responsivedesign/responsivedesign.jsm
@@ -6,17 +6,17 @@
 
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource:///modules/devtools/gDevTools.jsm");
 Cu.import("resource:///modules/devtools/FloatingScrollbars.jsm");
-Cu.import("resource:///modules/devtools/shared/event-emitter.js");
+Cu.import("resource://gre/modules/devtools/event-emitter.js");
 
 var require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
 let Telemetry = require("devtools/shared/telemetry");
 let {TouchEventHandler} = require("devtools/touch-events");
 
 this.EXPORTED_SYMBOLS = ["ResponsiveUIManager"];
 
 const MIN_WIDTH = 50;
--- a/browser/devtools/scratchpad/scratchpad-panel.js
+++ b/browser/devtools/scratchpad/scratchpad-panel.js
@@ -1,17 +1,17 @@
 /* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* 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/. */
 "use strict";
 
 const {Cu} = require("chrome");
-const EventEmitter = require("devtools/shared/event-emitter");
+const EventEmitter = require("devtools/toolkit/event-emitter");
 const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
 
 
 function ScratchpadPanel(iframeWindow, toolbox) {
   let { Scratchpad } = iframeWindow;
   this._toolbox = toolbox;
   this.panelWin = iframeWindow;
   this.scratchpad = Scratchpad;
--- a/browser/devtools/shadereditor/panel.js
+++ b/browser/devtools/shadereditor/panel.js
@@ -2,17 +2,17 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* 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/. */
 "use strict";
 
 const { Cc, Ci, Cu, Cr } = require("chrome");
 const promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
-const EventEmitter = require("devtools/shared/event-emitter");
+const EventEmitter = require("devtools/toolkit/event-emitter");
 const { WebGLFront } = require("devtools/server/actors/webgl");
 
 function ShaderEditorPanel(iframeWindow, toolbox) {
   this.panelWin = iframeWindow;
   this._toolbox = toolbox;
   this._destroyer = null;
 
   EventEmitter.decorate(this);
--- a/browser/devtools/shadereditor/shadereditor.js
+++ b/browser/devtools/shadereditor/shadereditor.js
@@ -9,17 +9,17 @@ Cu.import("resource://gre/modules/Servic
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://gre/modules/devtools/Loader.jsm");
 Cu.import("resource:///modules/devtools/SideMenuWidget.jsm");
 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
 
 const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
 const promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
-const EventEmitter = require("devtools/shared/event-emitter");
+const EventEmitter = require("devtools/toolkit/event-emitter");
 const {Tooltip} = require("devtools/shared/widgets/Tooltip");
 const Editor = require("devtools/sourceeditor/editor");
 
 // The panel's window global is an EventEmitter firing the following events:
 const EVENTS = {
   // When new programs are received from the server.
   NEW_PROGRAM: "ShaderEditor:NewProgram",
   PROGRAMS_ADDED: "ShaderEditor:ProgramsAdded",
--- a/browser/devtools/shared/DeveloperToolbar.jsm
+++ b/browser/devtools/shared/DeveloperToolbar.jsm
@@ -30,17 +30,17 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 
 XPCOMUtils.defineLazyModuleGetter(this, "devtools",
                                   "resource://gre/modules/devtools/Loader.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "require",
                                   "resource://gre/modules/devtools/Require.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
-                                  "resource:///modules/devtools/shared/event-emitter.js");
+                                  "resource://gre/modules/devtools/event-emitter.js");
 
 XPCOMUtils.defineLazyGetter(this, "prefBranch", function() {
   let prefService = Cc["@mozilla.org/preferences-service;1"]
                     .getService(Ci.nsIPrefService);
   return prefService.getBranch(null)
                     .QueryInterface(Ci.nsIPrefBranch2);
 });
 
--- a/browser/devtools/shared/inplace-editor.js
+++ b/browser/devtools/shared/inplace-editor.js
@@ -35,17 +35,17 @@ const CONTENT_TYPES = {
 };
 const MAX_POPUP_ENTRIES = 10;
 
 const FOCUS_FORWARD = Ci.nsIFocusManager.MOVEFOCUS_FORWARD;
 const FOCUS_BACKWARD = Ci.nsIFocusManager.MOVEFOCUS_BACKWARD;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource:///modules/devtools/shared/event-emitter.js");
+Cu.import("resource://gre/modules/devtools/event-emitter.js");
 
 /**
  * Mark a span editable.  |editableField| will listen for the span to
  * be focused and create an InlineEditor to handle text input.
  * Changes will be committed when the InlineEditor's input is blurred
  * or dropped when the user presses escape.
  *
  * @param {object} aOptions
--- a/browser/devtools/shared/observable-object.js
+++ b/browser/devtools/shared/observable-object.js
@@ -25,17 +25,17 @@
  *   emitter.on("get", console.log);
  *   let obj = emitter.object;
  *   obj.x.y[0] = 50;
  *
  */
 
 "use strict";
 
-const EventEmitter = require("devtools/shared/event-emitter");
+const EventEmitter = require("devtools/toolkit/event-emitter");
 
 function ObservableObject(object = {}) {
   EventEmitter.decorate(this);
   let handler = new Handler(this);
   this.object = new Proxy(object, handler);
   handler._wrappers.set(this.object, object);
   handler._paths.set(object, []);
 }
--- a/browser/devtools/shared/test/browser.ini
+++ b/browser/devtools/shared/test/browser.ini
@@ -4,17 +4,16 @@ support-files =
   browser_layoutHelpers_iframe.html
   browser_templater_basic.html
   browser_toolbar_basic.html
   browser_toolbar_webconsole_errors_count.html
   head.js
   leakhunt.js
 
 [browser_css_color.js]
-[browser_eventemitter_basic.js]
 [browser_layoutHelpers.js]
 [browser_observableobject.js]
 [browser_outputparser.js]
 [browser_require_basic.js]
 [browser_telemetry_button_paintflashing.js]
 [browser_telemetry_button_responsive.js]
 [browser_telemetry_button_scratchpad.js]
 [browser_telemetry_button_tilt.js]
--- a/browser/devtools/shared/widgets/BreadcrumbsWidget.jsm
+++ b/browser/devtools/shared/widgets/BreadcrumbsWidget.jsm
@@ -6,17 +6,17 @@
 "use strict";
 
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 const ENSURE_SELECTION_VISIBLE_DELAY = 50; // ms
 
 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
-Cu.import("resource:///modules/devtools/shared/event-emitter.js");
+Cu.import("resource://gre/modules/devtools/event-emitter.js");
 
 this.EXPORTED_SYMBOLS = ["BreadcrumbsWidget"];
 
 /**
  * A breadcrumb-like list of items.
  *
  * Note: this widget should be used in tandem with the WidgetMethods in
  * ViewHelpers.jsm.
--- a/browser/devtools/shared/widgets/Chart.jsm
+++ b/browser/devtools/shared/widgets/Chart.jsm
@@ -15,17 +15,17 @@ const TAU = PI * 2;
 const EPSILON = 0.0000001;
 const NAMED_SLICE_MIN_ANGLE = TAU / 8;
 const NAMED_SLICE_TEXT_DISTANCE_RATIO = 1.9;
 const HOVERED_SLICE_TRANSLATE_DISTANCE_RATIO = 20;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
-Cu.import("resource:///modules/devtools/shared/event-emitter.js");
+Cu.import("resource://gre/modules/devtools/event-emitter.js");
 
 this.EXPORTED_SYMBOLS = ["Chart"];
 
 /**
  * Localization convenience methods.
  */
 let L10N = new ViewHelpers.L10N(NET_STRINGS_URI);
 
--- a/browser/devtools/shared/widgets/FastListWidget.js
+++ b/browser/devtools/shared/widgets/FastListWidget.js
@@ -1,16 +1,16 @@
 /* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* 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/. */
 "use strict";
 
-const EventEmitter = require("devtools/shared/event-emitter");
+const EventEmitter = require("devtools/toolkit/event-emitter");
 const { Cu, Ci } = require("chrome");
 const { ViewHelpers } = Cu.import("resource:///modules/devtools/ViewHelpers.jsm", {});
 
 /**
  * A list menu widget that attempts to be very fast.
  *
  * Note: this widget should be used in tandem with the WidgetMethods in
  * ViewHelpers.jsm.
--- a/browser/devtools/shared/widgets/SideMenuWidget.jsm
+++ b/browser/devtools/shared/widgets/SideMenuWidget.jsm
@@ -4,17 +4,17 @@
  * 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/. */
 "use strict";
 
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
-Cu.import("resource:///modules/devtools/shared/event-emitter.js");
+Cu.import("resource://gre/modules/devtools/event-emitter.js");
 
 this.EXPORTED_SYMBOLS = ["SideMenuWidget"];
 
 /**
  * A simple side menu, with the ability of grouping menu items.
  *
  * Note: this widget should be used in tandem with the WidgetMethods in
  * ViewHelpers.jsm.
--- a/browser/devtools/shared/widgets/Spectrum.js
+++ b/browser/devtools/shared/widgets/Spectrum.js
@@ -1,15 +1,15 @@
 /* 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/. */
 
 "use strict";
 
-const EventEmitter = require("devtools/shared/event-emitter");
+const EventEmitter = require("devtools/toolkit/event-emitter");
 
 /**
  * Spectrum creates a color picker widget in any container you give it.
  *
  * Simple usage example:
  *
  * const {Spectrum} = require("devtools/shared/widgets/Spectrum");
  * let s = new Spectrum(containerElement, [255, 126, 255, 1]);
--- a/browser/devtools/shared/widgets/Tooltip.js
+++ b/browser/devtools/shared/widgets/Tooltip.js
@@ -4,17 +4,17 @@
 
 "use strict";
 
 const {Cc, Cu, Ci} = require("chrome");
 const promise = require("sdk/core/promise");
 const IOService = Cc["@mozilla.org/network/io-service;1"]
   .getService(Ci.nsIIOService);
 const {Spectrum} = require("devtools/shared/widgets/Spectrum");
-const EventEmitter = require("devtools/shared/event-emitter");
+const EventEmitter = require("devtools/toolkit/event-emitter");
 const {colorUtils} = require("devtools/css-color");
 const Heritage = require("sdk/core/heritage");
 const {CSSTransformPreviewer} = require("devtools/shared/widgets/CSSTransformPreviewer");
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "setNamedTimeout",
--- a/browser/devtools/shared/widgets/VariablesView.jsm
+++ b/browser/devtools/shared/widgets/VariablesView.jsm
@@ -16,17 +16,17 @@ const APPEND_PAGE_SIZE_DEFAULT = 500;
 const PAGE_SIZE_SCROLL_HEIGHT_RATIO = 100;
 const PAGE_SIZE_MAX_JUMPS = 30;
 const SEARCH_ACTION_MAX_DELAY = 300; // ms
 const ITEM_FLASH_DURATION = 300 // ms
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
-Cu.import("resource:///modules/devtools/shared/event-emitter.js");
+Cu.import("resource://gre/modules/devtools/event-emitter.js");
 Cu.import("resource://gre/modules/devtools/DevToolsUtils.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js").Promise;
 
 XPCOMUtils.defineLazyModuleGetter(this, "devtools",
   "resource://gre/modules/devtools/Loader.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
--- a/browser/devtools/sourceeditor/editor.js
+++ b/browser/devtools/sourceeditor/editor.js
@@ -14,17 +14,17 @@ const AUTO_CLOSE  = "devtools.editor.aut
 const L10N_BUNDLE = "chrome://browser/locale/devtools/sourceeditor.properties";
 const XUL_NS      = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
 // Maximum allowed margin (in number of lines) from top or bottom of the editor
 // while shifting to a line which was initially out of view.
 const MAX_VERTICAL_OFFSET = 3;
 
 const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
-const events  = require("devtools/shared/event-emitter");
+const events  = require("devtools/toolkit/event-emitter");
 
 Cu.import("resource://gre/modules/Services.jsm");
 const L10N = Services.strings.createBundle(L10N_BUNDLE);
 
 // CM_STYLES, CM_SCRIPTS and CM_IFRAME represent the HTML,
 // JavaScript and CSS that is injected into an iframe in
 // order to initialize a CodeMirror instance.
 
--- a/browser/devtools/styleeditor/StyleEditorUI.jsm
+++ b/browser/devtools/styleeditor/StyleEditorUI.jsm
@@ -11,17 +11,17 @@ const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/PluralForm.jsm");
 Cu.import("resource://gre/modules/NetUtil.jsm");
 Cu.import("resource://gre/modules/osfile.jsm");
 let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js").Promise;
-Cu.import("resource:///modules/devtools/shared/event-emitter.js");
+Cu.import("resource://gre/modules/devtools/event-emitter.js");
 Cu.import("resource:///modules/devtools/gDevTools.jsm");
 Cu.import("resource:///modules/devtools/StyleEditorUtil.jsm");
 Cu.import("resource:///modules/devtools/SplitView.jsm");
 Cu.import("resource:///modules/devtools/StyleSheetEditor.jsm");
 
 const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
 const { PrefObserver, PREF_ORIG_SOURCES } = require("devtools/styleeditor/utils");
 
--- a/browser/devtools/styleeditor/StyleSheetEditor.jsm
+++ b/browser/devtools/styleeditor/StyleSheetEditor.jsm
@@ -16,17 +16,17 @@ const Editor  = require("devtools/source
 const promise = require("sdk/core/promise");
 const {CssLogic} = require("devtools/styleinspector/css-logic");
 const AutoCompleter = require("devtools/sourceeditor/autocomplete");
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/FileUtils.jsm");
 Cu.import("resource://gre/modules/NetUtil.jsm");
 Cu.import("resource://gre/modules/osfile.jsm");
-Cu.import("resource:///modules/devtools/shared/event-emitter.js");
+Cu.import("resource://gre/modules/devtools/event-emitter.js");
 Cu.import("resource:///modules/devtools/StyleEditorUtil.jsm");
 
 const LOAD_ERROR = "error-load";
 const SAVE_ERROR = "error-save";
 
 // max update frequency in ms (avoid potential typing lag and/or flicker)
 // @see StyleEditor.updateStylesheet
 const UPDATE_STYLESHEET_THROTTLE_DELAY = 500;
--- a/browser/devtools/styleeditor/styleeditor-panel.js
+++ b/browser/devtools/styleeditor/styleeditor-panel.js
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const {Cc, Ci, Cu, Cr} = require("chrome");
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 let promise = require("sdk/core/promise");
-let EventEmitter = require("devtools/shared/event-emitter");
+let EventEmitter = require("devtools/toolkit/event-emitter");
 
 Cu.import("resource:///modules/devtools/StyleEditorUI.jsm");
 Cu.import("resource:///modules/devtools/StyleEditorUtil.jsm");
 
 loader.lazyGetter(this, "StyleSheetsFront",
   () => require("devtools/server/actors/stylesheets").StyleSheetsFront);
 
 loader.lazyGetter(this, "StyleEditorFront",
--- a/browser/devtools/styleeditor/utils.js
+++ b/browser/devtools/styleeditor/utils.js
@@ -2,17 +2,17 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* 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/. */
 
 const {Cc, Ci, Cu, Cr} = require("chrome");
 
 Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource:///modules/devtools/shared/event-emitter.js");
+Cu.import("resource://gre/modules/devtools/event-emitter.js");
 
 exports.PREF_ORIG_SOURCES = "devtools.styleeditor.source-maps-enabled";
 
 /**
  * A PreferenceObserver observes a pref branch for pref changes.
  * It emits an event for each preference change.
  */
 function PrefObserver(branchName) {
--- a/browser/devtools/styleinspector/computed-view.js
+++ b/browser/devtools/styleinspector/computed-view.js
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const {Cc, Ci, Cu} = require("chrome");
 
 const ToolDefinitions = require("main").Tools;
 const {CssLogic} = require("devtools/styleinspector/css-logic");
 const {ELEMENT_STYLE} = require("devtools/server/actors/styles");
 const promise = require("sdk/core/promise");
-const {EventEmitter} = require("devtools/shared/event-emitter");
+const {EventEmitter} = require("devtools/toolkit/event-emitter");
 const {OutputParser} = require("devtools/output-parser");
 const {Tooltip} = require("devtools/shared/widgets/Tooltip");
 const {PrefObserver, PREF_ORIG_SOURCES} = require("devtools/styleeditor/utils");
 const {gDevTools} = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/PluralForm.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
--- a/browser/devtools/tilt/tilt.js
+++ b/browser/devtools/tilt/tilt.js
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 const {Cu} = require("chrome");
 
 let {TiltVisualizer} = require("devtools/tilt/tilt-visualizer");
 let TiltGL = require("devtools/tilt/tilt-gl");
 let TiltUtils = require("devtools/tilt/tilt-utils");
-let EventEmitter = require("devtools/shared/event-emitter");
+let EventEmitter = require("devtools/toolkit/event-emitter");
 let Telemetry = require("devtools/shared/telemetry");
 
 Cu.import("resource://gre/modules/Services.jsm");
 
 // Tilt notifications dispatched through the nsIObserverService.
 const TILT_NOTIFICATIONS = {
   // Called early in the startup of a new tilt instance
   STARTUP: "tilt-startup",
--- a/browser/devtools/webconsole/panel.js
+++ b/browser/devtools/webconsole/panel.js
@@ -4,17 +4,17 @@
 
 "use strict";
 
 const {Cc, Ci, Cu} = require("chrome");
 
 loader.lazyImporter(this, "devtools", "resource://gre/modules/devtools/Loader.jsm");
 loader.lazyImporter(this, "promise", "resource://gre/modules/Promise.jsm", "Promise");
 loader.lazyGetter(this, "HUDService", () => require("devtools/webconsole/hudservice"));
-loader.lazyGetter(this, "EventEmitter", () => require("devtools/shared/event-emitter"));
+loader.lazyGetter(this, "EventEmitter", () => require("devtools/toolkit/event-emitter"));
 loader.lazyImporter(this, "gDevTools", "resource:///modules/devtools/gDevTools.jsm");
 
 /**
  * A DevToolPanel that controls the Web Console.
  */
 function WebConsolePanel(iframeWindow, toolbox)
 {
   this._frameWindow = iframeWindow;
--- a/browser/devtools/webconsole/test/browser.ini
+++ b/browser/devtools/webconsole/test/browser.ini
@@ -263,10 +263,11 @@ run-if = os == "mac"
 [browser_webconsole_autocomplete_popup_close_on_tab_switch.js]
 [browser_console_hide_jsterm_when_devtools_chrome_enabled_false.js]
 [browser_webconsole_output_01.js]
 [browser_webconsole_output_02.js]
 [browser_webconsole_output_03.js]
 [browser_webconsole_output_04.js]
 [browser_webconsole_output_events.js]
 [browser_console_variables_view_highlighter.js]
+[browser_webconsole_start_netmon_first.js]
 [browser_webconsole_console_trace_duplicates.js]
 [browser_webconsole_cd_iframe.js]
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_start_netmon_first.js
@@ -0,0 +1,37 @@
+/* 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/. */
+
+// Check that the webconsole works if the network monitor is first opened, then
+// the user switches to the webconsole. See bug 970914.
+
+function test() {
+  Task.spawn(runner).then(finishTest);
+
+  function* runner() {
+    const {tab} = yield loadTab("data:text/html;charset=utf8,<p>hello");
+
+    const target = TargetFactory.forTab(tab);
+    const toolbox = yield gDevTools.showToolbox(target, "netmonitor");
+
+    const hud = yield openConsole(tab);
+
+    hud.jsterm.execute("console.log('foobar bug970914')");
+
+    yield waitForMessages({
+      webconsole: hud,
+      messages: [{
+        name: "console.log",
+        text: "foobar bug970914",
+        category: CATEGORY_WEBDEV,
+        severity: SEVERITY_LOG,
+      }],
+    });
+
+    let text = hud.outputNode.textContent;
+    isnot(text.indexOf("foobar bug970914"), -1, "console.log message confirmed");
+    ok(!/logging API|disabled by a script/i.test(text),
+       "no warning about disabled console API");
+  }
+}
+
--- a/browser/devtools/webconsole/webconsole.js
+++ b/browser/devtools/webconsole/webconsole.js
@@ -10,17 +10,17 @@ const {Cc, Ci, Cu} = require("chrome");
 
 let WebConsoleUtils = require("devtools/toolkit/webconsole/utils").Utils;
 
 loader.lazyServiceGetter(this, "clipboardHelper",
                          "@mozilla.org/widget/clipboardhelper;1",
                          "nsIClipboardHelper");
 loader.lazyImporter(this, "Services", "resource://gre/modules/Services.jsm");
 loader.lazyImporter(this, "promise", "resource://gre/modules/Promise.jsm", "Promise");
-loader.lazyGetter(this, "EventEmitter", () => require("devtools/shared/event-emitter"));
+loader.lazyGetter(this, "EventEmitter", () => require("devtools/toolkit/event-emitter"));
 loader.lazyGetter(this, "AutocompletePopup",
                   () => require("devtools/shared/autocomplete-popup").AutocompletePopup);
 loader.lazyGetter(this, "ToolSidebar",
                   () => require("devtools/framework/sidebar").ToolSidebar);
 loader.lazyGetter(this, "NetworkPanel",
                   () => require("devtools/webconsole/network-panel").NetworkPanel);
 loader.lazyGetter(this, "ConsoleOutput",
                   () => require("devtools/webconsole/console-output").ConsoleOutput);
--- a/browser/extensions/pdfjs/README.mozilla
+++ b/browser/extensions/pdfjs/README.mozilla
@@ -1,4 +1,4 @@
 This is the pdf.js project output, https://github.com/mozilla/pdf.js
 
-Current extension version is: 0.8.990
+Current extension version is: 0.8.1041
 
--- a/browser/extensions/pdfjs/components/PdfStreamConverter.js
+++ b/browser/extensions/pdfjs/components/PdfStreamConverter.js
@@ -536,28 +536,40 @@ var RangedChromeActions = (function Rang
           // manually to fetch the PDF in chunks.
           return;
         }
         this.headers[aHeader] = aValue;
       }
     };
     originalRequest.visitRequestHeaders(httpHeaderVisitor);
 
+    var self = this;
+    var xhr_onreadystatechange = function xhr_onreadystatechange() {
+      if (this.readyState === 1) { // LOADING
+        var netChannel = this.channel;
+        if ('nsIPrivateBrowsingChannel' in Ci &&
+            netChannel instanceof Ci.nsIPrivateBrowsingChannel) {
+          var docIsPrivate = self.isInPrivateBrowsing();
+          netChannel.setPrivate(docIsPrivate);
+        }
+      }
+    };
     var getXhr = function getXhr() {
       const XMLHttpRequest = Components.Constructor(
           '@mozilla.org/xmlextras/xmlhttprequest;1');
-      return new XMLHttpRequest();
+      var xhr = new XMLHttpRequest();
+      xhr.addEventListener('readystatechange', xhr_onreadystatechange);
+      return xhr;
     };
 
     this.networkManager = new NetworkManager(this.pdfUrl, {
       httpHeaders: httpHeaderVisitor.headers,
       getXhr: getXhr
     });
 
-    var self = this;
     // If we are in range request mode, this means we manually issued xhr
     // requests, which we need to abort when we leave the page
     domWindow.addEventListener('unload', function unload(e) {
       self.networkManager.abortAllRequests();
       domWindow.removeEventListener(e.type, unload);
     });
   }
 
--- a/browser/extensions/pdfjs/content/build/pdf.js
+++ b/browser/extensions/pdfjs/content/build/pdf.js
@@ -15,18 +15,18 @@
  * limitations under the License.
  */
 
 // Initializing PDFJS global object (if still undefined)
 if (typeof PDFJS === 'undefined') {
   (typeof window !== 'undefined' ? window : this).PDFJS = {};
 }
 
-PDFJS.version = '0.8.990';
-PDFJS.build = '54f6291';
+PDFJS.version = '0.8.1041';
+PDFJS.build = '2188bcb';
 
 (function pdfjsWrapper() {
   // Use strict in our context only - users might not want it
   'use strict';
 
 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 /* Copyright 2012 Mozilla Foundation
@@ -3304,17 +3304,17 @@ var LinkAnnotation = (function LinkAnnot
     var action = dict.get('A');
     if (action) {
       var linkType = action.get('S').name;
       if (linkType === 'URI') {
         var url = action.get('URI');
         if (isName(url)) {
           // Some bad PDFs do not put parentheses around relative URLs.
           url = '/' + url.name;
-        } else {
+        } else if (url) {
           url = addDefaultProtocolToUrl(url);
         }
         // TODO: pdf spec mentions urls can be relative to a Base
         // entry in the dictionary.
         if (!isValidUrl(url, false)) {
           url = '';
         }
         data.url = url;
@@ -3344,17 +3344,17 @@ var LinkAnnotation = (function LinkAnnot
       // simple destination link
       var dest = dict.get('Dest');
       data.dest = isName(dest) ? dest.name : dest;
     }
   }
 
   // Lets URLs beginning with 'www.' default to using the 'http://' protocol.
   function addDefaultProtocolToUrl(url) {
-    if (url.indexOf('www.') === 0) {
+    if (url && url.indexOf('www.') === 0) {
       return ('http://' + url);
     }
     return url;
   }
 
   Util.inherit(LinkAnnotation, Annotation, {
     hasOperatorList: function LinkAnnotation_hasOperatorList() {
       return false;
@@ -4081,16 +4081,17 @@ var WorkerTransport = (function WorkerTr
         messageHandler.on('RequestDataRange',
           function transportDataRange(data) {
             pdfDataRangeTransport.requestDataRange(data.begin, data.end);
           }, this);
       }
 
       messageHandler.on('GetDoc', function transportDoc(data) {
         var pdfInfo = data.pdfInfo;
+        this.numPages = data.pdfInfo.numPages;
         var pdfDocument = new PDFDocumentProxy(pdfInfo, this);
         this.pdfDocument = pdfDocument;
         this.workerReadyPromise.resolve(pdfDocument);
       }, this);
 
       messageHandler.on('NeedPassword', function transportPassword(data) {
         if (this.passwordCallback) {
           return this.passwordCallback(updatePassword,
@@ -4285,16 +4286,23 @@ var WorkerTransport = (function WorkerTr
 
     getData: function WorkerTransport_getData(promise) {
       this.messageHandler.send('GetData', null, function(data) {
         promise.resolve(data);
       });
     },
 
     getPage: function WorkerTransport_getPage(pageNumber, promise) {
+      if (pageNumber <= 0 || pageNumber > this.numPages ||
+          (pageNumber|0) !== pageNumber) {
+        var pagePromise = new PDFJS.LegacyPromise();
+        pagePromise.reject(new Error('Invalid page request'));
+        return pagePromise;
+      }
+
       var pageIndex = pageNumber - 1;
       if (pageIndex in this.pagePromises)
         return this.pagePromises[pageIndex];
       var promise = new PDFJS.LegacyPromise();
       this.pagePromises[pageIndex] = promise;
       this.messageHandler.send('GetPageRequest', { pageIndex: pageIndex });
       return promise;
     },
--- a/browser/extensions/pdfjs/content/build/pdf.worker.js
+++ b/browser/extensions/pdfjs/content/build/pdf.worker.js
@@ -15,18 +15,18 @@
  * limitations under the License.
  */
 
 // Initializing PDFJS global object (if still undefined)
 if (typeof PDFJS === 'undefined') {
   (typeof window !== 'undefined' ? window : this).PDFJS = {};
 }
 
-PDFJS.version = '0.8.990';
-PDFJS.build = '54f6291';
+PDFJS.version = '0.8.1041';
+PDFJS.build = '2188bcb';
 
 (function pdfjsWrapper() {
   // Use strict in our context only - users might not want it
   'use strict';
 
 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 /* Copyright 2012 Mozilla Foundation
@@ -3304,17 +3304,17 @@ var LinkAnnotation = (function LinkAnnot
     var action = dict.get('A');
     if (action) {
       var linkType = action.get('S').name;
       if (linkType === 'URI') {
         var url = action.get('URI');
         if (isName(url)) {
           // Some bad PDFs do not put parentheses around relative URLs.
           url = '/' + url.name;
-        } else {
+        } else if (url) {
           url = addDefaultProtocolToUrl(url);
         }
         // TODO: pdf spec mentions urls can be relative to a Base
         // entry in the dictionary.
         if (!isValidUrl(url, false)) {
           url = '';
         }
         data.url = url;
@@ -3344,17 +3344,17 @@ var LinkAnnotation = (function LinkAnnot
       // simple destination link
       var dest = dict.get('Dest');
       data.dest = isName(dest) ? dest.name : dest;
     }
   }
 
   // Lets URLs beginning with 'www.' default to using the 'http://' protocol.
   function addDefaultProtocolToUrl(url) {
-    if (url.indexOf('www.') === 0) {
+    if (url && url.indexOf('www.') === 0) {
       return ('http://' + url);
     }
     return url;
   }
 
   Util.inherit(LinkAnnotation, Annotation, {
     hasOperatorList: function LinkAnnotation_hasOperatorList() {
       return false;
@@ -3872,16 +3872,19 @@ var ChunkedStreamManager = (function Chu
     }
   };
 
   return ChunkedStreamManager;
 })();
 
 
 
+// The maximum number of bytes fetched per range request
+var RANGE_CHUNK_SIZE = 65536;
+
 // TODO(mack): Make use of PDFJS.Util.inherit() when it becomes available
 var BasePdfManager = (function BasePdfManagerClosure() {
   function BasePdfManager() {
     throw new Error('Cannot initialize BaseManagerManager');
   }
 
   BasePdfManager.prototype = {
     onLoadedStream: function BasePdfManager_onLoadedStream() {
@@ -3985,32 +3988,29 @@ var LocalPdfManager = (function LocalPdf
       function LocalPdfManager_terminate() {
     return;
   };
 
   return LocalPdfManager;
 })();
 
 var NetworkPdfManager = (function NetworkPdfManagerClosure() {
-
-  var CHUNK_SIZE = 65536;
-
   function NetworkPdfManager(args, msgHandler) {
 
     this.msgHandler = msgHandler;
 
     var params = {
       msgHandler: msgHandler,
       httpHeaders: args.httpHeaders,
       withCredentials: args.withCredentials,
       chunkedViewerLoading: args.chunkedViewerLoading,
       disableAutoFetch: args.disableAutoFetch,
       initialData: args.initialData
     };
-    this.streamManager = new ChunkedStreamManager(args.length, CHUNK_SIZE,
+    this.streamManager = new ChunkedStreamManager(args.length, RANGE_CHUNK_SIZE,
                                                   args.url, params);
 
     this.pdfModel = new PDFDocument(this, this.streamManager.getStream(),
                                     args.password);
   }
 
   NetworkPdfManager.prototype = Object.create(BasePdfManager.prototype);
   NetworkPdfManager.prototype.constructor = NetworkPdfManager;
@@ -31948,57 +31948,95 @@ var Lexer = (function LexerClosure() {
     }
     return -1;
   }
 
   Lexer.prototype = {
     nextChar: function Lexer_nextChar() {
       return (this.currentChar = this.stream.getByte());
     },
+    peekChar: function Lexer_peekChar() {
+      return this.stream.peekBytes(1)[0];
+    },
     getNumber: function Lexer_getNumber() {
-      var floating = false;
       var ch = this.currentChar;
-      var allDigits = ch >= 0x30 && ch <= 0x39;
-      var strBuf = this.strBuf;
-      strBuf.length = 0;
-      strBuf.push(String.fromCharCode(ch));
+      var eNotation = false;
+      var divideBy = 0; // different from 0 if it's a floating point value
+
+      var sign = 1;
+
+
+      if (ch === 0x2D) { // '-'
+        sign = -1;
+        ch = this.nextChar();
+      } else if (ch === 0x2B) { // '+'
+        ch = this.nextChar();
+      }
+      if (ch === 0x2E) { // '.'
+        divideBy = 10;
+        ch = this.nextChar();
+      }
+
+      if (ch < 0x30 || ch > 0x39) { // '0' - '9'
+        error('Invalid number: ' + String.fromCharCode(ch));
+        return 0;
+      }
+
+      var baseValue = ch - 0x30; // '0'
+      var powerValue = 0;
+      var powerValueSign = 1;
+
       while ((ch = this.nextChar()) >= 0) {
-        if (ch >= 0x30 && ch <= 0x39) { // '0'-'9'
-          strBuf.push(String.fromCharCode(ch));
-        } else if (ch === 0x2E && !floating) { // '.'
-          strBuf.push('.');
-          floating = true;
-          allDigits = false;
+        if (0x30 <= ch && ch <= 0x39) { // '0' - '9'
+          var currentDigit = ch - 0x30; // '0'
+          if (eNotation) { // We are after an 'e' or 'E'
+            powerValue = powerValue * 10 + currentDigit;
+          } else {
+            if (divideBy !== 0) { // We are after a point
+              divideBy *= 10;
+            }
+            baseValue = baseValue * 10 + currentDigit;
+          }
+        } else if (ch === 0x2E) { // '.'
+          if (divideBy === 0) {
+            divideBy = 1;
+          } else {
+            // A number can have only one '.'
+            break;
+          }
         } else if (ch === 0x2D) { // '-'
           // ignore minus signs in the middle of numbers to match
           // Adobe's behavior
           warn('Badly formated number');
-          allDigits = false;
         } else if (ch === 0x45 || ch === 0x65) { // 'E', 'e'
-          floating = true;
-          allDigits = false;
+          // 'E' can be either a scientific notation or the beginning of a new
+          // operator
+          var hasE = true;
+          ch = this.peekChar();
+          if (ch === 0x2B || ch === 0x2D) { // '+', '-'
+            powerValueSign = (ch === 0x2D) ? -1 : 1;
+            this.nextChar(); // Consume the sign character
+          } else if (ch < 0x30 || ch > 0x39) { // '0' - '9'
+            // The 'E' must be the beginning of a new operator
+            break;
+          }
+          eNotation = true;
         } else {
           // the last character doesn't belong to us
           break;
         }
       }
-      var value;
-      if (allDigits) {
-        value = 0;
-        var charCodeOfZero = 48;    // '0'
-        for (var i = 0, ii = strBuf.length; i < ii; i++) {
-          value = value * 10 + (strBuf[i].charCodeAt(0) - charCodeOfZero);
-        }
-      } else {
-        value = parseFloat(strBuf.join(''));
-        if (isNaN(value)) {
-          error('Invalid floating point number: ' + value);
-        }
-      }
-      return value;
+
+      if (divideBy !== 0) {
+        baseValue /= divideBy;
+      }
+      if (eNotation) {
+        baseValue *= Math.pow(10, powerValueSign * powerValue);
+      }
+      return sign * baseValue;
     },
     getString: function Lexer_getString() {
       var numParen = 1;
       var done = false;
       var strBuf = this.strBuf;
       strBuf.length = 0;
 
       var ch = this.nextChar();
@@ -34943,24 +34981,30 @@ var WorkerMessageHandler = PDFJS.WorkerM
             return;
           }
 
           var length = fullRequestXhr.getResponseHeader('Content-Length');
           length = parseInt(length, 10);
           if (!isInt(length)) {
             return;
           }
+          source.length = length;
+          if (length <= 2 * RANGE_CHUNK_SIZE) {
+            // The file size is smaller than the size of two chunks, so it does
+            // not make any sense to abort the request and retry with a range
+            // request.
+            return;
+          }
 
           // NOTE: by cancelling the full request, and then issuing range
           // requests, there will be an issue for sites where you can only
           // request the pdf once. However, if this is the case, then the
           // server should not be returning that it can support range requests.
           networkManager.abortRequest(fullRequestXhrId);
 
-          source.length = length;
           try {
             pdfManager = new NetworkPdfManager(source, handler);
             pdfManagerPromise.resolve(pdfManager);
           } catch (ex) {
             pdfManagerPromise.reject(ex);
           }
         },
 
@@ -35154,18 +35198,18 @@ var WorkerMessageHandler = PDFJS.WorkerM
     handler.on('RenderPageRequest', function wphSetupRenderPage(data) {
       pdfManager.getPage(data.pageIndex).then(function(page) {
 
         var pageNum = data.pageIndex + 1;
         var start = Date.now();
         // Pre compile the pdf page and fetch the fonts/images.
         page.getOperatorList(handler).then(function(operatorList) {
 
-          info('page=%d - getOperatorList: time=%dms, len=%d', pageNum,
-              Date.now() - start, operatorList.fnArray.length);
+          info('page=' + pageNum + ' - getOperatorList: time=' +
+               (Date.now() - start) + 'ms, len=' + operatorList.fnArray.length);
 
         }, function(e) {
 
           var minimumStackMessage =
               'worker.js: while trying to getPage() and getOperatorList()';
 
           var wrappedException;
 
@@ -35196,18 +35240,18 @@ var WorkerMessageHandler = PDFJS.WorkerM
     }, this);
 
     handler.on('GetTextContent', function wphExtractText(data, deferred) {
       pdfManager.getPage(data.pageIndex).then(function(page) {
         var pageNum = data.pageIndex + 1;
         var start = Date.now();
         page.extractTextContent().then(function(textContent) {
           deferred.resolve(textContent);
-          info('text indexing: page=%d - time=%dms', pageNum,
-              Date.now() - start);
+          info('text indexing: page=' + pageNum + ' - time=' +
+               (Date.now() - start) + 'ms');
         }, function (e) {
           // Skip errored pages
           deferred.reject(e);
         });
       });
     });
 
     handler.on('Cleanup', function wphCleanup(data, deferred) {
@@ -35219,18 +35263,53 @@ var WorkerMessageHandler = PDFJS.WorkerM
       pdfManager.terminate();
       deferred.resolve();
     });
   }
 };
 
 var consoleTimer = {};
 
+var workerConsole = {
+  log: function log() {
+    var args = Array.prototype.slice.call(arguments);
+    globalScope.postMessage({
+      action: 'console_log',
+      data: args
+    });
+  },
+
+  error: function error() {
+    var args = Array.prototype.slice.call(arguments);
+    globalScope.postMessage({
+      action: 'console_error',
+      data: args
+    });
+    throw 'pdf.js execution error';
+  },
+
+  time: function time(name) {
+    consoleTimer[name] = Date.now();
+  },
+
+  timeEnd: function timeEnd(name) {
+    var time = consoleTimer[name];
+    if (!time) {
+      error('Unknown timer name ' + name);
+    }
+    this.log('Timer:', name, Date.now() - time);
+  }
+};
+
+
 // Worker thread?
 if (typeof window === 'undefined') {
+  if (!('console' in globalScope)) {
+    globalScope.console = workerConsole;
+  }
 
   // Listen for unsupported features so we can pass them on to the main thread.
   PDFJS.UnsupportedManager.listen(function (msg) {
     globalScope.postMessage({
       action: '_unsupported_feature',
       data: msg
     });
   });
@@ -36909,114 +36988,138 @@ var JpxImage = (function JpxImageClosure
       function transformCalculate(subbands, u0, v0) {
       var ll = subbands[0];
       for (var i = 1, ii = subbands.length, j = 1; i < ii; i += 3, j++) {
         ll = this.iterate(ll, subbands[i], subbands[i + 1],
                           subbands[i + 2], u0, v0);
       }
       return ll;
     };
-    Transform.prototype.expand = function expand(buffer, bufferPadding, step) {
+    Transform.prototype.extend = function extend(buffer, offset, size) {
         // Section F.3.7 extending... using max extension of 4
-        var i1 = bufferPadding - 1, j1 = bufferPadding + 1;
-        var i2 = bufferPadding + step - 2, j2 = bufferPadding + step;
+        var i1 = offset - 1, j1 = offset + 1;
+        var i2 = offset + size - 2, j2 = offset + size;
         buffer[i1--] = buffer[j1++];
         buffer[j2++] = buffer[i2--];
         buffer[i1--] = buffer[j1++];
         buffer[j2++] = buffer[i2--];
         buffer[i1--] = buffer[j1++];
         buffer[j2++] = buffer[i2--];
-        buffer[i1--] = buffer[j1++];
-        buffer[j2++] = buffer[i2--];
+        buffer[i1] = buffer[j1];
+        buffer[j2] = buffer[i2];
     };
     Transform.prototype.iterate = function Transform_iterate(ll, hl, lh, hh,
                                                             u0, v0) {
       var llWidth = ll.width, llHeight = ll.height, llItems = ll.items;
       var hlWidth = hl.width, hlHeight = hl.height, hlItems = hl.items;
       var lhWidth = lh.width, lhHeight = lh.height, lhItems = lh.items;
       var hhWidth = hh.width, hhHeight = hh.height, hhItems = hh.items;
 
       // Section F.3.3 interleave
       var width = llWidth + hlWidth;
       var height = llHeight + lhHeight;
       var items = new Float32Array(width * height);
-      for (var i = 0, ii = llHeight; i < ii; i++) {
+      var i, j, k, l;
+
+      for (i = 0; i < llHeight; i++) {
         var k = i * llWidth, l = i * 2 * width;
-        for (var j = 0, jj = llWidth; j < jj; j++, k++, l += 2)
+        for (var j = 0; j < llWidth; j++, k++, l += 2) {
           items[l] = llItems[k];
-      }
-      for (var i = 0, ii = hlHeight; i < ii; i++) {
-        var k = i * hlWidth, l = i * 2 * width + 1;
-        for (var j = 0, jj = hlWidth; j < jj; j++, k++, l += 2)
+        }
+      }
+      for (i = 0; i < hlHeight; i++) {
+        k = i * hlWidth, l = i * 2 * width + 1;
+        for (j = 0; j < hlWidth; j++, k++, l += 2) {
           items[l] = hlItems[k];
-      }
-      for (var i = 0, ii = lhHeight; i < ii; i++) {
-        var k = i * lhWidth, l = (i * 2 + 1) * width;
-        for (var j = 0, jj = lhWidth; j < jj; j++, k++, l += 2)
+        }
+      }
+      for (i = 0; i < lhHeight; i++) {
+        k = i * lhWidth, l = (i * 2 + 1) * width;
+        for (j = 0; j < lhWidth; j++, k++, l += 2) {
           items[l] = lhItems[k];
-      }
-      for (var i = 0, ii = hhHeight; i < ii; i++) {
-        var k = i * hhWidth, l = (i * 2 + 1) * width + 1;
-        for (var j = 0, jj = hhWidth; j < jj; j++, k++, l += 2)
+        }
+      }
+      for (i = 0; i < hhHeight; i++) {
+        k = i * hhWidth, l = (i * 2 + 1) * width + 1;
+        for (j = 0; j < hhWidth; j++, k++, l += 2) {
           items[l] = hhItems[k];
+        }
       }
 
       var bufferPadding = 4;
-      var bufferLength = new Float32Array(Math.max(width, height) +
-        2 * bufferPadding);
-      var buffer = new Float32Array(bufferLength);
-      var bufferOut = new Float32Array(bufferLength);
+      var rowBuffer = new Float32Array(width + 2 * bufferPadding);
 
       // Section F.3.4 HOR_SR
       for (var v = 0; v < height; v++) {
         if (width == 1) {
           // if width = 1, when u0 even keep items as is, when odd divide by 2
           if ((u0 % 1) !== 0) {
             items[v * width] /= 2;
           }
           continue;
         }
-
-        var k = v * width;
-        var l = bufferPadding;
-        for (var u = 0; u < width; u++, k++, l++)
-          buffer[l] = items[k];
-
-        this.expand(buffer, bufferPadding, width);
-        this.filter(buffer, bufferPadding, width, u0, bufferOut);
-
         k = v * width;
-        l = bufferPadding;
-        for (var u = 0; u < width; u++, k++, l++)
-          items[k] = bufferOut[l];
-      }
+        rowBuffer.set(items.subarray(k, k + width), bufferPadding);
+
+        this.extend(rowBuffer, bufferPadding, width);
+        this.filter(rowBuffer, bufferPadding, width, u0, rowBuffer);
+
+        items.set(rowBuffer.subarray(bufferPadding, bufferPadding + width), k);
+      }
+
+      // Accesses to the items array can take long, because it may not fit into
+      // CPU cache and has to be fetched from main memory. Since subsequent
+      // accesses to the items array are not local when reading columns, we
+      // have a cache miss every time. To reduce cache misses, get up to
+      // 'numBuffers' items at a time and store them into the individual
+      // buffers. The colBuffers should be small enough to fit into CPU cache.
+      var numBuffers = 16;
+      var colBuffers = [];
+      for (i = 0; i < numBuffers; i++) {
+        colBuffers.push(new Float32Array(height + 2 * bufferPadding));
+      }
+      var b, currentBuffer = 0, ll = bufferPadding + height;
 
       // Section F.3.5 VER_SR
       for (var u = 0; u < width; u++) {
         if (height == 1) {
           // if height = 1, when v0 even keep items as is, when odd divide by 2
           if ((v0 % 1) !== 0) {
             items[u] /= 2;
           }
           continue;
         }
 
-        var k = u;
-        var l = bufferPadding;
-        for (var v = 0; v < height; v++, k += width, l++)
-          buffer[l] = items[k];
-
-        this.expand(buffer, bufferPadding, height);
-        this.filter(buffer, bufferPadding, height, v0, bufferOut);
-
-        k = u;
-        l = bufferPadding;
-        for (var v = 0; v < height; v++, k += width, l++)
-          items[k] = bufferOut[l];
-      }
+        // if we ran out of buffers, copy several image columns at once
+        if (currentBuffer === 0) {
+          numBuffers = Math.min(width - u, numBuffers);
+          for (k = u, l = bufferPadding; l < ll; k += width, l++) {
+            for (b = 0; b < numBuffers; b++) {
+              colBuffers[b][l] = items[k + b];
+            }
+          }
+          currentBuffer = numBuffers;
+        }
+
+        currentBuffer--;
+        var buffer = colBuffers[currentBuffer];
+        this.extend(buffer, bufferPadding, height);
+        this.filter(buffer, bufferPadding, height, v0, buffer);
+
+        // If this is last buffer in this group of buffers, flush all buffers.
+        if (currentBuffer === 0) {
+          k = u - numBuffers + 1;
+          for (l = bufferPadding; l < ll; k += width, l++) {
+            for (b = 0; b < numBuffers; b++) {
+              items[k + b] = colBuffers[b][l];
+            }
+          }
+        }
+      }
+
       return {
         width: width,
         height: height,
         items: items
       };
     };
     return Transform;
   })();
@@ -39408,27 +39511,26 @@ var JpegImage = (function jpegImage() {
     return offset - startOffset;
   }
 
   function buildComponentData(frame, component) {
     var lines = [];
     var blocksPerLine = component.blocksPerLine;
     var blocksPerColumn = component.blocksPerColumn;
     var samplesPerLine = blocksPerLine << 3;
-    var R = new Int32Array(64), r = new Uint8Array(64);
+    var R = new Int32Array(64);
 
     // A port of poppler's IDCT method which in turn is taken from:
     //   Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz,
     //   "Practical Fast 1-D DCT Algorithms with 11 Multiplications",
     //   IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989,
     //   988-991.
-    function quantizeAndInverse(zz, dataOut, dataIn) {
+    function quantizeAndInverse(zz, p) {
       var qt = component.quantizationTable;
       var v0, v1, v2, v3, v4, v5, v6, v7, t;
-      var p = dataIn;
       var i;
 
       // dequant
       for (i = 0; i < 64; i++)
         p[i] = zz[i] * qt[i];
 
       // inverse DCT on rows
       for (i = 0; i < 8; ++i) {
@@ -39502,17 +39604,17 @@ var JpegImage = (function jpegImage() {
       // inverse DCT on columns
       for (i = 0; i < 8; ++i) {
         var col = i;
 
         // check for all-zero AC coefficients
         if (p[1*8 + col] == 0 && p[2*8 + col] == 0 && p[3*8 + col] == 0 &&
             p[4*8 + col] == 0 && p[5*8 + col] == 0 && p[6*8 + col] == 0 &&
             p[7*8 + col] == 0) {
-          t = (dctSqrt2 * dataIn[i+0] + 8192) >> 14;
+          t = (dctSqrt2 * p[i+0] + 8192) >> 14;
           p[0*8 + col] = t;
           p[1*8 + col] = t;
           p[2*8 + col] = t;
           p[3*8 + col] = t;
           p[4*8 + col] = t;
           p[5*8 + col] = t;
           p[6*8 + col] = t;
           p[7*8 + col] = t;
@@ -39565,34 +39667,33 @@ var JpegImage = (function jpegImage() {
         p[2*8 + col] = v2 + v5;
         p[5*8 + col] = v2 - v5;
         p[3*8 + col] = v3 + v4;
         p[4*8 + col] = v3 - v4;
       }
 
       // convert to 8-bit integers
       for (i = 0; i < 64; ++i) {
-        var sample = 128 + ((p[i] + 8) >> 4);
-        dataOut[i] = sample < 0 ? 0 : sample > 0xFF ? 0xFF : sample;
+        p[i] = clampTo8bit((p[i] + 2056) >> 4);
       }
     }
 
     var i, j;
     for (var blockRow = 0; blockRow < blocksPerColumn; blockRow++) {
       var scanLine = blockRow << 3;
       for (i = 0; i < 8; i++)
         lines.push(new Uint8Array(samplesPerLine));
       for (var blockCol = 0; blockCol < blocksPerLine; blockCol++) {
-        quantizeAndInverse(component.blocks[blockRow][blockCol], r, R);
+        quantizeAndInverse(component.blocks[blockRow][blockCol], R);
 
         var offset = 0, sample = blockCol << 3;
         for (j = 0; j < 8; j++) {
           var line = lines[scanLine + j];
           for (i = 0; i < 8; i++)
-            line[sample + i] = r[offset++];
+            line[sample + i] = R[offset++];
         }
       }
     }
     return lines;
   }
 
   function clampTo8bit(a) {
     return a < 0 ? 0 : a > 255 ? 255 : a;
@@ -39643,17 +39744,17 @@ var JpegImage = (function jpegImage() {
             var blocksPerLine = Math.ceil(Math.ceil(frame.samplesPerLine / 8) * component.h / maxH);
             var blocksPerColumn = Math.ceil(Math.ceil(frame.scanLines  / 8) * component.v / maxV);
             var blocksPerLineForMcu = mcusPerLine * component.h;
             var blocksPerColumnForMcu = mcusPerColumn * component.v;
             var blocks = [];
             for (var i = 0; i < blocksPerColumnForMcu; i++) {
               var row = [];
               for (var j = 0; j < blocksPerLineForMcu; j++)
-                row.push(new Int32Array(64));
+                row.push(new Int16Array(64));
               blocks.push(row);
             }
             component.blocksPerLine = blocksPerLine;
             component.blocksPerColumn = blocksPerColumn;
             component.blocks = blocks;
           }
         }
         frame.maxH = maxH;
@@ -39847,184 +39948,146 @@ var JpegImage = (function jpegImage() {
           scaleX: component.h / frame.maxH,
           scaleY: component.v / frame.maxV
         });
       }
     },
     getData: function getData(width, height) {
       var scaleX = this.width / width, scaleY = this.height / height;
 
-      var component1, component2, component3, component4;
-      var component1Line, component2Line, component3Line, component4Line;
-      var x, y;
+      var component, componentLine, componentScaleX, componentScaleY;
+      var x, y, i;
       var offset = 0;
       var Y, Cb, Cr, K, C, M, Ye, R, G, B;
       var colorTransform;
-      var dataLength = width * height * this.components.length;
+      var numComponents = this.components.length;
+      var dataLength = width * height * numComponents;
       var data = new Uint8Array(dataLength);
-      switch (this.components.length) {
-        case 1:
-          component1 = this.components[0];
-          for (y = 0; y < height; y++) {
-            component1Line = component1.lines[0 | (y * component1.scaleY * scaleY)];
-            for (x = 0; x < width; x++) {
-              Y = component1Line[0 | (x * component1.scaleX * scaleX)];
-
-              data[offset++] = Y;
-            }
-          }
-          break;
-        case 2:
-          // PDF might compress two component data in custom colorspace
-          component1 = this.components[0];
-          component2 = this.components[1];
-          for (y = 0; y < height; y++) {
-            component1Line = component1.lines[0 | (y * component1.scaleY * scaleY)];
-            component2Line = component2.lines[0 | (y * component2.scaleY * scaleY)];
-            for (x = 0; x < width; x++) {
-              Y = component1Line[0 | (x * component1.scaleX * scaleX)];
-              data[offset++] = Y;
-              Y = component2Line[0 | (x * component2.scaleX * scaleX)];
-              data[offset++] = Y;
-            }
-          }
-          break;
+
+      // First construct image data ...
+      for (i = 0; i < numComponents; i++) {
+        component = this.components[i];
+        componentScaleX = component.scaleX * scaleX;
+        componentScaleY = component.scaleY * scaleY;
+        offset = i;
+        for (y = 0; y < height; y++) {
+          componentLine = component.lines[0 | (y * componentScaleY)];
+          for (x = 0; x < width; x++) {
+            data[offset] = componentLine[0 | (x * componentScaleX)];
+            offset += numComponents;
+          }
+        }
+      }
+
+      // ... then transform colors, if necessary
+      switch (numComponents) {
+        case 1: case 2: break;
+        // no color conversion for one or two compoenents
+
         case 3:
           // The default transform for three components is true
           colorTransform = true;
           // The adobe transform marker overrides any previous setting
           if (this.adobe && this.adobe.transformCode)
             colorTransform = true;
           else if (typeof this.colorTransform !== 'undefined')
             colorTransform = !!this.colorTransform;
 
-          component1 = this.components[0];
-          component2 = this.components[1];
-          component3 = this.components[2];
-          for (y = 0; y < height; y++) {
-            component1Line = component1.lines[0 | (y * component1.scaleY * scaleY)];
-            component2Line = component2.lines[0 | (y * component2.scaleY * scaleY)];
-            component3Line = component3.lines[0 | (y * component3.scaleY * scaleY)];
-            for (x = 0; x < width; x++) {
-              if (!colorTransform) {
-                R = component1Line[0 | (x * component1.scaleX * scaleX)];
-                G = component2Line[0 | (x * component2.scaleX * scaleX)];
-                B = component3Line[0 | (x * component3.scaleX * scaleX)];
-              } else {
-                Y = component1Line[0 | (x * component1.scaleX * scaleX)];
-                Cb = component2Line[0 | (x * component2.scaleX * scaleX)];
-                Cr = component3Line[0 | (x * component3.scaleX * scaleX)];
-
-                R = clampTo8bit(Y + 1.402 * (Cr - 128));
-                G = clampTo8bit(Y - 0.3441363 * (Cb - 128) - 0.71413636 * (Cr - 128));
-                B = clampTo8bit(Y + 1.772 * (Cb - 128));
-              }
-
-              data[offset++] = R;
-              data[offset++] = G;
-              data[offset++] = B;
+          if (colorTransform) {
+            for (i = 0; i < dataLength; i += numComponents) {
+              Y  = data[i    ];
+              Cb = data[i + 1];
+              Cr = data[i + 2];
+
+              R = clampTo8bit(Y + 1.402 * (Cr - 128));
+              G = clampTo8bit(Y - 0.3441363 * (Cb - 128) - 0.71413636 * (Cr - 128));
+              B = clampTo8bit(Y + 1.772 * (Cb - 128));
+
+              data[i    ] = R;
+              data[i + 1] = G;
+              data[i + 2] = B;
             }
           }
           break;
         case 4:
           // The default transform for four components is false
           colorTransform = false;
           // The adobe transform marker overrides any previous setting
           if (this.adobe && this.adobe.transformCode)
             colorTransform = true;
           else if (typeof this.colorTransform !== 'undefined')
             colorTransform = !!this.colorTransform;
 
-          component1 = this.components[0];
-          component2 = this.components[1];
-          component3 = this.components[2];
-          component4 = this.components[3];
-          for (y = 0; y < height; y++) {
-            component1Line = component1.lines[0 | (y * component1.scaleY * scaleY)];
-            component2Line = component2.lines[0 | (y * component2.scaleY * scaleY)];
-            component3Line = component3.lines[0 | (y * component3.scaleY * scaleY)];
-            component4Line = component4.lines[0 | (y * component4.scaleY * scaleY)];
-            for (x = 0; x < width; x++) {
-              if (!colorTransform) {
-                C = component1Line[0 | (x * component1.scaleX * scaleX)];
-                M = component2Line[0 | (x * component2.scaleX * scaleX)];
-                Ye = component3Line[0 | (x * component3.scaleX * scaleX)];
-                K = component4Line[0 | (x * component4.scaleX * scaleX)];
-              } else {
-                Y = component1Line[0 | (x * component1.scaleX * scaleX)];
-                Cb = component2Line[0 | (x * component2.scaleX * scaleX)];
-                Cr = component3Line[0 | (x * component3.scaleX * scaleX)];
-                K = component4Line[0 | (x * component4.scaleX * scaleX)];
-
-                C = 255 - clampTo8bit(Y + 1.402 * (Cr - 128));
-                M = 255 - clampTo8bit(Y - 0.3441363 * (Cb - 128) - 0.71413636 * (Cr - 128));
-                Ye = 255 - clampTo8bit(Y + 1.772 * (Cb - 128));
-              }
-              data[offset++] = C;
-              data[offset++] = M;
-              data[offset++] = Ye;
-              data[offset++] = K;
+          if (colorTransform) {
+            for (i = 0; i < dataLength; i += numComponents) {
+              Y  = data[i];
+              Cb = data[i + 1];
+              Cr = data[i + 2];
+
+              C = 255 - clampTo8bit(Y + 1.402 * (Cr - 128));
+              M = 255 - clampTo8bit(Y - 0.3441363 * (Cb - 128) - 0.71413636 * (Cr - 128));
+              Ye = 255 - clampTo8bit(Y + 1.772 * (Cb - 128));
+
+              data[i    ] = C;
+              data[i + 1] = M;
+              data[i + 2] = Ye;
+              // K is unchanged
             }
           }
           break;
         default:
           throw 'Unsupported color mode';
       }
       return data;
     },
     copyToImageData: function copyToImageData(imageData) {
       var width = imageData.width, height = imageData.height;
+      var imageDataBytes = width * height * 4;
       var imageDataArray = imageData.data;
       var data = this.getData(width, height);
-      var i = 0, j = 0, x, y;
+      var i = 0, j = 0;
       var Y, K, C, M, R, G, B;
       switch (this.components.length) {
         case 1:
-          for (y = 0; y < height; y++) {
-            for (x = 0; x < width; x++) {
-              Y = data[i++];
-
-              imageDataArray[j++] = Y;
-              imageDataArray[j++] = Y;
-              imageDataArray[j++] = Y;
-              imageDataArray[j++] = 255;
-            }
+          while (j < imageDataBytes) {
+            Y = data[i++];
+
+            imageDataArray[j++] = Y;
+            imageDataArray[j++] = Y;
+            imageDataArray[j++] = Y;
+            imageDataArray[j++] = 255;
           }
           break;
         case 3:
-          for (y = 0; y < height; y++) {
-            for (x = 0; x < width; x++) {
-              R = data[i++];
-              G = data[i++];
-              B = data[i++];
-
-              imageDataArray[j++] = R;
-              imageDataArray[j++] = G;
-              imageDataArray[j++] = B;
-              imageDataArray[j++] = 255;
-            }
+          while (j < imageDataBytes) {
+            R = data[i++];
+            G = data[i++];
+            B = data[i++];
+
+            imageDataArray[j++] = R;
+            imageDataArray[j++] = G;
+            imageDataArray[j++] = B;
+            imageDataArray[j++] = 255;
           }
           break;
         case 4:
-          for (y = 0; y < height; y++) {
-            for (x = 0; x < width; x++) {
-              C = data[i++];
-              M = data[i++];
-              Y = data[i++];
-              K = data[i++];
-
-              R = 255 - clampTo8bit(C * (1 - K / 255) + K);
-              G = 255 - clampTo8bit(M * (1 - K / 255) + K);
-              B = 255 - clampTo8bit(Y * (1 - K / 255) + K);
-
-              imageDataArray[j++] = R;
-              imageDataArray[j++] = G;
-              imageDataArray[j++] = B;
-              imageDataArray[j++] = 255;
-            }
+          while (j < imageDataBytes) {
+            C = data[i++];
+            M = data[i++];
+            Y = data[i++];
+            K = data[i++];
+
+            R = 255 - clampTo8bit(C * (1 - K / 255) + K);
+            G = 255 - clampTo8bit(M * (1 - K / 255) + K);
+            B = 255 - clampTo8bit(Y * (1 - K / 255) + K);
+
+            imageDataArray[j++] = R;
+            imageDataArray[j++] = G;
+            imageDataArray[j++] = B;
+            imageDataArray[j++] = 255;
           }
           break;
         default:
           throw 'Unsupported color mode';
       }
     }
   };
 
index 4b5551e23600acf956df706d73cab427db50b90c..bef02743fc108697e14e0e5daab8181f7ef91dd8
GIT binary patch
literal 199
zc%17D@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6`aE46Ln;`jUU1|(WFXM`uzZ<i
z<8)EMt{|mXaV+9Z51a(Fx;mVKK5(4(?3xhb{-Jg@&)@K)^B+&rnEJfwd;GyU=5cQm
zmdWd%;*dFSquSq7&2B0!w?AW7!m9JlifsPJ_iD0D2q;cxm@%pB&|CHR$^+^G@rA;P
x69iKx8$64;Ssyf6Fud%7>fwf<{~}+$G0pUl&6i=kdI{(<22WQ%mvv4FO#q)8O6mXr
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..1da6dc949cd6451c2d8ea39e1618d0323d2e1ec1
GIT binary patch
literal 304
zc$@(+0nh%4P)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0002@Nkl<Zcmd7S
zZ7u^*6o>J%mRW)o*bZ%{dl2K@N_?~eFJnrG5D`)>eWA=I9=*xr<Q5%0Cz1F+A8+pO
z<B|V9+DLsuU2Q&`fPNqQfs}Vf)0{xcgki`Bq`WbxasVw}dC|;3ixK@OBhX|>Z>GuI
z4!;9U26Pv$_Z4XH%%iCpph2GpV-c{*6Zhs6SfR_EJq5;V+<H<#lJk9T>?sh4&K}p+
z6sU+@u52lw#15CH6i}kr=3>#xgHlS7GA<BXbmC-rZcFmx0#QWS?|~#|o8+1eP-27A
zDkGpok#Q2T14`r>$J0E366+j!0VQ&&@3-ef{(7H#?13Ev59AjB0000<MNUMnLSTa3
C-hk%-
index f681e4ee44e4dd520759b974a7a1f6f868f30894..de1d0fc901c2d2369660026bd466d4c3f0a62eba
GIT binary patch
literal 193
zc$@*j06zbTP)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e0001pNkl<Zcmb8l
z(F(y(0LJm}m3RU#E2%{@;a)2jO1V(0iI%7xbspi*CY{r<o$~!IzrX$-8{`wAJL`B*
zabpz=u5T4fKUnbaoLd(%7nBqoO44s|>QONN1jjx$vyv5uZYI@G&FX~xujj12+YK~w
v*fr|J-NDGo&9wKH*qTY?mdrSMOX2+jbf@g_m202_00000NkvXXu0mjfGEh>(
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0250307c0d10b0c0a38a8381361ec265ef3080c8
GIT binary patch
literal 296
zc$@(!0oVSCP)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0002*Nkl<Zcmd7K
zYc2y}7{&3k7CW#5+i@Fv5ckVUeCrOB=?o!4L`b!?9jdE1)U-}3$~@<j=a;<ir}M}E
zKduqK0sk^k!V45ic!A!BHzt0d`>D^w4Rl6cnRtQcFE3nm0&QVWiRnO%{h3-*x?K4w
z&|<T)juHwyggkNid*D8(twj0Vg*|d<GH`2Xa#4XBN3mX@0EQ2*<IWB-hw<?$DnEec
z054<mea*|jMMS=*`RE2mJg+L-)m%4^g;|(S%62rbc+A9@15C#n+r}K=X{oVg%>kYa
uWt-+4V4d~Up94HjH;lQ?oa>Bv?A`$+U7<=?MIved0000<MNUMnLSTYHgMp0z
index f681e4ee44e4dd520759b974a7a1f6f868f30894..de1d0fc901c2d2369660026bd466d4c3f0a62eba
GIT binary patch
literal 193
zc$@*j06zbTP)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e0001pNkl<Zcmb8l
z(F(y(0LJm}m3RU#E2%{@;a)2jO1V(0iI%7xbspi*CY{r<o$~!IzrX$-8{`wAJL`B*
zabpz=u5T4fKUnbaoLd(%7nBqoO44s|>QONN1jjx$vyv5uZYI@G&FX~xujj12+YK~w
v*fr|J-NDGo&9wKH*qTY?mdrSMOX2+jbf@g_m202_00000NkvXXu0mjfGEh>(
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0250307c0d10b0c0a38a8381361ec265ef3080c8
GIT binary patch
literal 296
zc$@(!0oVSCP)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0002*Nkl<Zcmd7K
zYc2y}7{&3k7CW#5+i@Fv5ckVUeCrOB=?o!4L`b!?9jdE1)U-}3$~@<j=a;<ir}M}E
zKduqK0sk^k!V45ic!A!BHzt0d`>D^w4Rl6cnRtQcFE3nm0&QVWiRnO%{h3-*x?K4w
z&|<T)juHwyggkNid*D8(twj0Vg*|d<GH`2Xa#4XBN3mX@0EQ2*<IWB-hw<?$DnEec
z054<mea*|jMMS=*`RE2mJg+L-)m%4^g;|(S%62rbc+A9@15C#n+r}K=X{oVg%>kYa
uWt-+4V4d~Up94HjH;lQ?oa>Bv?A`$+U7<=?MIved0000<MNUMnLSTYHgMp0z
index 4b5551e23600acf956df706d73cab427db50b90c..bef02743fc108697e14e0e5daab8181f7ef91dd8
GIT binary patch
literal 199
zc%17D@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6`aE46Ln;`jUU1|(WFXM`uzZ<i
z<8)EMt{|mXaV+9Z51a(Fx;mVKK5(4(?3xhb{-Jg@&)@K)^B+&rnEJfwd;GyU=5cQm
zmdWd%;*dFSquSq7&2B0!w?AW7!m9JlifsPJ_iD0D2q;cxm@%pB&|CHR$^+^G@rA;P
x69iKx8$64;Ssyf6Fud%7>fwf<{~}+$G0pUl&6i=kdI{(<22WQ%mvv4FO#q)8O6mXr
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..1da6dc949cd6451c2d8ea39e1618d0323d2e1ec1
GIT binary patch
literal 304
zc$@(+0nh%4P)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0002@Nkl<Zcmd7S
zZ7u^*6o>J%mRW)o*bZ%{dl2K@N_?~eFJnrG5D`)>eWA=I9=*xr<Q5%0Cz1F+A8+pO
z<B|V9+DLsuU2Q&`fPNqQfs}Vf)0{xcgki`Bq`WbxasVw}dC|;3ixK@OBhX|>Z>GuI
z4!;9U26Pv$_Z4XH%%iCpph2GpV-c{*6Zhs6SfR_EJq5;V+<H<#lJk9T>?sh4&K}p+
z6sU+@u52lw#15CH6i}kr=3>#xgHlS7GA<BXbmC-rZcFmx0#QWS?|~#|o8+1eP-27A
zDkGpok#Q2T14`r>$J0E366+j!0VQ&&@3-ef{(7H#?13Ev59AjB0000<MNUMnLSTa3
C-hk%-
index a9e82db331e9dfc6e3a0d660423bbca5f31d3dcd..40925e25ace9954a0e3092c1cd19a02eca82fd07
GIT binary patch
literal 403
zc$@)~0c`$>P)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e00046Nkl<Z7#U5$
z!Aima00!WH40Z|h(5;J?N_G%(p1Sr79=dkuK`L<Ii0bZT1wxtyMI;e|fiRdlp|B1?
zL1J!ou!0=c_NO*S-v<O3r$&Q4_GnOJ9RE?G>f7wOH{J8@xqHK&Z&Rg&Ka^Nx_w{OH
z9m_}{f#t3B*DH2;L<wVFhR=6;G=&JJqS4fy&Sx(JfN?%K<yjd5MtI6Ij0v-{Q|2QV
z;b!@;w+aCh{fqtu{s?=kd~mZERKE;FFqMRYsmQ<>RN>ve93sSHo*-nGyj%E|okxgm
zwh?+OeAn@Q=~fY<MGGPK`n`<yE}K*kV4ZaYsIYmz19inWhIxvZa0*Tl6BLJe-%wY8
zndUZ4Zc)To5(-8ra+79r8#4f6a!04h11=%JB=>1{^q7nZVNPje{Tf@WFvlD#Z27f@
xHm5*9K*0Q3+R{Et{`F7g<H*w1(pZ3ikza!z$HP=Cb}Ik?002ovPDHLkV1gF|uTTI0
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..adb240eaad3c4cd7329cccd7af188e6472302a00
GIT binary patch
literal 933
zc$@*H16urvP)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg000AQNkl<Zcmb7^
zUuaWj7{(tnFA^{XcefjD=!K+>+qx@PFC2mwUI+_V#0!U0aTB~4lirBT6~rN1X&QR5
ziS$l!Yw6r@1zSsJY|}JHn=~zE#x^mTTW2Vij5U8sa-O{(2WEP{rm**SIDC2jyypZ$
zu-UMQe)e*dDJ}~sIR)q!6*{`)VITiso_|U8Pg*R?r@W{^akpIH<d-Te(an*il5jR!
z&}=@Gzzd7D_~PwQ&)x33-Jzbv+iP*rES4qJyxD>_^Ea`77qaQWFHU10yx4`egk5sl
z*L^xY$SjrrLXvIv1<huXIYnXW;z_ik3APcX_2S9Gl$DZnbNvFR`G8qPcBo}P+-NlJ
zmi^fwD=7`<e+z1tManSqd}!xhIIz_?cJ6&Xq_WJ`F4s_lT=bY3rkO5;THCR$KFx!i
z6Aluu!M4`+LP+JM<sm?<_i>3!=HiuO_NUk4Dp-rxP!Akej+u+9vmRIn=r&V)#%D{n
z^zUANtej%Bh>gI#bW1tXbffYiQ;O^U>#+0frzN8px$(&j*!fOcii#hF0H5;dS{O~x
z=S_6reYxw?v=&yqLID5#!X%TKfeij91FHA;2r34j@JZrQ0y-RKPWX|~NnBFBbpz%c
z7q~EgZXP;JDo^gvnLnpIa}H*V2_{l!Q_vB|0y?R)$}wZ8OsOAB?m`Ya;#fc@cR@Lo
zFkanZjIove73hd#0iBh8<-Ga{=^$r0Tb?LGM;r_2lqZyv4r2UcJ`!g6t{xKI0vhi~
zL!7ZwIN_;I)1Xld7GXzp3)m?Jm0q1b;Q_WM`xzBx>C=Ky3r+X&vC@<M*bboUKsC$=
zBh{bj+!)M%uk`#6dDKIvBvn4#b)XB7%QbV2(?YZs<Qv3m(2fs;_fR*I=wnpnXRg5o
zYkc0-VTJ{Rfemk=<CKJ<va7>BuMa*c3vhgNxHQU1A<8>!BO1^qZdBz;qo)pU{QGfz
zcC>Vl4}~z}{DyDa%c6YEn7EQD-TS-~F4$(r@gu8)3{f$|Igarwo?)kOMowd*%vkQ~
z;PE5a0e#@w-4VHJPVfO0lZ?>dBf*f<q@|h@k*m8q;6j6OprzBl&|AIFUv;YY7kWGW
zXpz*G<H8>Ap@H*>o|iYvBj&g{ULJXQGto0}-g^jp^k@GIS5r3yiD|~C00000NkvXX
Hu0mjfs1U=|
index 2c1076d467cf676d338f8437a2dd062f27108106..e68846aa5f609f48e89b25692abdd85c2de7ecb9
GIT binary patch
literal 179
zc%17D@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6sytmBLn;{eUNGc3<RH-cuzYC+
z6Th^R0!ve`nWhd;&O`^Dpor+#_a2mUwI<%&Ds<ocX?*WLqdprhKaUrdMd!Pdr@Ya6
z%U$Mm{NM@Udk4<)EM1WPILqu;%!Q4c_N*<*ykI0eXXZ6_-bQbw3pGu%I*X6F^d8x6
dAM)#99H-!Av0COEwLn)ec)I$ztaD0e0su3%MKS;Y
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3ad8af5173850f4b645f9c94f4efe3379564b128
GIT binary patch
literal 266
zc$@(W0rmcgP)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0002dNkl<ZcmeIq
zQA)!w9DwovNp=T!g59OrvMt_EUlc_|Tv;h)#WBVZQT7tN!e^j}W3*`!M11J?d;etU
zzr+=v39b=Da5(aj;P^9mPxL*oH@wBOw^po(b>u=O3C8jVap{PU;A41oOzOaJ;Key$
zQU*)*)D8A5V+RX%R3~;UVg_@zlxMcgLkF6gqD74k8E7`-9X9B`!HkM$kBXUZFs0<F
zN6EBnpeT3@P@vidiZu^`)~NGAM$UbNoa}UvvEnY$s#!FbkxUYd<aZkS0@>+2AR>HC
Q6951J07*qoM6N<$f&iRyUH||9
index 10845c695d7b832450d530702ffab9f674427618..cb85a841b18be0235fc6c6714223609e1097d1f4
GIT binary patch
literal 301
zc$@((0n+}7P)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e0002=Nkl<ZcmZw7
zze)o^6ov64B3Rl4Qj3*fVJAL-jkPefVCQRyZ;+7MN+IQ_C}I#%TqAK~h<_HuAXwN0
z7B|8s+~Z}UFzaN0%Ll_fD1JQRG2sJ?J`}jBf`R3s_FX}G?1ck&;`lUi@T!Vk<dQ!~
zRH1SsF9OIfJ}bY|e3U1D&{bZ)%IxON9N-pfTp`$2HP<(4M|HOINC(*gJ95u?wp7P;
z?18O8V*pf*-12T@*$ic;8GyN~T}JwhLa9xG6s3jFeO^z}ulE7{r#9DyXS@u>J24O|
z%<gUT;=gZemJMK>QaP!}IU9e5CrM>v9W%fW1qojxzD%=Q00000NkvXXu0mjf%W{5L
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5c13f77ff003460753a39d9e406c0020231cabda
GIT binary patch
literal 583
zc$@)80=WH&P)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0006GNkl<Zcmb8t
zKWGzS7{~FS6k7xZ2dh~m3f8%Tvr7u%;Gj^@-MWg1Ac#<OF{2<>sDncb1tl(lO0{5H
zQE6&xnvkURPmGNv7*b6L!Th=V`QF__%SrC--TQe6-{l_O7Xsbk5HrdU;SJO<GTh{*
zkul&6h6aC%;5QIO0cDWW%HZw`B1|h0yElYtbJ4nsxoE;ojhm6OJ~2}E6MhJLnOz&Z
z-=H8gtzVEAn$|D)CN!;I@KxygFduP@;qD7Q3r)8kTaW3?bkKnsH?9lNvm0}Eed&IK
zHKFNt(kdg}^{>pV0KIxYb5^yMTWCRz8#4m*=<-RYnu#WwP~*n506n@GajHIFM;%}f
zFY^Y^aW7$86$8At-QN{yj&9v@sxj9<1L$1g8gpFdYaS((q*!NG$}P*BQ`PAzs=(Gm
zuGm&PFW5_{a(v>7UM*fj4M<$)vPc?t4M_V?iB(Vmj)#B6xFk|MFXcmJ%3gpyBWK$S
zOgPLXDIdy{Wt3sfzR7D`46gK~gc4x?9LbFFLr|r0SztMRsut(_U<wZkC_s$`J-3I=
z1-=U+AI&2V<OL4Q+~M0G;+NuxLyf?}aPcV@{Q46M^@k9GnjII<{C&xJe<nsIU{SLJ
zz2jFo=SSi``qA|q`WWRKJ#%(;wC_Y89BTeE@cd?Fs{N|lr|p^F&l1t$3pj@D^AD`K
Vd>iii;Sc}-002ovPDHLkV1iPk2)h6P
index 55a9efe42f1318ada3290f56edc9214eab3d7fdd..be763e0c4a02cab5d7842c8999faade8c47059bf
GIT binary patch
literal 175
zc%17D@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6$~;{hLn;{eb{X<9DT=r}_bOuI
z*S;pAB4U5DMLQrPIWf`wN4P|1^q&c>d5`zJymvU>ZK0k3(_cShdv}w=iShns``k;6
z|9a2*kZNL>>-ng7x$0%-AZ2dv-evusD-M1!nVC^#Cw7NZpelLZ;<(0t-0Qey{BDRJ
YJiB<=q@5ck0$sr1>FVdQ&MBb@0Mz?GUH||9
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..8570984f2d9952ebb8543a6c8bbca2408be3fe90
GIT binary patch
literal 276
zc$@(g0qg#WP)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0002nNkl<ZcmeH{
zOG?Ht6h`k_x&vK-E9(N<(w06K;A0(%gSJTsBB&rDA_{fl7CxmHt=d--L>&Czfjc{g
zj6%Epm%+!Y13m~u!|`;DXFGIF9(|doYCM^ve(0R2@MwmrSf3_JJZz&%)@Kv4!2LS1
zV0}4}<8B$5v%a3la66C8Hg!&j6gN{uYNm4{!PR#}Vyttbi*Y&9#dbQsBEkhDB5R!!
zZ3qqBhHg41f;Mp0Iq}XP49B>3;N<f^K!bA!nlW(Z$VcGi5U2L^M?LjK!`Y()2li>V
a-`N}fhF>K<1*gRT0000<MNUMnLSTX{Jai8L
index d23d84a5435ebff9e4ae226659c25feba770dd1b..675d6da2c09cebd7e2375d94cbc43de49a28a6e8
GIT binary patch
literal 360
zc$@)f0hj)XP)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e0003mNkl<Z7#V%R
zF-rmg0EXcY#6@U`6rv^CT7n9}p&~b1>IXDM<M{&wN4ExD9SVY`8iJylj6$)9qQgiy
zFhu1%9HQD1I=VMBEeY&-BoQN~|Ioyd2$CdEixzp31oaCWn=P+KizYTUO<G=!HT6-a
zPLqanlrg4b)3J=<9MQmGRo|#mrFxatj7H^?PotW-N>lYJjH!bP6)MzmI9A`JeaMrW
zP{;Eb78VxP+o^u+tz)%w>Y7tjQAHKiynbv>Q2u<>aK#ZG+*=LzzJU35q7H&2Nb8UG
z4tHis9hc+YH714zU~vDD-<VaGf7hUhNtOr!0z}ASQrtD<S5Ig=?w)f)i85tM+_>l4
zafLJ>w7618y&iZMZti8jkXl?(NPqY>rLdN@q_C#sSI-x0yte^Yo}f<v0000<MNUMn
GLSTa5F_{_w
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b9e74312270af04fa2b9b033675d8674faab64e6
GIT binary patch
literal 731
zc$@*-0wn#3P)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0007_Nkl<ZcmcJ~
zUr2Lx90u^mmDq%63`rAqV>h8e7=r0Vcp)Y9Pr|5OlrS&sF1(Z=>P7`I$&2V#B8FQ@
z#xx11n2B@MtaN4N=HFayP|U&0*qP^fzdz3rbvx5{@V?*A7yO;ybIvoweHnhs|HM2|
zKI2b<|A+)(s$d&G<Se(D5ZesM({plLvf#)BVWXR2CiyRqrPOdNPf59TOKMqgXnI<H
z=R2OrCx^x4_C(SKtAYd5i8wOO)+CLyqqtzdkRFTsrv~5XsqK8~#lE+u2IGD`W@ZQa
zAv+2S_O9Fe>YW}mq85+9hKEosr^Z)ai~BEfeTNO#3*wjb*wP4^U`OFpp(!|`#~2s8
z`FYx|7Q`+s4a0>};|dO&@9px<s|9~wvCm`EH$)-0_I$>Bxm8wN7W`#thbT7CssC=I
zTAKz9&;++jKrz^NzcAADM`@&iv`7W`N3qmw3RZ&e8hPgH3^G7Qpcx$&o`vOn_6(y+
zZas$_WXt7wl$(nFs}3E|%QjcV-;}eBGn_%TTz6djMaiyYk%erz{(qejCHZ9%NywHf
z{V9J|qQg-{A#0$GFYt5L61R9<|A{{;zE^$lK~~|*404N++(Ztym|$2*&p8|pI3TP1
z`L<k!M1&sV1|E4Mq|CfG14UM;c_QiOnxfxS;gNJrN&0K*YoN#)`n$A6uAbZACv+A6
z@BCPjRYhCu@9Kv^)&TpsC%?=e&V?D_7++#N9~Sj;8k3L1Mw(w9_rMN|agO$B3tTa+
zOUWj;#HO6qFYdL4(LOj)Vw~>ol$YO^mh!s0;lvGNuWs=UoKADO*y*%)pt=Qi+&XoY
ztsnG;h7yz6Kt7lcW&?@I(9rw6m9415J&yxVq8aUYUbLfGo*u)4nY;A)5mO4m-#Y*R
N002ovPDHLkV1o45W##|?
index f36bba81e041f42e3e73ecac0413da2b7c6cc90b..e1c7598886bd49e194764015577b766aadd82288
GIT binary patch
literal 359
zc$@)e0hs=YP)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e0003lNkl<Z7#VfJ
zF-rmg0EXcY!bNBh?jTyC%_XP^T#Vdo@eedb<MjgyN1GaSZ72wuY6uLZMJW`EAUceM
z14A_K4k4&UA?e<@vXa2(k;WoTT7NLeQl&?aDp?E(4_`mX1RZ*KxVU)qf)2a5xcWv0
zpC`Xqu;S@>x?uT5p77|>RR|+!(Z0%SPBBerLNU!<<!RHVt<YebNB2}S8sZF}E-hNL
z6zZ38j@I<+t%QSvgY$f@(8mMKjcNT^P)aGKl+vO?A2#>(Nsaeb!tN(Ep1s3u|3Lqc
zXA482_4)TIcUT&Mg&ka9PU%bJ(4vmb9tomENw9}a{m@cGL+1YGpu!Cenlx!}GpOuu
z%G3xmxmwG;o&*<z^2>28mt2*pe<GUIl2){=CCw_Lp-;j?w+ux$rQ`qr002ovPDHLk
FV1jvRo<jft
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..cb257b41c537552a19f711ced5ec19cad5fc1c9f
GIT binary patch
literal 714
zc$@*s0yX`KP)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0007!Nkl<Zcmc)J
zK}geK7zXgymDHq2MA8H=)*&<qL(n{g2SK4EA)|Itm<KxrJ4z6qR1lLqgjb;$HnM_Q
z5>7D_=c-w$rRM%>rppb3*+sVXe|le>e}?;(Er{M9e0<;c?0eV_qyI8^j_+&`1R|)U
z;XGO}fI0Zt9GrYA<6DaHV~zRM1twVFK>**dj<uL|J_Y#J!YQ$@F^Yl$yub!OSyfoW
z2B&2>W85SZR6yh2FUfJb!D6Sq1r_=#U#<w<r#bqXuh!*Mo~~-V-q)--bRSj{#227I
zU&Qi`<wx~(R7g2=m`rqlGI&>5b6Imp7B9ZQ6dlA8G-$eSq@9Y$Onc`L6}j4VAGA1e
z1=skwPmHutJ|&xcR~vkBjDocAI6jNzhpOjziuITk{*=Ke2$x|I3s}%U+A3|7NKzG}
zAk>06vGjn<q!`YWjDjDJ@kzLDxJV`F<TOEWAV@(XS;CW;6+LHrNQH{2Lg5_kj{Y9g
z!g|z7sUlf^PT_-?Ju*wFB3ZV_@J@tIg(y`dOTYoI*u1hysUlfs+VEC{?)~LA=&QkN
zp}#>6XdlOMA5}2zo(U{7GxQ7|5$+DtKDyz>3|zQm6o@A`;T9ZPLCJCIg`0Wi>*q<x
z!m>{U9GDRL?<%aEPKbabJ1?6A$s(GnBf}UMn8ID;D}MVOPR2!KxT(5{c95|#cUhyO
zcqQP07oE6>JRD?syzAu0o}Dy0+GSP$>9RT+BSRRAndFjb%&=+RP43=DhB_K4i;_&1
zr8a2C%jAM~ORYRlKIV)PyKSo<qlvcq?Y4{(GSj}3n_ham!QJZb-F8M@QP;N9-|KF@
w)sS9Fx%9`ANhhh8%IN|tr(!-Gqkl8M0N&iw@8RFz)Bpeg07*qoM6N<$f{`^)u>b%7
index b27050e2116e305c929ab43c02e3a0c05a00df90..a187be6c9ba78003d9d2013e4cdc1c7f73bb8949
GIT binary patch
literal 174
zc%17D@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6N<Cd1Ln;`PlN1;paQ)lw+{`0z
zf+g9Y#<^8O&ESu7Yl_B?ZZ1R7KaQ;>28}V=>tyzpi1dq!_s#Y(o?Z6PqD=UotbK;z
z+=pt1eY;;C=TG8Xk<7mK*`GaMCo^*7N1nAT`yj#0VsudA+GmM(2Yq*^+n%4r$i(=*
XtGDvpiMgkM4q)(f^>bP0l+XkKeAzzU
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..4efbaa6758dce6ea82f9e03e81c0196cd806b266
GIT binary patch
literal 260
zc$@(Q0sH=mP)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0002XNkl<ZcmeH{
z&B}s66owD8@qR=YYP?CMM1;JUgaO?&vuMB(L<C#562eUrfyC!fj6Xqq;CVLk;(0i)
z3lS`w?+et`01QET05=213d+DL7$LYD`27WIh5z^s)(W+#&kHJ4V&iSSO3bWKFxS7Z
zhP!@onsGtS>|Mj3PYt*CIh*)L;+Ye)qJLer!U=dbLBLZSzSesM4tY9KKocB+w3G#Z
zP#|$ck0S&$A%{+O@CHd@not;m^nk=r!lx-oOkfDo1ASdr=)nV-#q?0Gf`(oI0000<
KMNUMnLSTYMTxkmc
index 7755eee779e5ad801d274ba8184673bcba08779c..eaab35f09e12fed1a285ca765b38846f84ebbb91
GIT binary patch
literal 259
zc$@(P0sQ`nP)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e0002WNkl<Zcma)$
zJ<7sB5QeAv@D%B^vrw?#!d|q`6|@k%klw*Y{3RqsK(P=k1Q9iC;|V@?oXNNhSuC6f
zl6l{K5*B_Moa3tk;0QsG*Awp*04*yj+yb~MaHzsHpaX`8^bVJR2NsO};Vg7}{AGXO
zvkE5x{(z_EvkFIn_b^Mb7kCe|6glSO7!3F^lbAadGR*$h7||v~ZpEDn36Z+xM`_S;
z%AE?klEf{rj!oRqku+YgQz{9n4s^AxBs;TU0m?@U%oo}~^9E?zG!7ESS7rbJ002ov
JPDHLkV1f;GXr2H7
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..896face455a605a86196bce9ad3b7d640468dd17
GIT binary patch
literal 425
zc$@*L0apHrP)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0004SNkl<Zcmd7L
zyGkoj7{&2#2zDvNMnqA346TOXTWFCdh+-`&f(V{29L_6PiWjWCCm9n%f&@jBsJR>)
zyTrz@9NlC#^DUV~uyB6O#`Wc|{GJapsNf}n_~s#6@aR;~Ks|!^o;hKkb<`q>uf_@c
ze2Ny_{735Rz+(^grfCv7@DMF@(?E&?)gFc+;s(Y=f4GnKw)K%<_IcMs6%8~k4%~hd
z1#ZH&m*NR=jd<c<P467I4jUU4N4lRgIiYtBRKm>9Z9?xHxKc#XI|a&$D7>pcNfCv2
z6(}mA@U8*{MHJpuAa5+piu*}@=C6x$-8&9=MtcJe#2}8pdIkrw28vjvgyHy0F}R~Z
zCUA)rP9TO&f3a5-II~coM6B}%`OpmoPD3uR3@7y8J#|5W6U7S>1Ne&^?G!jBIjmz4
zBlw35uM~LQ#}Ub*j1tayY3;VeknSU$Z13T)Kdqf~GA)J#k0F^Bw@*|4^-q28r{Use
T)~jCX00000NkvXXu0mjf;mWr^
index 63a7c320e9a981f83c3416f754e4db1a6ab504d4..306eb43b86861ffd83ab17541d64a4e8d240c86a
GIT binary patch
literal 108
zc%17D@N?(olHy`uVBq!ia0vp^>_9BQ!3HF6HKu+5QpTPxjv*44lM^HyKK%b*U#Aeq
zu;`*{L_>wHfPM2NofDJ17YG^bX|d`%n5z@V{_rc;Tt)`NYtfrMyS6_7YG?3t^>bP0
Hl+XkKJQO0C
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f7570bc0d30db3dafe54aa7c1fe92367690f5046
GIT binary patch
literal 152
zc%17D@N?(olHy`uVBq!ia0vp^d_b(g!2%>Zo;S(>sd!Hp$B+ufWQooP^)>=V3JT0Z
z$G`noR@ib>ZRMZ;zy7B?RLGuin*8K{y@Up1n}eABCY96wr#d)VuzZRTnDjQlktL_y
z<57djB$XEmhvE+MurwWXw|F2ZV0`Mr1B0n74EE`D>#U8d6@XSTc)I$ztaD0e0s!v6
BGz<U$
index e139f3017d6379d324fcdab5e850fc9bd80928ff..b5cf1bd06139d17c90cb6ab492221803f5047543
GIT binary patch
literal 295
zc$@(z0oeYDP)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e0002)Nkl<ZcmZP|
z0{q|c{~Z)={m=QI0TqIXXaAo-Adoc$n}SD3@ag~8Nbm+&K}R|+*q7V~RB#?>G;VmC
z;q~VKH(~JG$%=&H*l#BhBA@m%+@JRU8U%hjmgvvG%fOT9|Lqt|?CCOwE9L($f#A18
zKxs~}zd3<Q4naikbTgca`F|b+Ya<}i5G8ey5Ycma3<ur*p8-Ljmu|!S4rJYch#n1Q
z*l+Ux1PsCyAVdz@G3-$Je-s8`3J@Zjv>BF({67qbqF`wWgvfL;hE+U&_WnNzfk1a(
t2EvOl{_oukEDQ`x40a3-IG`;90|2DgL5N;Bd29dx002ovPDHLkV1nayd!_&Y
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..91ab76593eadd6280b2a554d8d3eb1430d7ef6ba
GIT binary patch
literal 550
zc$@(y0@?kEP)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0005)Nkl<Zcmd7M
zKWGzS7=ZETVn}ciS_N09V5|rZh2kIv|4^4MRUF&|?d0I#5cd*62s+dv{-YfNl^{jj
zB&60xtBLfIQ*&|}jcJm>V8EdrV)CkilFRiwZGwaE58mndUOxVhkz-=YH-{A&5&o{d
zns22dWrs@ZlkDB%fnWKmLb;Wa?OQuga#3zxZ}MmDC0|@s<g2T>&JT+HXqXKe@Ow>O
zxH{3h$him+5RYuj9yN~lP7jG!JjhF_%4%QAQk5*<6Jqsm?Kz+C$$K}&xzJc>>|@Nm
zsKzm_h^c1H4jjOTZ(zSQ>)J$FIwS8?teL?fGyt^0A!|lm<t`CFC~r3VaDU_Z#tHMT
zs!N^X<c_8;xo+m2uIB)nFKFD9oYSLW(AJWYwKJxCK{T9$KVVErwp(~7VQO(%=`g1K
z0Y5GR#<aa%U&I3xZ^`S9=x7voH%9Gk?O_dSSd)^mF~w@b!D=(@ZRvIiN|=}Bl>!cm
zrf{tQ1#;(QSpf${lMm-1Pv*3|P{2Xa=o32VET52+0uG8MJ)VX%$q`vnz(LU@4ksYN
zlb}3P@CY_uRWrYD9_C5zkwt}Z+X>H)v#KVxI|eagyX2`tMhu(u=AyNL7l4cY^~bW%
oyZVDVb*O{JA&&H6n13-p0bKq8;5tc*kN^Mx07*qoM6N<$g1cw`kpKVy
index 9ba3667e94986235e8a27dff14d6a70f26e49193..1957f79ab95a970cc93eaeadec532661c5a1ae55
GIT binary patch
literal 242
zc$@+901f|%P)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e0002FNkl<Zcmb8o
zK?;IU5C-6Zpc53d>kgj4Lv#w4(S5>&h#<m)I)MZ&f}llE5ky&tPujPrzj~ug_S!Tb
zyaE4ThW;A3m>|Q|$T30}L=f&H#|39(FQ@U4`qXaxf1Bc1+XmFJ4%~M*)ck=@jF*AE
z@OmCGUIsRTT4WE_AE@?zRCReJsxQhE$k7T*n^xpdHBOme(Nrc9n@SO5E{eDjb45p(
sF&)`4S3;ynbtti233MRw&&qfF1f{Oim%bd<nE(I)07*qoM6N<$f<Ve*x&QzG
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..16ebcb8ef1e923710574bb914e19526f2545abdb
GIT binary patch
literal 398
zc$@)_0df9`P)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg00041Nkl<Zcmd7N
zJ4ypl7{&1;s3@c{OGq0V8yDaXVy9wf73@>k=KUzNjE&+Z(ng)kL^NUuQIUigABdoZ
zjSq~+fdO@9zMHugg5R&b=MNYE`8du+Zn4FCK6*TGn{x~k1gJ8@hCRLGEpOaj+8e8g
zB8)MpkFy_r`|-8kb8}@LQy6}n7&Pq1SAK);+5#pKbni>{<G#dNM+m|9w8Klu+i7e%
z1~<e6uMPGj?M;kA=h$IaQdzFR3l#x7vU0QxFO&tmki|oBcp)y}xeO!FJDw@P50tcJ
z`hk{A9Z0a}(v*2#CB6cP)Jr`1oq7oo{J4l!<gq@h=*-=T0*~}q1!wM0<arp($~$v0
zVdi)+oS9S4okW(Fnwb^mLc){@b2(AV(D18e<hh(kbKk9&R?p>+q`3FZOa;uPgpuN|
s!;t41i6pD68cF@RkkFqi61Km+Pl0_ej2E!U-~a#s07*qoM6N<$f+7928vp<R
index 272a3ca8351f251e8e9c6179b5d0fc5496f3a5c7..8219ecf83c6bcf74acc8d0cf5935347a7937edb5
GIT binary patch
literal 238
zc$@+501^L*P)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e0002BNkl<Zcma*d
zK?;IE6vpufK_{q1tM1?lIz$JFI#9F_5kwfM6G+e^2wDV1fs}<f(%yxA#nkhS*`oO^
z=E3);KOVZ6AjRECFvkES2t;k_Psg|*dAZ{DNbQ8b&cVf*6^nvcb<Bo{S$QmpRmZ4@
zlZBWZE$oFIh@Geh3bC=Z#D+2fIa*=Uq!l^zc}^Z;U6+S4n<NXc5?R2rm1rN!H|^WA
oop^{4X;0>6;%ZmspUL<91jYXM#X%ehtN;K207*qoM6N<$g5$DeH~;_u
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..758c01d8364c5597d7e9ead825cf4e7754c8d929
GIT binary patch
literal 396
zc$@)@0dxL|P)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0003~Nkl<Zcmd7K
zyGjE=6vpu*s3@c{kB~MtHa>uFpq+}Hm0+F1Hup;*cG@Vugl*K#ZX`wwAsWOGa}fz>
zkwzm~KZOBxbLOmLAviyn;=uQ(|M3vS0uJzqrx86=v5yr@f+Xsjpdf{JHeYJ!j=0AI
zdMIPgH=xkW`qFa+9gXf=3-i7Kg{HTb-3Hnk9k+}r-+)2^XB#c8_HcDb96Kz|zFy%@
zr+?TdjvvNrduZwmN(16Fr=vAAblkd2oaVF}#;t%j0<#gojle8GW2g(H0CO!c4%7t3
zfvP|ZM9}o82$~*|&j5vrIb8luF-IZ#_Cih;7v`L-ntKx&oSShnYR(gBlz!%<)m)pf
zQ#kWyr_@|dB;m;HB%5m!ww^R+i9!MvS4hZno`~brs}PswLc)&W<cl4X=VHQ&;aIWQ
q+%yqI9(gM&%*_(!b0P8JZ{IsjqP}qdC0j-S0000<MNUMnLSTZQ0jpd9
index da02bc69f7aab143771a3d6373b1c547605d0798..98e7ce481c163c0d4221be87d262096c631f800e
GIT binary patch
literal 245
zc%17D@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6_ISEDhEy<4J-?BwDL{nn!R9Sn
zezMp$J0}Z%5nJo{{*m$yvn_2Bw=O7&im*63D@e3?++e=)=tH^QooM&X3qQwRIQ(C~
z{hy4Eq$i8!k>1w*T#Q92I_?)jA__{b8r{ocmDkjB;))luQR&DQs#s?5{OcWsXDuPe
zmo+wBW`Ex!Y-z#88@{DbU>|qCUYXlY&65@XZDezLlfot}w3kTg-zv6Kc{)$s27`wd
tL8q?PzUn!-=+u@K&b74>{cp1VFo`V}NvvaB+5+?kgQu&X%Q~loCIFI;U?~6q
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a01b02380b90e5ab32727ac5460eca3108a8f1e5
GIT binary patch
literal 405
zc$@*10c!q<P)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg00048Nkl<Zcmd7Q
z!7c+)6vpvGSeDpGkg%1A2WTyH;~jVd?aZ{X@Blo3wZsG1N;eiV!n8$1BSeI>rkxqu
zT8M?#!bm@}5SjL#xxE$==eN2ibN;KL|31hDNQNMj#dAQK=y(1Y5EDv)44Ux1HIb1A
zxbp_wkVaG@>bwr8M;#f}fPp8}M8Vcj2^jETNAO_u3+Qn1AmKun1#~zl_u)W~3TUX}
zUO^Qa7tmniPLU0*H;_gJx9U(qIvhx$jGJF7BlQ!YX-bCSn%DhRa1}MU;;H}2mpt`A
ziKiME#syC?(4NFOPciVagfos`@JYn1UN>;cY3;X2BrFj7v{2+Y+YX6@#fO0+3LJCQ
zBvH>3vz-&<Iqh6xCPAXE2c|j)usFWCxlDs3AH-oIk7Lo>-ueoS%1%d+z!pldaMb1S
zJy+Y=T^nDZ7)fV{#%PX`f<=ncJWbF5{oQ;4iDXE!#q;ab00000NkvXXu0mjfx2&{B
index a4d6c8ea7512a65aa46bc8dfa2eadf0d84911837..fb9daa337656a75091ea00d4c5600ba4f557d834
GIT binary patch
literal 246
zc$@+D015wzP)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e0002JNkl<Zcmb8q
zG0MU~5XJFnEG%;Z&tPHchu|$NExd|&1X~MR36aFYMpRG`1PdV$`6L9<10+p~=Y#CB
zOI!={n`YQQgpnUVtVnDETZ9Ki-+~YsQpymzf+e5sO3JMk1o+3z;1<|{j|6c|0$&FU
zu2+YcFCv__^n`FRxD#LO4`;)D=E>4@1mz9~E$`$~;b_k}_F6G1q{7jr18lHWj_7~<
wLcH<tH7nQ5h{*_^2~@(vy6VI~X-Pxm4aA%w=kn*`ng9R*07*qoM6N<$f(Be=$^ZZW
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a5cfd755b0b400bc6b7790c0fd41e7aa70d8aa1c
GIT binary patch
literal 403
zc$@)~0c`$>P)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg00046Nkl<Zcmd7Q
zy-Gr19LMorQKLmmP=l>ObOG9sOZQNBke(N5=mxxi_UHnda|*&J&5TH*h$u8)^QA!?
z;xt&CUk(xa@IS{#Xz2Hu|6d*s2mgJH_rVY7C(gG%-^8f%*FGts5wO{2{YRVjxB;6j
z)&{h^5?<#`RuxU!x&ey~Rs;=NIsuDymORvHjS85o@x@1treDBhm4y+iG`#`_%Y4>Q
zrXd9kmiVNpL_-b4SmY!16&V{0L|Nd&m<o*k1`tGK5btG(3<<((yp!qw%C|E8KwhRF
zxbZNp8@QG^iw;z91a6L3lFmj4Ds%+SF>{h`q6-zeg7QAIlCLxaTHheG%?nYsXZ0`)
zJwbTMNirjGFS)Go0!$`0KT}Lg+!F?+fC96-Tkl6a7i8QNLsCG2!2H_bPUYYu$y1&U
xNi)wqhB>1K6qvvQRuRHFB2cYh4paDxeFMq5jmkNGJDLCh002ovPDHLkV1nI`spbFx
index 2bd1c1dfe84330ee65430f38f73abee8eb2bb72a..3ac21244dff26830f46ec462f2dab36e1a18938c
GIT binary patch
literal 321
zc$@)20lxl;P)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e00039Nkl<ZC{tr#
zAPoM$gTgwvNF7WJ!hHgQm*z4k!SyIzoDC6$D0l>d-;VqjhMU0mZ4X2g!hLXQ*2lyD
zAO1T4QSzVf-}e8HzMQ-~=l=t+g42^3RNS0C9Q=RpM>>fAJ?a1b&&NYN8B~EX5F3G*
z)y-)~6N3zxFSVx?D9sL)fdf{kGziForAY+;dH)B&*<t^MkfqW=(*M@{zxqECDt-0e
z7Lbzv=@11M|L6W&_5aMLtqpo0evZcb4gXL7+x)-a|3!#`qyNwSKly31zdO`vtoDxY
z*Zn^U6g>)2a2N#7G$Xm3^>hP76r$iD7@qu}40l!X|5FfA2;Tt;<=`gB!NnK=_L!_3
TdOB@M00000NkvXXu0mjfBu|wT
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..cada9e7918da28bdf84af38c354dbf1e1c6fe31a
GIT binary patch
literal 586
zc$@)B0=4~#P)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0006JNkl<Zcmd^-
zJ!=$E6oyY10%{dlND(E4g^IO81kob?hE&SJrZZNXAQBZT%Y0x$tc>6nm<X%An$7NH
z?(8NRRxoa6H(3=s|AFWA&YkR>`NYOT@I1}o-1mKoVd&o&{7f+mN-&#|()Zx;dz{8H
zjZ$((8_UU@2);#emg03$I7{)Q2)+sjYw5ZuyjRhz2zmk^;u<K2OTRkNtOyQc^e~=T
zA44~u6v2T{Z=E~Ark}<$>iyU5k4mtKpo5NDq;oH3c;DYmG_Dw9@94#Qd!Np$MYD$j
zPc4{FS9m_nZFoN1#o4faN{c<ie&rqw`=3)SzzYRxKK$~9mu22V8|~KPq2ogoK!eRW
z|AsH`?wUFo#k?X#q%>jOD4v!1b8BVb^Z<qEggwW56{#Bq<xJuBb*YQu&JC&mX-?!{
z|ChlqC{6Y?D|ituCR5i5{)DS}f@u5#w&9?aP)z8H!){D5DFPRzew~|8ur)5ugwd1O
zF*locapmY%f-3?GyC|7@16#0s)@JA!^=EMP7T3*v3)@Cf(hW-lb<GYQumj8NwKvm=
zzpn6f3Y(}Kns}(wdK1B>!9gw9*2_{C#gi$nn)e!<ASZ&Vz}44@x+qp}@<uc(f(@aw
zlCF!Q{V19h!N&-76hS!@VMVhd_z*+oD2h<=qzK+8urm}z*vVWdpvx&nC^;h;slPG5
Y0k(Qrk4L1bp8x;=07*qoM6N<$g1hz(@c;k-
index ccc62089faef81a6390f53ccbc2ade2ca52a4b1b..51275e54bee695c76a455579262ad642efe7220c
GIT binary patch
literal 257
zc$@(N0sj7pP)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e0002UNkl<Zcma*d
zJxawu90c$=f$u8Mj{|IHm*5dn=skjXf>f!}1hmw`k2Xb!g|HAo2t*7E*&>DgR^vZU
zVV4ks^D731!9T-ielNTbGw_$axq|YpFKNTWBMo*4b40@@e=r<~g@MK&J_SO41MfMq
z6K6!=^stS5fYisq7foRJTRX628(*Bq(yKr%dZE{WZ`;7vZJ2IZv$kcQLwS8}%Xy#f
zfMcjMVUtA}0uh@ufx-#qxPlcm-vgSJD;yl)1oluX_K^Glse?0qV_8Mk00000NkvXX
Hu0mjf@9=3h
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..53d18daf7825ae12d99406068073d16ab682737e
GIT binary patch
literal 464
zc$@*y0WbcEP)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0004(Nkl<Zcmd7P
zKX21O7{~G7WOeSq&{xp~sUVPC6?LpSc6DDwM?}|76%5^~BK0i<7{P56L_>|6%E6&Q
z<c~eFMUf>gKhE5R6HaVnnStjcWqH1ObaL>24WBUJ_Y#4uV1O`0z?e~qSOfwF1Pr+z
z$Bpe>*voD2#tn`c<-UL;j`nO=$Qx_VPMhTiws^}Shp<pIR@%sNYvF+C$i+ZHiL@Dt
z&cZj~Hw`5+omqU<P$JWrMPEaSOlKBfG?d76;3lsbNuhR+D6sasi==CALbMt3v+?7+
z;KZ8Ts!j<-8|*UpLzw<eIR*?fbr-y?2fR_9?Zbxs)ZtAvps)CkefaqFh<-Jor}fyE
zdi1IRKh^`b>j6L11HP{ZY}JG58#d<-o%HwW2=;PUN2XFHukd_-`kI$Y@{*S`_h91y
zIW}gls+39Ng#)bOp}H?Gw|H@Pf)(V=%H0Vs*gACdn;u{lW|A|ybdPtAQD7%+lCuPJ
zNHpGOlkX&todVvkrYUPEpq8BS?cYmI7hZsM*cGhfU(HW?%hSMo{ZqpL0000<MNUMn
GLSTX%=h>YA
index e52370e68dcaa9fd75a8764505d617d1cc8b2689..f9b75579b1e058baada95941a4a7ff0c80edb5cb
GIT binary patch
literal 309
zc$@(>0m}Y~P)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e0002|Nkl<Z7#W?x
zze)lD0LSs)5Hu>}CT$H)>Cl*KShVy4rnvP0Z8?}Z*4h&|1f^pNMc6--g9AMzMF;T^
zdxEU<?%SexQ4RI^NPk0u5(5U5+17U)F~(-d5SuZ_`id=Vw^zw;?CkDU@@@~Cg#0EY
z`qiAmTGFz@*E#x=viw|&PAa0ARD_Oe$<Hxqcfy*fuh4c(`MqA!e9LI&BTaLBCBMf*
zOs_?f00EL-3-cnQ1)|di1_l;gx>y+IsY03~>NTiO@2lBS(WyDLQStmhYno%7XP%~a
zg|t=`Q(SSy6w-os!-I2sl2TAVdpUcr6!sO=uOix1Q2+A@lD3RUk?l9y00000NkvXX
Hu0mjfGKYz;
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..456b133248fd5310857db3e2b174730f6488371b
GIT binary patch
literal 653
zc$@)^0&@L{P)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg00071Nkl<Zcmd_m
zPe{{$7zgmTrXlIVQ>{bbX%$pI4<4dGmxrK3y9C*x5W092iXDWyS$NGul86ip{iUm*
zph&8bY4&exY`K>GnEG>Dd62o*(mD5i_k8$VY~O9Br=aKc@csAZc|K$K(~H}AmbW;?
zMG@u@&$EhH4=lw&FBkZQF-Ap9o)(M%&-~tka$b|+DChG;`IX(=w(){a#`%8{F<#$j
z!3oAVrx=lttE;Wi(dg)E3%QJl{>ms%ms(Jfo#2eJ;_GOI4YjBgwXk)xuK0A4^|Gqy
zg0)keVT6&~w6g^ktS^hRB{!`y&ScJIkb$(>x10P=3G|{G`Bfe0)oE%dg%qUCmd7})
z3^)d0=5pwC)whaONSkH-{G>RoP849(sVpfg@*ia0@S_s8gi(M+r$*3#0co@3D5sRA
zh9wlxpwskt8fi$I&Gs><q^_n=K&MXQgK@+mZT9d21BwykJ|d6JkVNscd*FezS)Dcc
zn0{q#g0{Tz37!1#*z4@DL)vU{XYxLMRQ$#VUSU0Vh<aX@H@{BY?I=g#qJ?h0=R0a%
z1{vmO5tb*f{u;W0-Nna8=;PZ`LOnGHYM@E4M~g8cC%o2@557N=`!CX?gBP(MWkpUm
zhUJ7wEpe~8dDpSQOSApUqw0P6$(+mW+}l{<$LDU#885ZO-KOKHl#{GDh@-Gq*yVZ%
zdr)3{{9nG}xR$u1#<7{ob#sz0w1nGk-{d%uea0~@F|vhmV6KPHmBjFt#(|SZ=KGAN
nvHmTN12T3PP54Lde_Q<o?a=%7G*Dw<00000NkvXXu0mjfaivhY
index 145316b8345d08154a776009b3e0e548f8f72fca..8437095273c46e84b404dcdc1157240cfdd1b454
GIT binary patch
literal 246
zc$@+D015wzP)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e0002JNkl<ZcmcJ_
zF)KxJ7{~GNA9tV(HoM_=8I-|b@+!Ox@4=2mu}XKi14$`XNs*$iK?mJ#Ih~Zr8}Ox0
zPd&T*zRRbchyPy*SU6w<=(9<-ZId3`SdUNWX4B4&XTCcg4Oq&K^R(xVe0%M)m>uWY
z?@M2Nt`6yC6T6=Kx^U>Q*>AFmU}|CQ^VA2Q+|HIZgo*jpkAZhSx|3}@2xVraKJvzU
wce9NLp>&q3J+HiVD_f9=9_zn#f#kpM2NJQXccvwU^Z)<=07*qoM6N<$g7779MF0Q*
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9d9bfa4f63d6a8ae5cbaafa2efadd2c16b48a3d8
GIT binary patch
literal 456
zc$@*q0XP1MP)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0004xNkl<ZcmeIt
zO{h$97{~EvyiL<+O4RjImn<e_;g*tQ!AL2h6tYobV<WOt7V0j^%EE$`Y$Pi+MR8x4
zbMJNBK|^z!rZHwnNi-s({$HL>&Eo0wtSl_%_c@)#x6@Nc{?`phhD&@IIESE8yJl-K
zSNKF1)hUn5sOZvq+E~U7KGIR4efOfQ^}884Zquc$Li5&n8S%Rr1@7~nmioPL?ToDQ
zyBRA(nRhf*zjpbgtnj-TYr+Ig8tT{lh2v82yBQlog$4`i$IR)&lJ~nAn?g*Tx2iXJ
zWWVJ6ZpK)6$s20w>%%>JCF}K+&F|>X@+#3QM<bCW(z~Tk;q1|$Q&dr}!(&z>D!p6D
zD}Un9_eZ=yRl_vval1L7BzJJ%w+GCj;t)~vyE&jFTPl6N#|&!ruPuHz2b3(`y7R*w
zDyWF(Z1=l4pkzsLTk9rI70-y-?RRDWXwkZ{`gNuh)5IL`x)Kb@EZ<zc%7kK)m}B@I
yLqE+HE8{##Fvlsc3#nwI>>3!A!A$=*8}1L$Je~+C1~_8?0000<MNUMnLSTZZg51Oa
index 02ed6c62ad8a22fc28d1c689a75bdff3b57bcc31..1f90f83da745ff2470745ecf1c0c276b7179b088
GIT binary patch
literal 243
zc$@+A01W?$P)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e0002GNkl<ZcmZRe
z3-~|j|2rU@@t^TO3L64JNd3W@|4;ru`@i--Gcp^Z077WpS@HkD|HuC~{%1vILluB2
z&D)Fr-}!&<|JMJU$ZU`TxRRUm|6l)q>)($5yeRDdaQJ-M|4aWbecXOn@Guga;V=~b
z@A-fE|GC#2l&u(8kl8S=_WnQr|Ky7m5@rlc$ZVK&-~ZG9k3Lz%WyHXU%!Wxf{y*{m
t;LXXb20&>fHX<n1861F66NODh005WCw%{Z<zMTL7002ovPDHLkV1l<$b{qfz
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b066fe5cb0ef03ceee653393df468690f382abdf
GIT binary patch
literal 458
zc$@*s0X6=KP)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0004zNkl<ZcmeIt
zPl$|h9LMqR_%}_fN$p|%sU?R=IoMKC9N6|CiKK9nxH!pP9i+Ifn}gye<sc{7BH0~0
zyR-A`3>ungn#PzRCDDkC`n~n-$qc_|=6h2P`+3##e4qF2k^f~&;~by5E|5SX@g5gF
zM(<yuNlWp8DV8(1dw##x-#+geG!^f;#wxq_^p271ldeWX(c&g4vv>V@4qrL*vqBy9
zmb;|w9+AI3)?7T<DN#ecanlUjUHN~Mo;?1eKowPUGpw_^5<D_=>hQODDyXUp*o57Q
zk<^j>?O9%<$}VJ!)rCGJIWh710VUKc_nfi8UFd6Wq&>}xNGDg=Rgg%$YmQ;9d&EnM
z>U;L=QAvw#VE4vGm!-&}`ugz1AsMo}H!?0DWI=tocW|Gi?Cy<iE=P`e_3_U5xFqfF
zjh!yf9D#awYx{0lX?Jhzbs^7qs_Hi~J7k5~{c*sBJRz&fS2v8wGPC>R7<p!yQN^j%
zTP0z3f1Gv;JdOmHlNm|aJ-$)d)3w>|OZx}=1^9!Vb3w=BGynhq07*qoM6N<$f>h_@
AZvX%Q
index c308668b12c8304b567247622443d9b789f9acc5..6f85ec061ea167b1718d2865cfc1e53370f11b7a
GIT binary patch
literal 225
zc%17D@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6R(QHNhEy=Fy|9t%kby|+!~K<=
z=lYs7_Vv%s4-^nwVp00$&6?)LeSG^I3$L4YTv-}i{FpUUBct%;PlbZ%#R_fqh7bDx
z-F*1OP);pG_E<uLROI?ak<6Z-RPM_QWEnIlbjv<>xTK`(Chn5R(EeH9pPAiYO~EVU
zg;AX0YiF?m$$s9yK0f=U*jm^Eqt`WV2>kpZ@LOBJCk~ccO~LBz65exMPv3u}^Njbh
X)s)<0)dyODZf5Xw^>bP0l+XkKTSZs>
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..291e006797fc7f0e84d297e952630c719fe6eeab
GIT binary patch
literal 344
zc$@)P0jK_nP)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0003WNkl<ZcmeH{
zu}T9$6h%+QPKzXn-{D6n_z$9=;5K4oWg!}{GL40#v9Xa9DJ(1`SeV8}#NZ#8#zazV
zWYKx<_=*&d0f$&g?t$A}-sR2~>zGl0Qy}Zomti9P@(RHP^G#|@5~=y7$K!siiboRh
zuIeZWmVB=G=|>dh^>JgTvTX_3{+V)mF&H3<DcC)^xu$Cg+0m1-^>EjY7F_lyu+m(`
z^5@!%E%1sIf<-iET7g&00wOY5YylCO%que#{I4g>zrp+oX2Hs@7Sy8){GqKd3+i8+
z(La(~<(6kl$Y?0+E!3g~6pVPYgsgOBL}3a(#z;E(drpoEc78P(r=PdlEn2u>S!eOM
qa*)PSBkN>jxL^#qr<+KRA;34`pdw#DmQPIp0000<MNUMnLSTZHc$r)P
index be9eceba944be98da1cbd80b54fc015de46b6f86..025dc9040e5073bfd18da3464566163456f72534
GIT binary patch
literal 225
zc%17D@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6R(QHNhEy=Fy|9q$P=HAL$NcZA
z*K(Cs@TYt-3~OskjEXVmVw>%D&|RWz?R3S%8@5!h6F=s6G4bYqaW?MzjoCkpng6|s
zXV#N@oaktrz{i#`@v)}nB&N==y>HnTvNCfR?M_V%Q~Gzyo8O~>Q6}#e!-ESy&GlaR
zu`s+4fAKGyamxbf<p$3>PlhLUim60w=5E=2>$USub|+s^j;X5ze{YfSp5y*9zfkTo
Z<J9IUxd-1q<^;N#!PC{xWt~$(696JQR_6c!
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..7f834df94000475b8edda3b062279b17277db9d8
GIT binary patch
literal 331
zc$@)C0kr;!P)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0003JNkl<ZcmeIu
zJ<3x-7zN;GaxX!P;02qAxB&~7V57JJ+hCQ#DvgD;jSEO05Rrf&3YKCaX<UJzwjV;$
zC=n8WGh-tOWEk*9;RDIjpTl`yr!GLcZmh4JxsjLD331$Me9=x5$1W2#=zNg07hEJH
zIB}Ru)F1)##p4%?6>$GH;g-ye=E3m76~FBj%$^S3p8p9*q*pSbd*{>iVWHsKF0S;I
z^gX<uru~8l?Ba-&D#Uz2E-A|w$VFxGFAM&&6OKQ~PdJ`%&hify^ot8NgX+<?B9-Es
zdsQkFRE@hjfRA`17ps*YwnBoL!(63?ub<EKw6<PCy~gCp@aEZG+xX-e)Dw)JkKXHQ
d=bLx_g<m(2eGF<5p*;Wq002ovPDHLkV1irSl*Ir5
index 21ceb3b165cc73de106009f21c8233fda247735b..aaa9430211e168a593f7e3bb486b3cac2be6556b
GIT binary patch
literal 177
zc%17D@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6Dm+~rLn;{8UeM)Zaui^FxJzhG
z!|qKIVyq93J2V|v60i`ubLP&1jLj#z)YdH6_dNZQ&xuJ2GPazLv>Ue+?>6bs6%sUl
z=5wmNX+x=cM?cG@Z*M=Wx3_WU$gY-DxaT(E)^*=hf#2W0ec7YVF<0AhkJ^MyI<bwP
b9`ng3|Geny8qbgkbOVE@tDnm{r-UW|^{hk$
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3410f70dfa653e77cd7e6b9e2c69cb2e2869c7ef
GIT binary patch
literal 394
zc$@)>0d@X~P)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0003|Nkl<ZcmeIy
z%}N4M7{>AE8oCqP6^J2Th#(YoIRh@jaAR$9RboY0TBz8UW*<_dt4i~Ob~DGonWs6N
zDHmgSc1896;1BQmyd3<D;Vxe_>=B*_8?FdJfKrFg8ajkxH`r#|ZrHE^89r%(@^&LP
zaU~!CnZY3+ryJx4P}Ww4*H%5boJ10kK>!OHX7MpIn8%#kUo_liM?;42gn8)-kME$x
z2MsMkajI;x=~Nv!fDG?7K@n$i6P3?9=x2F1U4N$!WpzoMSmnfG0tr9{|91dxvNb`P
z@Pt@#g$O@Ts`FxkI-!h8tg$vKjo=3vo__&~$jeRS1pFY=P4m>Rm+nD{$E*W$KOT$2
zPbKiz-rYZ3=dFef!V_e{6&&9|na3K+gyQ5_WYNiu|AQk<P=;B#nHdu%AoG%9VY+Ur
o3&n_98FR~s8ZZEvZ~YJ60rV~$E@j|y*#H0l07*qoM6N<$f=C;tDF6Tf
index 9b2e2f5be21be969516530f04a10a9c97659b527..976365a50612903b56e307401195ad1159e91b3f
GIT binary patch
literal 178
zc%17D@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6Dm`5sLn;{OUeH~~<S4@W@Ybbd
z);CiR8fb9XvkBRVH6EDwVAp%TuCU31<_kZ+x_#i}LS_GXOEozs>^Ne|QKRngBbo7l
z(Z#9O-!Ih&DHL`j3;gi;Q|>%Z+C4MQ_`#CC(&&{H^BL7&PFp7v<NevAVM?eZ7i)g!
ceft{5d!ZM5IVQfV1v-Mk)78&qol`;+0R4_a@&Et;
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b6a197fdf33da57ada4fec17e042708b1586fb29
GIT binary patch
literal 331
zc$@)C0kr;!P)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0003JNkl<ZcmeIy
z&q@MO7>4op8oHYTF~kcIgrY7-m_-=gLr9yLNJGQQw7)|`w#sbRZsr&`=k35ZXB7v&
zrAY4&X89~W4uka=>r9+FQTkQ_0Xjv(1s6q9K=4z^2Y#M8=iEFR2+oy!;P`O)ls|M1
zIuQI&@&RmN2ixxJx2v>4V~zJtjVOI7`6Jp1XPnuIh2Wc#513n~OwGtZFjew_qkVIo
zU$ytz5PVhoe+S{Q%8^qgO78)3#J^TUPB~o-R}j1l2nEaq#~hp3KyVxo3PjEPJUfe;
z5d?1nLIL%=*r2h(o>L)8FG~K1Hs*i>8(RooD*3?jlzsNIZU(`=k`J^Rc{e+0HChnt
dDXqo-;1^oHB*H?C%i{n5002ovPDHLkV1gg@i>m+t
index d71dd27711f6e100a15309a5831e491bbace64d4..584ba55881f9a192ddea645d6d8525bab205e289
GIT binary patch
literal 185
zc%17D@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf68a!PbLn;`1FBoz$1@g2!+&O99
zf!$e4*(<gwHMMTodbFuS=SV~N4Aq>j56dDxhu@!aQ2zL__%gK{mTjH$a~4^&m3zt@
zUaiuXsMG0KBR${yp3FT-zMKuGw=rB<eO&qY8<!2mJk0Vp9SV8APqJu>1}fgF!j@Pa
jH|<TrhI1RH+Mijv)lz5Ad+#+sw=j6R`njxgN@xNAEOkl?
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fb7db9383669cf734685ca7422bbab1032f486fd
GIT binary patch
literal 220
zc%17D@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4Ui#=T&Ln;{WUfJl$U?_6@q5h<M
zZk9T0Sk@jrBpP!-HTHn4P9D?73r>FP1#Umq<NNTSROrO@e-He-RCZ}!n0L23&W2%9
zoK%gKi@Kh|d(k%?WkAxTb4kBR!3o*F{vYl$zkYplYC<jZgfE|ZKSwWL6mP8Xl3C-z
zygQv~{S8a5vzgbqTvvFnb;BiR!dE`?!iMKI9}ax7i{;v9#}IYtbkoY`^&i;#6M}Bo
T&uF~~bS{IZtDnm{r-UW|#Cu$)
index 670acd93f5324c0f32e37e13d43c31890bdd123a..513d081bc2d2f3eb64801a5e8cde86ef4455829c
GIT binary patch
literal 136
zc%17D@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6{5@S9Ln;`P7g+!J&&MG-LGg5b
zi0J(bTQ@BD_<zEh2EnYO$r}H;1wK36+;l>154)g5P7Bj9n-%)M8r~??+_T|q$+)-V
kia5^-HX{oL#i@)8E52we&r^_U0~*cX>FVdQ&MBb@0BWi($p8QV
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d5d49d5ff107f01daa307bd0f89f98efc31eeec7
GIT binary patch
literal 160
zc%17D@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4U>7Fi*Ar*|t5-bTK29GBH`OkMs
z;LzH(r}lQj`-ICFx#MpBpCa|4zl7P1x1vYwH*5P29X)2dhZ~*=Z`AwIt>?Q+{9j-O
zLo#EO)0^fl@rko%`Z-H3Q%PTTaY>Is!UArQV{B|y4S@^{cTUS(`F>5r0%#?Jr>mdK
II;Vst0FRG1RsaA1
index 7991ee7a50703401c00aee71297564cd4755c481..156c26b941c12a13130e7a7c181d13300a85de89
GIT binary patch
literal 88
zc%17D@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6<UL&+Ln;`PB?2G(x7L}!$kNEc
kqo3#`!pg%J@xXwIAzIG(VVQKJ3{WY9r>mdKI;Vst01!SC>;M1&
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..959e1919d5a7a83a9c319de4d65ddaf6dc6c2763
GIT binary patch
literal 109
zc%17D@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UCY~;iAr*|t5<LkbJxzfh{>x6B
zz{uFh!Ff-a?~&O9p+bS}jK@2hEqD_O6oi80fl3Ux7>c+~q<V+<rvUXcc)I$ztaD0e
F0sx?19k&1g
--- a/browser/extensions/pdfjs/content/web/viewer.css
+++ b/browser/extensions/pdfjs/content/web/viewer.css
@@ -738,17 +738,16 @@ html[dir='rtl'] #findPrevious {
 }
 html[dir='rtl'] #findNext {
   margin-left: 3px;
 }
 
 .toolbarButton::before,
 .secondaryToolbarButton::before {
   /* All matching images have a size of 16x16
-   * (except for the print button: 18x16)
    * All relevant containers have a size of 32x25 */
   position: absolute;
   display: inline-block;
   top: 4px;
   left: 7px;
 }
 
 html[dir="ltr"] .secondaryToolbarButton::before {
@@ -811,24 +810,16 @@ html[dir='rtl'] .toolbarButton.pageDown:
 .toolbarButton.presentationMode::before,
 .secondaryToolbarButton.presentationMode::before {
   content: url(images/toolbarButton-presentationMode.png);
 }
 
 .toolbarButton.print::before,
 .secondaryToolbarButton.print::before {
   content: url(images/toolbarButton-print.png);
-  left: 6px;
-}
-
-html[dir="ltr"] .secondaryToolbarButton.print::before {
-  left: 3px;
-}
-html[dir="rtl"] .secondaryToolbarButton.print::before {
-  right: 3px;
 }
 
 .toolbarButton.openFile::before,
 .secondaryToolbarButton.openFile::before {
   content: url(images/toolbarButton-openFile.png);
 }
 
 .toolbarButton.download::before,
@@ -1484,26 +1475,24 @@ html[dir='rtl'] #documentPropertiesConta
 
 #viewer.textLayer-shadow .textLayer > div {
   background-color: rgba(255,255,255, .6);
   color: black;
 }
 
 .grab-to-pan-grab {
   cursor: url("images/grab.cur"), move !important;
-  cursor: -moz-grab !important;
   cursor: grab !important;
 }
 .grab-to-pan-grab *:not(input):not(textarea):not(button):not(select):not(:link) {
   cursor: inherit !important;
 }
 .grab-to-pan-grab:active,
 .grab-to-pan-grabbing {
   cursor: url("images/grabbing.cur"), move !important;
-  cursor: -moz-grabbing !important;
   cursor: grabbing !important;
 
   position: fixed;
   background: transparent;
   display: block;
   top: 0;
   left: 0;
   right: 0;
--- a/browser/extensions/pdfjs/content/web/viewer.js
+++ b/browser/extensions/pdfjs/content/web/viewer.js
@@ -4910,17 +4910,16 @@ var DocumentOutlineView = function docum
 };
 
 
 document.addEventListener('DOMContentLoaded', function webViewerLoad(evt) {
   PDFView.initialize();
 
   var file = window.location.href.split('#')[0];
 
-
   document.getElementById('openFile').setAttribute('hidden', 'true');
   document.getElementById('secondaryOpenFile').setAttribute('hidden', 'true');
 
   // Special debugging flags in the hash section of the URL.
   var hash = document.location.hash.substring(1);
   var hashParams = PDFView.parseQueryString(hash);
 
   if ('disableWorker' in hashParams) {
--- a/browser/themes/shared/customizableui/panelUIOverlay.inc.css
+++ b/browser/themes/shared/customizableui/panelUIOverlay.inc.css
@@ -717,27 +717,33 @@ toolbarpaletteitem[place="palette"] > #s
 }
 
 #edit-controls@inAnyPanel@ > toolbarbutton,
 #zoom-controls@inAnyPanel@ > toolbarbutton {
   border: 0;
   padding: .5em;
   margin: 0;
   -moz-box-flex: 1;
-  /* reduce the width with 2px for each button to compensate for two separators
-     of 3px. */
-  min-width: calc(@menuPanelButtonWidth@ - 2px);
-  max-width: calc(@menuPanelButtonWidth@ - 2px);
+  min-width: calc(@menuPanelButtonWidth@);
+  max-width: calc(@menuPanelButtonWidth@);
   /* We'd prefer to use height: auto here but it leads to layout bugs in the panel. Cope:
      1.2em for line height + 2 * .5em padding + margin on the label (2 * 2px) */
   height: calc(2.2em + 4px);
   max-height: none;
   -moz-box-orient: horizontal;
 }
 
+#edit-controls@inAnyPanel@ > #copy-button,
+#zoom-controls@inAnyPanel@ > #zoom-reset-button {
+  /* reduce the width with 2px for this button to compensate for two separators
+     of 1px. */
+  min-width: calc(@menuPanelButtonWidth@ - 2px);
+  max-width: calc(@menuPanelButtonWidth@ - 2px);
+}
+
 #edit-controls@inAnyPanel@ > toolbarbutton[disabled] > .toolbarbutton-icon,
 #zoom-controls@inAnyPanel@ > toolbarbutton[disabled] > .toolbarbutton-icon {
   opacity: .25;
 }
 
 #zoom-controls[cui-areatype="toolbar"] > #zoom-reset-button > .toolbarbutton-text {
 %ifdef XP_MACOSX
   min-width: 6ch;
@@ -757,29 +763,41 @@ toolbarpaletteitem[place="palette"] > #s
 #edit-controls@inAnyPanel@ > #cut-button:-moz-locale-dir(rtl),
 #edit-controls@inAnyPanel@ > #paste-button:-moz-locale-dir(ltr),
 #zoom-controls@inAnyPanel@ > #zoom-out-button:-moz-locale-dir(rtl),
 #zoom-controls@inAnyPanel@ > #zoom-in-button:-moz-locale-dir(ltr) {
   border-top-left-radius: 0;
   border-bottom-left-radius: 0;
 }
 
-#edit-controls > separator,
-#zoom-controls > separator {
+.toolbaritem-combined-buttons > separator {
   -moz-appearance: none;
   width: 3px;
   -moz-box-align: stretch;
   background-image: linear-gradient(to bottom, hsla(0,0%,100%,0), hsla(0,0%,100%,.3) 40%, hsla(0,0%,100%,.3) 60%, hsla(0,0%,100%,0)),
                     linear-gradient(to bottom, hsla(210,54%,20%,0), hsla(210,54%,20%,.15) 40%, hsla(210,54%,20%,.15) 60%, hsla(210,54%,20%,0)),
                     linear-gradient(to bottom, hsla(0,0%,100%,0), hsla(0,0%,100%,.3) 40%, hsla(0,0%,100%,.3) 60%, hsla(0,0%,100%,0));
   background-size: 1px, 1px, 1px;
   background-position: 0 0, 1px 0, 2px 0;
   background-repeat: no-repeat;
 }
 
+.toolbaritem-combined-buttons@inAnyPanel@ > separator {
+  margin: .5em 0;
+  width: 1px;
+  background: hsla(210,4%,10%,.15);
+  transition-property: margin;
+  transition-duration: 10ms;
+  transition-timing-function: ease;
+}
+
+.toolbaritem-combined-buttons@inAnyPanel@:hover > separator {
+  margin: 0;
+}
+
 #widget-overflow > .panel-arrowcontainer > .panel-arrowcontent {
   padding: 0;
 }
 
 .cui-widget-panelview,
 #widget-overflow-scroller {
   overflow-y: auto;
   overflow-x: hidden;
--- a/browser/themes/shared/devtools/app-manager/manifest-editor.inc.css
+++ b/browser/themes/shared/devtools/app-manager/manifest-editor.inc.css
@@ -49,19 +49,21 @@
 
 .manifest-editor .variables-view-variable {
   border-bottom: none;
 }
 
 .manifest-editor .variables-view-delete,
 .manifest-editor .variables-view-delete:hover,
 .manifest-editor .variables-view-delete:active,
+.manifest-editor .variable-or-property:focus .variables-view-delete,
 .manifest-editor .variables-view-add-property,
 .manifest-editor .variables-view-add-property:hover,
-.manifest-editor .variables-view-add-property:active {
+.manifest-editor .variables-view-add-property:active,
+.manifest-editor .variable-or-property:focus .variables-view-add-property {
   list-style-image: none;
   -moz-image-region: initial;
 }
 
 .manifest-editor .variables-view-delete::before,
 .manifest-editor .variables-view-add-property::before {
   width: 11px;
   height: 11px;
--- a/browser/themes/shared/tab-selected.svg
+++ b/browser/themes/shared/tab-selected.svg
@@ -30,17 +30,18 @@
         background-color: @fgTabBackgroundColor@;
         background-image: @fgTabTexture@;
         background-repeat: no-repeat;
         height: 100%;
         width: 100%;
       }
 
 %ifdef WINDOWS_AERO
-      @media (-moz-windows-default-theme) {
+      @media (-moz-windows-default-theme) and (-moz-os-version: windows-vista),
+             (-moz-windows-default-theme) and (-moz-os-version: windows-win7) {
         #tab-background-fill {
           background-color: @customToolbarColor@;
         }
       }
 %endif
     ]]></style>
 
 %include ../../base/content/tab-shape.inc.svg
copy from browser/themes/windows/Toolbar.png
copy to browser/themes/windows/Toolbar-XP.png
index dce0b0a7d994d7dd5114da346217794e7677f4fb..57f6f7c7f4995517548e6015887710922fb5dd1b
GIT binary patch
literal 9463
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
Gq5ltFE|6#d
--- a/browser/themes/windows/browser-aero.css
+++ b/browser/themes/windows/browser-aero.css
@@ -17,17 +17,18 @@
     margin-top: 1px;
   }
 
   .panel-promo-message {
     font-style: italic;
   }
 }
 
-@media (-moz-windows-default-theme) {
+@media (-moz-windows-default-theme) and (-moz-os-version: windows-vista),
+       (-moz-windows-default-theme) and (-moz-os-version: windows-win7) {
   #navigator-toolbox > toolbar:not(:-moz-lwtheme),
   #browser-bottombox:not(:-moz-lwtheme),
   .browserContainer > findbar {
     background-color: @customToolbarColor@;
   }
 
   .tab-background-middle[selected=true]:not(:-moz-lwtheme) {
     background-color: @customToolbarColor@;
@@ -164,18 +165,16 @@
     border-top: 1px solid @toolbarShadowColor@ !important;
     background-clip: padding-box;
   }
 
   /* This code is only needed for restored windows (i.e. sizemode=normal)
      because of the border radius on the toolbar below the tab bar. */
   #main-window[sizemode=normal] #nav-bar {
     border-top: 1px solid @toolbarShadowColor@;
-    border-top-left-radius: 2.5px;
-    border-top-right-radius: 2.5px;
     background-clip: padding-box;
   }
 
   /* Cover the top border of the adjacent toolbar */
   #TabsToolbar {
     margin-bottom: -1px;
   }
 
@@ -192,17 +191,28 @@
   }
 
   #appcontent:not(:-moz-lwtheme) {
     background-color: -moz-dialog;
   }
 
   #main-menubar:not(:-moz-lwtheme):not(:-moz-window-inactive) {
     background-color: rgba(255,255,255,.5);
-    border-radius: 4px;
+  }
+
+  @media (-moz-os-version: windows-vista),
+         (-moz-os-version: windows-win7) {
+    #main-window[sizemode=normal] #nav-bar {
+      border-top-left-radius: 2.5px;
+      border-top-right-radius: 2.5px;
+    }
+
+    #main-menubar:not(:-moz-lwtheme):not(:-moz-window-inactive) {
+      border-radius: 4px;
+    }
   }
 
   #ctrlTab-panel {
     background: transparent;
     -moz-appearance: -moz-win-glass;
     border-radius: 0;
     border: none;
     font: normal 1.2em "Segoe UI";
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -780,16 +780,25 @@ toolbarbutton[sdk-button="true"][cui-are
 .unified-nav-forward[_moz-menuactive]:-moz-locale-dir(ltr),
 .unified-nav-back[_moz-menuactive]:-moz-locale-dir(rtl) {
   list-style-image: url("chrome://browser/skin/menu-forward.png") !important;
 }
 
 #home-button.bookmark-item {
   list-style-image: url("chrome://browser/skin/Toolbar.png");
 }
+
+%ifndef WINDOWS_AERO
+@media (-moz-windows-theme: luna-silver) {
+  #home-button.bookmark-item {
+    list-style-image: url("chrome://browser/skin/Toolbar-lunaSilver.png");
+  }
+}
+%endif
+
 #home-button.bookmark-item:-moz-lwtheme-brighttext {
   list-style-image: url("chrome://browser/skin/Toolbar-inverted.png");
 }
 
 #sync-button[cui-areatype="toolbar"][status="active"] {
   /* !important because we need to override the glass selectors that trigger
    * use of the Toolbar-inverted image. Those use a list of all primary toolbar
    * buttons, so we can't easily fix those selectors. */
new file mode 100644
--- /dev/null
+++ b/browser/themes/windows/customizableui/panelUIOverlay-aero.css
@@ -0,0 +1,7 @@
+/* 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/. */
+
+%define WINDOWS_AERO
+%include panelUIOverlay.css
+%undef WINDOWS_AERO
--- a/browser/themes/windows/customizableui/panelUIOverlay.css
+++ b/browser/themes/windows/customizableui/panelUIOverlay.css
@@ -29,8 +29,29 @@
   padding: 0 2px;
   -moz-padding-start: 0;
   height: 18px;
 }
 
 .widget-overflow-list .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
   padding: 0 6px;
 }
+
+%ifdef WINDOWS_AERO
+/* Win8 and beyond. */
+@media not all and (-moz-os-version: windows-vista) {
+  @media not all and (-moz-os-version: windows-win7) {
+    panelview .toolbarbutton-1,
+    .subviewbutton,
+    .widget-overflow-list .toolbarbutton-1,
+    .panelUI-grid .toolbarbutton-1 > .toolbarbutton-menubutton-button,
+    #edit-controls@inAnyPanel@ > toolbarbutton,
+    #zoom-controls@inAnyPanel@ > toolbarbutton {
+      border-radius: 0;
+    }
+
+    #edit-controls@inAnyPanel@,
+    #zoom-controls@inAnyPanel@ {
+      border-radius: 0;
+    }
+  }
+}
+%endif
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -67,17 +67,17 @@ browser.jar:
         skin/classic/browser/Privacy-48.png
         skin/classic/browser/privatebrowsing-indicator.png
         skin/classic/browser/reload-stop-go.png
         skin/classic/browser/searchbar.css
         skin/classic/browser/searchbar-dropdown-arrow.png
         skin/classic/browser/Secure24.png
         skin/classic/browser/setDesktopBackground.css
         skin/classic/browser/slowStartup-16.png
-        skin/classic/browser/Toolbar.png
+        skin/classic/browser/Toolbar.png                             (Toolbar-XP.png)
         skin/classic/browser/Toolbar-inverted.png
         skin/classic/browser/Toolbar-lunaSilver.png
         skin/classic/browser/toolbarbutton-dropdown-arrow.png
         skin/classic/browser/toolbarbutton-dropdown-arrow-inverted.png
         skin/classic/browser/urlbar-arrow.png
         skin/classic/browser/urlbar-popup-blocked.png
         skin/classic/browser/urlbar-history-dropmarker.png
         skin/classic/browser/notification-pluginNormal.png           (../shared/plugins/notification-pluginNormal.png)
@@ -385,18 +385,19 @@ browser.jar:
         skin/classic/aero/browser/Privacy-48.png                     (Privacy-48-aero.png)
         skin/classic/aero/browser/privatebrowsing-indicator.png
         skin/classic/aero/browser/reload-stop-go.png
         skin/classic/aero/browser/searchbar.css
         skin/classic/aero/browser/searchbar-dropdown-arrow.png       (searchbar-dropdown-arrow-aero.png)
         skin/classic/aero/browser/Secure24.png                       (Secure24-aero.png)
         skin/classic/aero/browser/setDesktopBackground.css
         skin/classic/aero/browser/slowStartup-16.png
-        skin/classic/aero/browser/Toolbar.png                        (Toolbar-aero.png)
+        skin/classic/aero/browser/Toolbar.png
         skin/classic/aero/browser/Toolbar-inverted.png
+        skin/classic/aero/browser/Toolbar-aero.png
         skin/classic/aero/browser/toolbarbutton-dropdown-arrow.png
         skin/classic/aero/browser/toolbarbutton-dropdown-arrow-inverted.png
         skin/classic/aero/browser/urlbar-arrow.png
         skin/classic/aero/browser/urlbar-popup-blocked.png
         skin/classic/aero/browser/urlbar-history-dropmarker.png
         skin/classic/aero/browser/notification-pluginNormal.png     (../shared/plugins/notification-pluginNormal.png)
         skin/classic/aero/browser/notification-pluginAlert.png      (../shared/plugins/notification-pluginAlert.png)
         skin/classic/aero/browser/notification-pluginBlocked.png    (../shared/plugins/notification-pluginBlocked.png)
@@ -405,17 +406,17 @@ browser.jar:
         skin/classic/aero/browser/webRTC-sharingDevice-16.png
         skin/classic/aero/browser/customizableui/background-noise-toolbar.png  (customizableui/background-noise-toolbar.png)
         skin/classic/aero/browser/customizableui/customize-titleBar-toggle.png  (customizableui/customize-titleBar-toggle.png)
         skin/classic/aero/browser/customizableui/customizeFavicon.ico  (../shared/customizableui/customizeFavicon.ico)
         skin/classic/aero/browser/customizableui/customizeMode-gridTexture.png  (customizableui/customizeMode-gridTexture.png)
         skin/classic/aero/browser/customizableui/customizeMode-separatorHorizontal.png  (customizableui/customizeMode-separatorHorizontal.png)
         skin/classic/aero/browser/customizableui/customizeMode-separatorVertical.png  (customizableui/customizeMode-separatorVertical.png)
         skin/classic/aero/browser/customizableui/menuPanel-customizeFinish.png  (../shared/customizableui/menuPanel-customizeFinish.png)
-*       skin/classic/aero/browser/customizableui/panelUIOverlay.css  (customizableui/panelUIOverlay.css)
+*       skin/classic/aero/browser/customizableui/panelUIOverlay.css  (customizableui/panelUIOverlay-aero.css)
         skin/classic/aero/browser/customizableui/subView-arrow-back-inverted.png  (../shared/customizableui/subView-arrow-back-inverted.png)
 *       skin/classic/aero/browser/downloads/allDownloadsViewOverlay.css (downloads/allDownloadsViewOverlay-aero.css)
         skin/classic/aero/browser/downloads/buttons.png              (downloads/buttons-aero.png)
         skin/classic/aero/browser/downloads/contentAreaDownloadsView.css (downloads/contentAreaDownloadsView.css)
         skin/classic/aero/browser/downloads/download-glow.png        (downloads/download-glow.png)
         skin/classic/aero/browser/downloads/download-glow-menuPanel.png   (downloads/download-glow-menuPanel.png)
         skin/classic/aero/browser/downloads/download-glow-menuPanel-XPVista7.png   (downloads/download-glow-menuPanel-XPVista7.png)
         skin/classic/aero/browser/downloads/download-notification-finish.png (downloads/download-notification-finish.png)
@@ -637,10 +638,13 @@ browser.jar:
         skin/classic/aero/browser/devtools/tooltip/arrow-horizontal-dark@2x.png   (../shared/devtools/tooltip/arrow-horizontal-dark@2x.png)
         skin/classic/aero/browser/devtools/tooltip/arrow-vertical-dark.png   (../shared/devtools/tooltip/arrow-vertical-dark.png)
         skin/classic/aero/browser/devtools/tooltip/arrow-vertical-dark@2x.png   (../shared/devtools/tooltip/arrow-vertical-dark@2x.png)
         skin/classic/aero/browser/devtools/tooltip/arrow-horizontal-light.png   (../shared/devtools/tooltip/arrow-horizontal-light.png)
         skin/classic/aero/browser/devtools/tooltip/arrow-horizontal-light@2x.png   (../shared/devtools/tooltip/arrow-horizontal-light@2x.png)
         skin/classic/aero/browser/devtools/tooltip/arrow-vertical-light.png   (../shared/devtools/tooltip/arrow-vertical-light.png)
         skin/classic/aero/browser/devtools/tooltip/arrow-vertical-light@2x.png   (../shared/devtools/tooltip/arrow-vertical-light@2x.png)
 
+% override chrome://browser/skin/Toolbar.png               chrome://browser/skin/Toolbar-aero.png                  os=WINNT osversion=6
+% override chrome://browser/skin/Toolbar.png               chrome://browser/skin/Toolbar-aero.png                  os=WINNT osversion=6.1
+
 % override chrome://browser/skin/sync-horizontalbar.png          chrome://browser/skin/sync-horizontalbar-XPVista7.png          os=WINNT osversion<6.2
 % override chrome://browser/skin/syncProgress-horizontalbar.png  chrome://browser/skin/syncProgress-horizontalbar-XPVista7.png  os=WINNT osversion<6.2
--- a/browser/themes/windows/places/organizer-aero.css
+++ b/browser/themes/windows/places/organizer-aero.css
@@ -31,17 +31,18 @@
     border-top: none;
   }
 
   #placesToolbar {
     background-image: linear-gradient(@toolbarHighlight@, rgba(255,255,255,0));
   }
 }
 
-@media (-moz-windows-default-theme) {
+@media (-moz-windows-default-theme) and (-moz-os-version: windows-vista),
+       (-moz-windows-default-theme) and (-moz-os-version: windows-win7) {
   #placesView,
   #infoPane,
   #placesList,
   #placeContent {
     background-color: #EEF3FA;
   }
 
   #placesToolbar {
--- a/browser/themes/windows/places/organizer.css
+++ b/browser/themes/windows/places/organizer.css
@@ -12,16 +12,25 @@
   opacity: .4;
 }
 
 #back-button,
 #forward-button {
   list-style-image: url("chrome://browser/skin/Toolbar.png");
 }
 
+%ifndef WINDOWS_AERO
+@media (-moz-windows-theme: luna-silver) {
+  #back-button,
+  #forward-button {
+    list-style-image: url("chrome://browser/skin/Toolbar-lunaSilver.png");
+  }
+}
+%endif
+
 #back-button {
   -moz-image-region: rect(0, 54px, 18px, 36px);
 }
 
 #forward-button {
   -moz-image-region: rect(0, 72px, 18px, 54px);
 }
 
--- a/services/common/Makefile.in
+++ b/services/common/Makefile.in
@@ -1,14 +1,15 @@
 # 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/.
 
 modules := \
-  hawk.js \
+  hawkclient.js \
+  hawkrequest.js \
   storageservice.js \
   stringbundle.js \
   tokenserverclient.js \
   utils.js \
   $(NULL)
 
 pp_modules := \
   async.js \
rename from services/common/hawk.js
rename to services/common/hawkclient.js
--- a/services/common/hawk.js
+++ b/services/common/hawkclient.js
@@ -26,17 +26,17 @@
 
 this.EXPORTED_SYMBOLS = ["HawkClient"];
 
 const {interfaces: Ci, utils: Cu} = Components;
 
 Cu.import("resource://gre/modules/FxAccountsCommon.js");
 Cu.import("resource://services-common/utils.js");
 Cu.import("resource://services-crypto/utils.js");
-Cu.import("resource://services-common/rest.js");
+Cu.import("resource://services-common/hawkrequest.js");
 Cu.import("resource://gre/modules/Promise.jsm");
 
 /*
  * A general purpose client for making HAWK authenticated requests to a single
  * host.  Keeps track of the clock offset between the client and the host for
  * computation of the timestamp in the HAWK Authorization header.
  *
  * Clients should create one HawkClient object per each server they wish to
@@ -60,22 +60,28 @@ this.HawkClient.prototype = {
    *
    * @param restResponse
    *        A RESTResponse object from a RESTRequest
    *
    * @param errorString
    *        A string describing the error
    */
   _constructError: function(restResponse, errorString) {
-    return {
+    let errorObj = {
       error: errorString,
       message: restResponse.statusText,
       code: restResponse.status,
       errno: restResponse.status
     };
+    let retryAfter = restResponse.headers["retry-after"];
+    retryAfter = retryAfter ? parseInt(retryAfter) : retryAfter;
+    if (retryAfter) {
+      errorObj.retryAfter = retryAfter;
+    }
+    return errorObj;
   },
 
   /*
    *
    * Update clock offset by determining difference from date gives in the (RFC
    * 1123) Date header of a server response.  Because HAWK tolerates a window
    * of one minute of clock skew (so two minutes total since the skew can be
    * positive or negative), the simple method of calculating offset here is
new file mode 100644
--- /dev/null
+++ b/services/common/hawkrequest.js
@@ -0,0 +1,145 @@
+/* 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/. */
+
+"use strict";
+
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+this.EXPORTED_SYMBOLS = [
+  "HAWKAuthenticatedRESTRequest",
+];
+
+Cu.import("resource://gre/modules/Preferences.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Log.jsm");
+Cu.import("resource://services-common/rest.js");
+
+XPCOMUtils.defineLazyModuleGetter(this, "CryptoUtils",
+                                  "resource://services-crypto/utils.js");
+
+const Prefs = new Preferences("services.common.rest.");
+
+/**
+ * Single-use HAWK-authenticated HTTP requests to RESTish resources.
+ *
+ * @param uri
+ *        (String) URI for the RESTRequest constructor
+ *
+ * @param credentials
+ *        (Object) Optional credentials for computing HAWK authentication
+ *        header.
+ *
+ * @param payloadObj
+ *        (Object) Optional object to be converted to JSON payload
+ *
+ * @param extra
+ *        (Object) Optional extra params for HAWK header computation.
+ *        Valid properties are:
+ *
+ *          now:                 <current time in milliseconds>,
+ *          localtimeOffsetMsec: <local clock offset vs server>
+ *
+ * extra.localtimeOffsetMsec is the value in milliseconds that must be added to
+ * the local clock to make it agree with the server's clock.  For instance, if
+ * the local clock is two minutes ahead of the server, the time offset in
+ * milliseconds will be -120000.
+ */
+
+this.HAWKAuthenticatedRESTRequest =
+ function HawkAuthenticatedRESTRequest(uri, credentials, extra={}) {
+  RESTRequest.call(this, uri);
+
+  this.credentials = credentials;
+  this.now = extra.now || Date.now();
+  this.localtimeOffsetMsec = extra.localtimeOffsetMsec || 0;
+  this._log.trace("local time, offset: " + this.now + ", " + (this.localtimeOffsetMsec));
+
+  // Expose for testing
+  this._intl = getIntl();
+};
+HAWKAuthenticatedRESTRequest.prototype = {
+  __proto__: RESTRequest.prototype,
+
+  dispatch: function dispatch(method, data, onComplete, onProgress) {
+    let contentType = "text/plain";
+    if (method == "POST" || method == "PUT") {
+      contentType = "application/json";
+    }
+    if (this.credentials) {
+      let options = {
+        now: this.now,
+        localtimeOffsetMsec: this.localtimeOffsetMsec,
+        credentials: this.credentials,
+        payload: data && JSON.stringify(data) || "",
+        contentType: contentType,
+      };
+      let header = CryptoUtils.computeHAWK(this.uri, method, options);
+      this.setHeader("Authorization", header.field);
+      this._log.trace("hawk auth header: " + header.field);
+    }
+
+    this.setHeader("Content-Type", contentType);
+
+    this.setHeader("Accept-Language", this._intl.accept_languages);
+
+    return RESTRequest.prototype.dispatch.call(
+      this, method, data, onComplete, onProgress
+    );
+  }
+};
+
+// With hawk request, we send the user's accepted-languages with each request.
+// To keep the number of times we read this pref at a minimum, maintain the
+// preference in a stateful object that notices and updates itself when the
+// pref is changed.
+this.Intl = function Intl() {
+  // We won't actually query the pref until the first time we need it
+  this._accepted = "";
+  this._everRead = false;
+  this._log = Log.repository.getLogger("Services.common.RESTRequest");
+  this._log.level = Log.Level[Prefs.get("log.logger.rest.request")];
+  this.init();
+};
+
+this.Intl.prototype = {
+  init: function() {
+    Services.prefs.addObserver("intl.accept_languages", this, false);
+  },
+
+  uninit: function() {
+    Services.prefs.removeObserver("intl.accept_languages", this);
+  },
+
+  observe: function(subject, topic, data) {
+    this.readPref();
+  },
+
+  readPref: function() {
+    this._everRead = true;
+    try {
+      this._accepted = Services.prefs.getComplexValue(
+        "intl.accept_languages", Ci.nsIPrefLocalizedString).data;
+    } catch (err) {
+      this._log.error("Error reading intl.accept_languages pref: " + CommonUtils.exceptionStr(err));
+    }
+  },
+
+  get accept_languages() {
+    if (!this._everRead) {
+      this.readPref();
+    }
+    return this._accepted;
+  },
+};
+
+// Singleton getter for Intl, creating an instance only when we first need it.
+let intl = null;
+function getIntl() {
+  if (!intl) {
+    intl = new Intl();
+  }
+  return intl;
+}
+
--- a/services/common/rest.js
+++ b/services/common/rest.js
@@ -5,17 +5,16 @@
 #ifndef MERGED_COMPARTMENT
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 this.EXPORTED_SYMBOLS = [
   "RESTRequest",
   "RESTResponse",
   "TokenAuthenticatedRESTRequest",
-  "HAWKAuthenticatedRESTRequest",
 ];
 
 #endif
 
 Cu.import("resource://gre/modules/Preferences.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Log.jsm");
@@ -720,80 +719,8 @@ TokenAuthenticatedRESTRequest.prototype 
     this.setHeader("Authorization", sig.getHeader());
 
     return RESTRequest.prototype.dispatch.call(
       this, method, data, onComplete, onProgress
     );
   },
 };
 
-/**
- * Single-use HAWK-authenticated HTTP requests to RESTish resources.
- *
- * @param uri
- *        (String) URI for the RESTRequest constructor
- *
- * @param credentials
- *        (Object) Optional credentials for computing HAWK authentication
- *        header.
- *
- * @param payloadObj
- *        (Object) Optional object to be converted to JSON payload
- *
- * @param extra
- *        (Object) Optional extra params for HAWK header computation.
- *        Valid properties are:
- *
- *          now:                 <current time in milliseconds>,
- *          localtimeOffsetMsec: <local clock offset vs server>
- *
- * extra.localtimeOffsetMsec is the value in milliseconds that must be added to
- * the local clock to make it agree with the server's clock.  For instance, if
- * the local clock is two minutes ahead of the server, the time offset in
- * milliseconds will be -120000.
- */
-this.HAWKAuthenticatedRESTRequest =
- function HawkAuthenticatedRESTRequest(uri, credentials, extra={}) {
-  RESTRequest.call(this, uri);
-
-  this.credentials = credentials;
-  this.now = extra.now || Date.now();
-  this.localtimeOffsetMsec = extra.localtimeOffsetMsec || 0;
-  this._log.trace("local time, offset: " + this.now + ", " + (this.localtimeOffsetMsec));
-};
-HAWKAuthenticatedRESTRequest.prototype = {
-  __proto__: RESTRequest.prototype,
-
-  dispatch: function dispatch(method, data, onComplete, onProgress) {
-    let contentType = "text/plain";
-    if (method == "POST" || method == "PUT") {
-      contentType = "application/json";
-    }
-    if (this.credentials) {
-      let options = {
-        now: this.now,
-        localtimeOffsetMsec: this.localtimeOffsetMsec,
-        credentials: this.credentials,
-        payload: data && JSON.stringify(data) || "",
-        contentType: contentType,
-      };
-      let header = CryptoUtils.computeHAWK(this.uri, method, options);
-      this.setHeader("Authorization", header.field);
-      this._log.trace("hawk auth header: " + header.field);
-    }
-
-    this.setHeader("Content-Type", contentType);
-
-    try {
-      let acceptLanguage = Services.prefs.getComplexValue(
-          "intl.accept_languages", Ci.nsIPrefLocalizedString).data;
-      if (acceptLanguage) {
-        this.setHeader("Accept-Language", acceptLanguage);
-      }
-    } catch (err) {
-      this._log.error("Error reading intl.accept_languages pref: " + CommonUtils.exceptionStr(err));
-    }
-
-    return RESTRequest.prototype.dispatch.call(
-      this, method, data, onComplete, onProgress
-    );
-  }
-};
rename from services/common/tests/unit/test_hawk.js
rename to services/common/tests/unit/test_hawkclient.js
--- a/services/common/tests/unit/test_hawk.js
+++ b/services/common/tests/unit/test_hawkclient.js
@@ -1,15 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 Cu.import("resource://gre/modules/Promise.jsm");
-Cu.import("resource://services-common/hawk.js");
+Cu.import("resource://services-common/hawkclient.js");
 
 const SECOND_MS = 1000;
 const MINUTE_MS = SECOND_MS * 60;
 const HOUR_MS = MINUTE_MS * 60;
 
 const TEST_CREDS = {
   id: "eyJleHBpcmVzIjogMTM2NTAxMDg5OC4x",
   key: "qTZf4ZFpAMpMoeSsX3zVRjiqmNs=",
new file mode 100644
--- /dev/null
+++ b/services/common/tests/unit/test_hawkrequest.js
@@ -0,0 +1,203 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+Cu.import("resource://gre/modules/Log.jsm");
+Cu.import("resource://services-common/utils.js");
+Cu.import("resource://services-common/hawkrequest.js");
+
+function do_register_cleanup() {
+  Services.prefs.resetUserPrefs();
+
+  // remove the pref change listener
+  let hawk = new HAWKAuthenticatedRESTRequest("https://example.com");
+  hawk._intl.uninit();
+}
+
+function run_test() {
+  Log.repository.getLogger("Services.Common.RESTRequest").level =
+    Log.Level.Trace;
+  initTestLogging("Trace");
+
+  run_next_test();
+}
+
+
+add_test(function test_intl_accept_language() {
+  let testCount = 0;
+  let languages = [
+    "zu-NP;vo",     // Nepalese dialect of Zulu, defaulting to Volap√ľk
+    "fa-CG;ik",     // Congolese dialect of Farsei, defaulting to Inupiaq
+  ];
+
+  function setLanguage(lang) {
+    let acceptLanguage = Cc["@mozilla.org/supports-string;1"]
+                           .createInstance(Ci.nsISupportsString);
+    acceptLanguage.data = lang;
+    Services.prefs.setComplexValue(
+      "intl.accept_languages", Ci.nsISupportsString, acceptLanguage);
+  }
+
+  let hawk = new HAWKAuthenticatedRESTRequest("https://example.com");
+
+  Services.prefs.addObserver("intl.accept_languages", nextTest, false);
+  setLanguage(languages[testCount]);
+
+  function nextTest() {
+    CommonUtils.nextTick(function() {
+      if (testCount < 2) {
+        do_check_eq(hawk._intl.accept_languages, languages[testCount]);
+
+        testCount += 1;
+        setLanguage(languages[testCount]);
+        nextTest();
+        return;
+      }
+      Services.prefs.removeObserver("intl.accept_languages", nextTest);
+      run_next_test();
+      return;
+    });
+  }
+});
+
+add_test(function test_hawk_authenticated_request() {
+  let onProgressCalled = false;
+  let postData = {your: "data"};
+
+  // An arbitrary date - Feb 2, 1971.  It ends in a bunch of zeroes to make our
+  // computation with the hawk timestamp easier, since hawk throws away the
+  // millisecond values.
+  let then = 34329600000;
+
+  let clockSkew = 120000;
+  let timeOffset = -1 * clockSkew;
+  let localTime = then + clockSkew;
+
+  // Set the accept-languages pref to the Nepalese dialect of Zulu.
+  let acceptLanguage = Cc['@mozilla.org/supports-string;1'].createInstance(Ci.nsISupportsString);
+  acceptLanguage.data = 'zu-NP'; // omit trailing ';', which our HTTP libs snip
+  Services.prefs.setComplexValue('intl.accept_languages', Ci.nsISupportsString, acceptLanguage);
+
+  let credentials = {
+    id: "eyJleHBpcmVzIjogMTM2NTAxMDg5OC4x",
+    key: "qTZf4ZFpAMpMoeSsX3zVRjiqmNs=",
+    algorithm: "sha256"
+  };
+
+  let server = httpd_setup({
+    "/elysium": function(request, response) {
+      do_check_true(request.hasHeader("Authorization"));
+
+      // check that the header timestamp is our arbitrary system date, not
+      // today's date.  Note that hawk header timestamps are in seconds, not
+      // milliseconds.
+      let authorization = request.getHeader("Authorization");
+      let tsMS = parseInt(/ts="(\d+)"/.exec(authorization)[1], 10) * 1000;
+      do_check_eq(tsMS, then);
+
+      // This testing can be a little wonky. In an environment where
+      //   pref("intl.accept_languages") === 'en-US, en'
+      // the header is sent as:
+      //   'en-US,en;q=0.5'
+      // hence our fake value for acceptLanguage.
+      let lang = request.getHeader("Accept-Language");
+      do_check_eq(lang, acceptLanguage);
+
+      let message = "yay";
+      response.setStatusLine(request.httpVersion, 200, "OK");
+      response.bodyOutputStream.write(message, message.length);
+    }
+  });
+
+  function onProgress() {
+    onProgressCalled = true;
+  }
+
+  function onComplete(error) {
+    do_check_eq(200, this.response.status);
+    do_check_eq(this.response.body, "yay");
+    do_check_true(onProgressCalled);
+
+    Services.prefs.resetUserPrefs();
+    let pref = Services.prefs.getComplexValue(
+      "intl.accept_languages", Ci.nsIPrefLocalizedString);
+    do_check_neq(acceptLanguage.data, pref.data);
+
+    server.stop(run_next_test);
+  }
+
+  let url = server.baseURI + "/elysium";
+  let extra = {
+    now: localTime,
+    localtimeOffsetMsec: timeOffset
+  };
+
+  let request = new HAWKAuthenticatedRESTRequest(url, credentials, extra);
+
+  // Allow hawk._intl to respond to the language pref change
+  CommonUtils.nextTick(function() {
+    request.post(postData, onComplete, onProgress);
+  });
+});
+
+add_test(function test_hawk_language_pref_changed() {
+  let languages = [
+    "zu-NP",        // Nepalese dialect of Zulu
+    "fa-CG",        // Congolese dialect of Farsi
+  ];
+
+  let credentials = {
+    id: "eyJleHBpcmVzIjogMTM2NTAxMDg5OC4x",
+    key: "qTZf4ZFpAMpMoeSsX3zVRjiqmNs=",
+    algorithm: "sha256",
+  };
+
+  function setLanguage(lang) {
+    let acceptLanguage = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
+    acceptLanguage.data = lang;
+    Services.prefs.setComplexValue("intl.accept_languages", Ci.nsISupportsString, acceptLanguage);
+  }
+
+  let server = httpd_setup({
+    "/foo": function(request, response) {
+      do_check_eq(languages[1], request.getHeader("Accept-Language"));
+
+      response.setStatusLine(request.httpVersion, 200, "OK");
+    },
+  });
+
+  let url = server.baseURI + "/foo";
+  let postData = {};
+  let request;
+
+  setLanguage(languages[0]);
+
+  // A new request should create the stateful object for tracking the current
+  // language.
+  request = new HAWKAuthenticatedRESTRequest(url, credentials);
+  CommonUtils.nextTick(testFirstLanguage);
+
+  function testFirstLanguage() {
+    do_check_eq(languages[0], request._intl.accept_languages);
+
+    // Change the language pref ...
+    setLanguage(languages[1]); 
+    CommonUtils.nextTick(testRequest);
+  }
+
+  function testRequest() {
+    // Change of language pref should be picked up, which we can see on the
+    // server by inspecting the request headers.
+    request = new HAWKAuthenticatedRESTRequest(url, credentials);
+    request.post({}, function(error) {
+      do_check_null(error);
+      do_check_eq(200, this.response.status);
+
+      Services.prefs.resetUserPrefs();
+
+      server.stop(run_next_test);
+    });
+  }
+});
+
--- a/services/common/tests/unit/test_restrequest.js
+++ b/services/common/tests/unit/test_restrequest.js
@@ -1,18 +1,18 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
+"use strict";
+
 Cu.import("resource://gre/modules/NetUtil.jsm");
 Cu.import("resource://gre/modules/Log.jsm");
 Cu.import("resource://services-common/rest.js");
 Cu.import("resource://services-common/utils.js");
 
-//DEBUG = true;
-
 function run_test() {
   Log.repository.getLogger("Services.Common.RESTRequest").level =
     Log.Level.Trace;
   initTestLogging("Trace");
 
   run_next_test();
 }
 
@@ -833,84 +833,8 @@ add_test(function test_not_sending_cooki
   res.get(function (error) {
     do_check_null(error);
     do_check_true(this.response.success);
     do_check_eq("COOKIE!", this.response.body);
     server.stop(run_next_test);
   });
 });
 
-add_test(function test_hawk_authenticated_request() {
-  do_test_pending();
-
-  let onProgressCalled = false;
-  let postData = {your: "data"};
-
-  // An arbitrary date - Feb 2, 1971.  It ends in a bunch of zeroes to make our
-  // computation with the hawk timestamp easier, since hawk throws away the
-  // millisecond values.
-  let then = 34329600000;
-
-  let clockSkew = 120000;
-  let timeOffset = -1 * clockSkew;
-  let localTime = then + clockSkew;
-
-  // Set the accept-languages pref to the Nepalese dialect of Zulu.
-  let acceptLanguage = Cc['@mozilla.org/supports-string;1'].createInstance(Ci.nsISupportsString);
-  acceptLanguage.data = 'zu-NP'; // omit trailing ';', which our HTTP libs snip
-  Services.prefs.setComplexValue('intl.accept_languages', Ci.nsISupportsString, acceptLanguage);
-
-  let credentials = {
-    id: "eyJleHBpcmVzIjogMTM2NTAxMDg5OC4x",
-    key: "qTZf4ZFpAMpMoeSsX3zVRjiqmNs=",
-    algorithm: "sha256"
-  };
-
-  let server = httpd_setup({
-    "/elysium": function(request, response) {
-      do_check_true(request.hasHeader("Authorization"));
-
-      // check that the header timestamp is our arbitrary system date, not
-      // today's date.  Note that hawk header timestamps are in seconds, not
-      // milliseconds.
-      let authorization = request.getHeader("Authorization");
-      let tsMS = parseInt(/ts="(\d+)"/.exec(authorization)[1], 10) * 1000;
-      do_check_eq(tsMS, then);
-
-      // This testing can be a little wonky. In an environment where
-      //   pref("intl.accept_languages") === 'en-US, en'
-      // the header is sent as:
-      //   'en-US,en;q=0.5'
-      // hence our fake value for acceptLanguage.
-      let lang = request.getHeader('Accept-Language');
-      do_check_eq(lang, acceptLanguage);
-
-      let message = "yay";
-      response.setStatusLine(request.httpVersion, 200, "OK");
-      response.bodyOutputStream.write(message, message.length);
-    }
-  });
-
-  function onProgress() {
-    onProgressCalled = true;
-  }
-
-  function onComplete(error) {
-    do_check_eq(200, this.response.status);
-    do_check_eq(this.response.body, "yay");
-    do_check_true(onProgressCalled);
-    do_test_finished();
-    server.stop(run_next_test);
-  }
-
-  let url = server.baseURI + "/elysium";
-  let extra = {
-    now: localTime,
-    localtimeOffsetMsec: timeOffset
-  };
-  let request = new HAWKAuthenticatedRESTRequest(url, credentials, extra);
-  request.post(postData, onComplete, onProgress);
-
-  Services.prefs.resetUserPrefs();
-  let pref = Services.prefs.getComplexValue('intl.accept_languages',
-                                            Ci.nsIPrefLocalizedString);
-  do_check_neq(acceptLanguage.data, pref.data);
-});
--- a/services/common/tests/unit/xpcshell.ini
+++ b/services/common/tests/unit/xpcshell.ini
@@ -20,17 +20,18 @@ firefox-appdir = browser
 [test_utils_stackTrace.js]
 [test_utils_utf8.js]
 [test_utils_uuid.js]
 
 [test_async_chain.js]
 [test_async_querySpinningly.js]
 [test_bagheera_server.js]
 [test_bagheera_client.js]
-[test_hawk.js]
+[test_hawkclient.js]
+[test_hawkrequest.js]
 [test_observers.js]
 [test_restrequest.js]
 [test_tokenauthenticatedrequest.js]
 
 # Storage service APIs
 [test_storageservice_bso.js]
 [test_storageservice_client.js]
 # Bug 969624: Intermittent fail on Android 2.3 emulator
--- a/services/fxaccounts/FxAccountsClient.jsm
+++ b/services/fxaccounts/FxAccountsClient.jsm
@@ -5,33 +5,37 @@
 this.EXPORTED_SYMBOLS = ["FxAccountsClient"];
 
 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
 
 Cu.import("resource://gre/modules/Log.jsm");
 Cu.import("resource://gre/modules/Promise.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://services-common/utils.js");
-Cu.import("resource://services-common/hawk.js");
+Cu.import("resource://services-common/hawkclient.js");
 Cu.import("resource://services-crypto/utils.js");
 Cu.import("resource://gre/modules/FxAccountsCommon.js");
 Cu.import("resource://gre/modules/Credentials.jsm");
 
 let _host = "https://api.accounts.firefox.com/v1"
 try {
   _host = Services.prefs.getCharPref("identity.fxaccounts.auth.uri");
 } catch(keepDefault) {}
 
 const HOST = _host;
 this.FxAccountsClient = function(host = HOST) {
   this.host = host;
 
   // The FxA auth server expects requests to certain endpoints to be authorized
   // using Hawk.
   this.hawk = new HawkClient(host);
+
+  // Manage server backoff state. C.f.
+  // https://github.com/mozilla/fxa-auth-server/blob/master/docs/api.md#backoff-protocol
+  this.backoffError = null;
 };
 
 this.FxAccountsClient.prototype = {
 
   /**
    * Return client clock offset, in milliseconds, as determined by hawk client.
    * Provided because callers should not have to know about hawk
    * implementation.
@@ -301,16 +305,20 @@ this.FxAccountsClient.prototype = {
     return {
       algorithm: "sha256",
       key: out.slice(32, 64),
       extra: out.slice(64),
       id: CommonUtils.bytesAsHex(out.slice(0, 32))
     };
   },
 
+  _clearBackoff: function() {
+      this.backoffError = null;
+  },
+
   /**
    * A general method for sending raw API calls to the FxA auth server.
    * All request bodies and responses are JSON.
    *
    * @param path
    *        API endpoint path
    * @param method
    *        The HTTP request method
@@ -327,29 +335,47 @@ this.FxAccountsClient.prototype = {
    *          "error": "Bad Request", // string description of the error type
    *          "message": "the value of salt is not allowed to be undefined",
    *          "info": "https://docs.dev.lcip.og/errors/1234" // link to more info on the error
    *        }
    */
   _request: function hawkRequest(path, method, credentials, jsonPayload) {
     let deferred = Promise.defer();
 
+    // We were asked to back off.
+    if (this.backoffError) {
+      log.debug("Received new request during backoff, re-rejecting.");
+      deferred.reject(this.backoffError);
+      return deferred.promise;
+    }
+
     this.hawk.request(path, method, credentials, jsonPayload).then(
       (responseText) => {
         try {
           let response = JSON.parse(responseText);
           deferred.resolve(response);
         } catch (err) {
           log.error("json parse error on response: " + responseText);
           deferred.reject({error: err});
         }
       },
 
       (error) => {
         log.error("error " + method + "ing " + path + ": " + JSON.stringify(error));
+        if (error.retryAfter) {
+          log.debug("Received backoff response; caching error as flag.");
+          this.backoffError = error;
+          // Schedule clearing of cached-error-as-flag.
+          CommonUtils.namedTimer(
+            this._clearBackoff,
+            error.retryAfter * 1000,
+            this,
+            "fxaBackoffTimer"
+           );
+	}
         deferred.reject(error);
       }
     );
 
     return deferred.promise;
   },
 };
 
--- a/services/fxaccounts/tests/mochitest/test_invalidEmailCase.html
+++ b/services/fxaccounts/tests/mochitest/test_invalidEmailCase.html
@@ -24,17 +24,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <script class="testbody" type="text/javascript;version=1.8">
 
 SimpleTest.waitForExplicitFinish();
 
 Components.utils.import("resource://gre/modules/Promise.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 Components.utils.import("resource://gre/modules/FxAccounts.jsm");
 Components.utils.import("resource://gre/modules/FxAccountsClient.jsm");
-Components.utils.import("resource://services-common/hawk.js");
+Components.utils.import("resource://services-common/hawkclient.js");
 
 const TEST_SERVER =
   "http://mochi.test:8888/chrome/services/fxaccounts/tests/mochitest/file_invalidEmailCase.sjs?path=";
 
 let MockStorage = function() {
   this.data = null;
 };
 MockStorage.prototype = Object.freeze({
--- a/services/fxaccounts/tests/xpcshell/test_client.js
+++ b/services/fxaccounts/tests/xpcshell/test_client.js
@@ -97,16 +97,63 @@ add_task(function test_500_error() {
   } catch (e) {
     do_check_eq(500, e.code);
     do_check_eq("Internal Server Error", e.message);
   }
 
   yield deferredStop(server);
 });
 
+add_task(function test_backoffError() {
+  let method = "GET";
+  let server = httpd_setup({
+    "/retryDelay": function(request, response) {
+      response.setHeader("Retry-After", "30");
+      response.setStatusLine(request.httpVersion, 429, "Client has sent too many requests");
+      let message = "<h1>Ooops!</h1>";
+      response.bodyOutputStream.write(message, message.length);
+    },
+    "/duringDelayIShouldNotBeCalled": function(request, response) {
+      response.setStatusLine(request.httpVersion, 200, "OK");
+      let jsonMessage = "{\"working\": \"yes\"}";
+      response.bodyOutputStream.write(jsonMessage, jsonMessage.length);
+    },
+  });
+
+  let client = new FxAccountsClient(server.baseURI);
+
+  // Retry-After header sets client.backoffError
+  do_check_eq(client.backoffError, null);
+  try {
+    yield client._request("/retryDelay", method);
+  } catch (e) {
+    do_check_eq(429, e.code);
+    do_check_eq(30, e.retryAfter);
+    do_check_neq(typeof(client.fxaBackoffTimer), "undefined");
+    do_check_neq(client.backoffError, null);
+  }
+  // While delay is in effect, client short-circuits any requests
+  // and re-rejects with previous error.
+  try {
+    yield client._request("/duringDelayIShouldNotBeCalled", method);
+    throw new Error("I should not be reached");
+  } catch (e) {
+    do_check_eq(e.retryAfter, 30);
+    do_check_eq(e.message, "Client has sent too many requests");
+    do_check_neq(client.backoffError, null);
+  }
+  // Once timer fires, client nulls error out and HTTP calls work again.
+  client._clearBackoff();
+  let result = yield client._request("/duringDelayIShouldNotBeCalled", method);
+  do_check_eq(client.backoffError, null);
+  do_check_eq(result.working, "yes");
+
+  yield deferredStop(server);
+});
+
 add_task(function test_signUp() {
   let creationMessage = JSON.stringify({
     uid: "uid",
     sessionToken: "sessionToken",
     keyFetchToken: "keyFetchToken"
   });
   let errorMessage = JSON.stringify({code: 400, errno: 101, error: "account exists"});
   let created = false;
--- a/services/sync/tests/unit/test_browserid_identity.js
+++ b/services/sync/tests/unit/test_browserid_identity.js
@@ -3,17 +3,17 @@
 
 Cu.import("resource://gre/modules/FxAccounts.jsm");
 Cu.import("resource://services-sync/browserid_identity.js");
 Cu.import("resource://services-sync/rest.js");
 Cu.import("resource://services-sync/util.js");
 Cu.import("resource://services-common/utils.js");
 Cu.import("resource://services-crypto/utils.js");
 Cu.import("resource://testing-common/services/sync/utils.js");
-Cu.import("resource://services-common/hawk.js");
+Cu.import("resource://services-common/hawkclient.js");
 Cu.import("resource://gre/modules/FxAccounts.jsm");
 Cu.import("resource://gre/modules/FxAccountsClient.jsm");
 Cu.import("resource://gre/modules/FxAccountsCommon.js");
 
 const SECOND_MS = 1000;
 const MINUTE_MS = SECOND_MS * 60;
 const HOUR_MS = MINUTE_MS * 60;
 
--- a/testing/mozbase/mozlog/mozlog/__init__.py
+++ b/testing/mozbase/mozlog/mozlog/__init__.py
@@ -4,21 +4,21 @@
 
 """
 Mozlog aims to standardize log formatting within Mozilla.
 
 It simply wraps Python's logging_ module and adds a few convenience methods
 for logging test results and events.
 
 The structured submodule takes a different approach and implements a
-JSON-based logging protocol designed for recording test results.
-"""
+JSON-based logging protocol designed for recording test results."""
 
 from logger import *
 from loglistener import LogMessageServer
 from loggingmixin import LoggingMixin
 
 try:
     import structured
 except ImportError:
     # Structured logging doesn't work on python 2.6 which is still used on some
     # legacy test machines; https://bugzilla.mozilla.org/show_bug.cgi?id=864866
     pass
+
--- a/testing/mozbase/mozlog/mozlog/structured/commandline.py
+++ b/testing/mozbase/mozlog/mozlog/structured/commandline.py
@@ -10,16 +10,17 @@ import handlers
 import formatters
 
 log_formatters = {
     'raw': (formatters.JSONFormatter, "Raw structured log messages"),
     'unittest': (formatters.UnittestFormatter, "Unittest style output"),
     'xunit': (formatters.XUnitFormatter, "xUnit compatible XML"),
     'html': (formatters.HTMLFormatter, "HTML report"),
     'mach': (formatters.MachFormatter, "Uncolored mach-like output"),
+    'mach_terminal': (formatters.MachTerminalFormatter, "Colored mach-like output for use in a tty"),
 }
 
 
 def log_file(name):
     if name == "-":
         return sys.stdout
     else:
         return open(name, "w")
@@ -37,44 +38,45 @@ def add_logging_group(parser):
                    options added.
     """
     group = parser.add_argument_group("Output Logging",
                                       description="Options for logging output.\n"
                                       "Each option represents a possible logging format "
                                       "and takes a filename to write that format to, "
                                       "or '-' to write to stdout.")
     for name, (cls, help_str) in log_formatters.iteritems():
-        group.add_argument("--log-" + name, type=log_file,
+        group.add_argument("--log-" + name, action="append", type=log_file,
                            help=help_str)
 
 
 def setup_logging(suite, args, defaults):
     """
     Configure a structuredlogger based on command line arguments.
 
     :param suite: The name of the testsuite being run
-    :param args: The Namespace object produced by argparse from parsing
-                 command line arguments from a parser with logging arguments.
+    :param args: A dictionary of {argument_name:value} produced from
+                 parsing the command line arguments for the application
     :param defaults: A dictionary of {formatter name: output stream} to apply
                      when there is no logging supplied on the command line.
 
     :rtype: StructuredLogger
     """
     logger = StructuredLogger(suite)
     prefix = "log_"
     found = False
     found_stdout_logger = False
-    for name, value in args.iteritems():
-        if name.startswith(prefix) and value is not None:
-            found = True
-            if value == sys.stdout:
-                found_stdout_logger = True
-            formatter_cls = log_formatters[name[len(prefix):]][0]
-            logger.add_handler(handlers.StreamHandler(stream=value,
-                                                      formatter=formatter_cls()))
+    for name, values in args.iteritems():
+        if name.startswith(prefix) and values is not None:
+            for value in values:
+                found = True
+                if value == sys.stdout:
+                    found_stdout_logger = True
+                formatter_cls = log_formatters[name[len(prefix):]][0]
+                logger.add_handler(handlers.StreamHandler(stream=value,
+                                                          formatter=formatter_cls()))
 
     #If there is no user-specified logging, go with the default options
     if not found:
         for name, value in defaults.iteritems():
             formatter_cls = log_formatters[name][0]
             logger.add_handler(handlers.StreamHandler(stream=value,
                                                       formatter=formatter_cls()))
 
--- a/testing/mozbase/mozlog/mozlog/structured/formatters/__init__.py
+++ b/testing/mozbase/mozlog/mozlog/structured/formatters/__init__.py
@@ -3,9 +3,10 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 import json
 from unittest import UnittestFormatter
 from xunit import XUnitFormatter
 from html import HTMLFormatter
 from machformatter import MachFormatter, MachTerminalFormatter
 
-JSONFormatter = lambda: json.dumps
+def JSONFormatter():
+    return lambda x: json.dumps(x) + "\n"
--- a/testing/mozbase/mozlog/mozlog/structured/formatters/html/html.py
+++ b/testing/mozbase/mozlog/mozlog/structured/formatters/html/html.py
@@ -1,14 +1,15 @@
 #!/usr/bin/env python
 # 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/.
 
 import sys
+import json
 import datetime
 import os
 
 from .. import base
 
 from collections import defaultdict
 
 html = None
--- a/testing/mozbase/mozlog/mozlog/structured/formatters/machformatter.py
+++ b/testing/mozbase/mozlog/mozlog/structured/formatters/machformatter.py
@@ -24,17 +24,17 @@ class BaseMachFormatter(base.BaseFormatt
         self.last_time = None
 
     def __call__(self, data):
         s = base.BaseFormatter.__call__(self, data)
         if s is not None:
             return "%s %s\n" % (self.generic_formatter(data), s)
 
     def _get_test_id(self, data):
-        test_id = data["test"]
+        test_id = data.get("test")
         if isinstance(test_id, list):
             test_id = tuple(test_id)
         return test_id
 
     def generic_formatter(self, data):
         return "%s: %s" % (data["action"].upper(), data["thread"])
 
     def suite_start(self, data):
@@ -57,22 +57,23 @@ class BaseMachFormatter(base.BaseFormatt
 
         return "Harness status %s%s. Subtests passed %i/%i. Unexpected %i" % (
             data["status"], expected_str, subtests["pass"],
             subtests["count"], unexpected)
 
     def test_status(self, data):
         test = self._get_test_id(data)
         if test not in self.status_buffer:
-            self.buffer[test] = {"count": 0, "unexpected": 0, "pass": 0}
-        self.buffer[test]["count"] += 1
+            self.status_buffer[test] = {"count": 0, "unexpected": 0, "pass": 0}
+        self.status_buffer[test]["count"] += 1
+
         if "expected" in data:
-            self.buffer[test]["unexpected"] += 1
+            self.status_buffer[test]["unexpected"] += 1
         if data["status"] == "PASS":
-            self.buffer[test]["pass"] += 1
+            self.status_buffer[test]["pass"] += 1
 
     def process_output(self, data):
         return '"%s" (pid:%s command:%s)' % (data["data"],
                                              data["process"],
                                              data["command"])
 
     def log(self, data):
         return "%s %s" % (data["level"], data["message"])
@@ -127,19 +128,19 @@ class MachTerminalFormatter(BaseMachForm
         BaseMachFormatter.__init__(self,
                                    start_time=start_time,
                                    write_interval=write_interval,
                                    write_times=write_times)
 
     def __call__(self, data):
         s = BaseMachFormatter.__call__(self, data)
         if s is not None:
-            t = self.terminal.blue(format_seconds(self._time(entry)))
+            t = self.terminal.blue(format_seconds(self._time(data)))
 
-            return '%s %s' % (t, self._colorize(entry, s))
+            return '%s %s' % (t, self._colorize(data, s))
 
     def _colorize(self, data, s):
         if self.terminal is None:
             return s
 
         subtests = self._get_subtest_data(data)
 
         color = None
@@ -150,15 +151,17 @@ class MachTerminalFormatter(BaseMachForm
                 color = self.terminal.green
             else:
                 color = self.terminal.red
         elif data["action"] in ("suite_start", "suite_end", "test_start"):
             color = self.terminal.yellow
 
         if color is not None:
             result = color(s[:len_action]) + s[len_action:]
+        else:
+            result = s
 
         return result
 
 if __name__ == "__main__":
     base.format_file(sys.stdin,
                      handlers.StreamHandler(stream=sys.stdout,
                                             formatter=MachFormatter()))
--- a/testing/mozbase/mozlog/mozlog/structured/handlers/__init__.py
+++ b/testing/mozbase/mozlog/mozlog/structured/handlers/__init__.py
@@ -1,14 +1,16 @@
 # 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/.
 
 from threading import Lock
 
+from ..structuredlog import log_levels
+
 
 class BaseHandler(object):
     def __init__(self, formatter=str):
         self.formatter = formatter
         self.filters = []
 
     def add_filter(self, filter_func):
         self.filters.append(filter_func)
--- a/testing/mozbase/mozlog/mozlog/structured/structuredlog.py
+++ b/testing/mozbase/mozlog/mozlog/structured/structuredlog.py
@@ -99,22 +99,25 @@ class StructuredLogger(object):
         all_data = {"action": action,
                     "time": int(time.time() * 1000),
                     "thread": current_thread().name,
                     "pid": current_process().pid,
                     "source": self.name}
         all_data.update(data)
         return all_data
 
-    def suite_start(self, tests):
+    def suite_start(self, tests, run_info=None):
         """Log a suite_start message
 
         :param tests: List of test identifiers that will be run in the suite.
         """
-        self._log_data("suite_start", {"tests": tests})
+        data = {"tests": tests}
+        if run_info is not None:
+            data["run_info"] = run_info
+        self._log_data("suite_start", data)
 
     def suite_end(self):
         """Log a suite_end message"""
         self._log_data("suite_end")
 
     def test_start(self, test):
         """Log a test_start message
 
@@ -166,18 +169,17 @@ class StructuredLogger(object):
             data["message"] = message
         if expected != data["status"]:
             data["expected"] = expected
         if extra is not None:
             data["extra"] = extra
         self._log_data("test_end", data)
 
     def process_output(self, process, data, command=None):
-        """
-        Log output from a managed process.
+        """Log output from a managed process.
 
         :param process: A unique identifier for the process producing the output
                         (typically the pid)
         :param data: The output to log
         :param command: A string representing the full command line used to start
                         the process.
         """
         data = {"process": process, "data": data}
--- a/toolkit/components/places/PlacesUtils.jsm
+++ b/toolkit/components/places/PlacesUtils.jsm
@@ -1948,17 +1948,17 @@ TransactionItemCache.prototype = {
   get siteURI()
     this._siteURI || null,
   set index(v)
     this._index = (parseInt(v) >= 0 ? v : null),
   // Index can be 0.
   get index()
     this._index != null ? this._index : PlacesUtils.bookmarks.DEFAULT_INDEX,
   set annotations(v)
-    this._annotations = Array.isArray(v) ? JSON.parse(JSON.stringify(v)) : null,
+    this._annotations = Array.isArray(v) ? Cu.cloneInto(v, {}) : null,
   get annotations()
     this._annotations || null,
   set tags(v)
     this._tags = (v && Array.isArray(v) ? Array.slice(v) : null),
   get tags()
     this._tags || null,
 };
 
--- a/toolkit/devtools/Loader.jsm
+++ b/toolkit/devtools/Loader.jsm
@@ -53,16 +53,17 @@ BuiltinProvider.prototype = {
         "source-map": SourceMap,
       },
       paths: {
         // When you add a line to this mapping, don't forget to make a
         // corresponding addition to the SrcdirProvider mapping below as well.
         "": "resource://gre/modules/commonjs/",
         "main": "resource:///modules/devtools/main.js",
         "devtools": "resource:///modules/devtools",
+        "devtools/toolkit": "resource://gre/modules/devtools",
         "devtools/server": "resource://gre/modules/devtools/server",
         "devtools/toolkit/webconsole": "resource://gre/modules/devtools/toolkit/webconsole",
         "devtools/app-actor-front": "resource://gre/modules/devtools/app-actor-front.js",
         "devtools/styleinspector/css-logic": "resource://gre/modules/devtools/styleinspector/css-logic",
         "devtools/css-color": "resource://gre/modules/devtools/css-color",
         "devtools/output-parser": "resource://gre/modules/devtools/output-parser",
         "devtools/touch-events": "resource://gre/modules/devtools/touch-events",
         "devtools/client": "resource://gre/modules/devtools/client",
@@ -101,16 +102,17 @@ SrcdirProvider.prototype = {
   load: function() {
     let srcdir = Services.prefs.getComplexValue("devtools.loader.srcdir",
                                                 Ci.nsISupportsString);
     srcdir = OS.Path.normalize(srcdir.data.trim());
     let devtoolsDir = OS.Path.join(srcdir, "browser", "devtools");
     let toolkitDir = OS.Path.join(srcdir, "toolkit", "devtools");
     let mainURI = this.fileURI(OS.Path.join(devtoolsDir, "main.js"));
     let devtoolsURI = this.fileURI(devtoolsDir);
+    let toolkitURI = this.fileURI(toolkitDir);
     let serverURI = this.fileURI(OS.Path.join(toolkitDir, "server"));
     let webconsoleURI = this.fileURI(OS.Path.join(toolkitDir, "webconsole"));
     let appActorURI = this.fileURI(OS.Path.join(toolkitDir, "apps", "app-actor-front.js"));
     let cssLogicURI = this.fileURI(OS.Path.join(toolkitDir, "styleinspector", "css-logic"));
     let cssColorURI = this.fileURI(OS.Path.join(toolkitDir, "css-color"));
     let outputParserURI = this.fileURI(OS.Path.join(toolkitDir, "output-parser"));
     let touchEventsURI = this.fileURI(OS.Path.join(toolkitDir, "touch-events"));
     let clientURI = this.fileURI(OS.Path.join(toolkitDir, "client"));
@@ -122,16 +124,17 @@ SrcdirProvider.prototype = {
       modules: {
         "toolkit/loader": loader,
         "source-map": SourceMap,
       },
       paths: {
         "": "resource://gre/modules/commonjs/",
         "main": mainURI,
         "devtools": devtoolsURI,
+        "devtools/toolkit": toolkitURI,
         "devtools/server": serverURI,
         "devtools/toolkit/webconsole": webconsoleURI,
         "devtools/app-actor-front": appActorURI,
         "devtools/styleinspector/css-logic": cssLogicURI,
         "devtools/css-color": cssColorURI,
         "devtools/output-parser": outputParserURI,
         "devtools/touch-events": touchEventsURI,
         "devtools/client": clientURI,
--- a/toolkit/devtools/apps/Devices.jsm
+++ b/toolkit/devtools/apps/Devices.jsm
@@ -1,15 +1,15 @@
 /* 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/. */
 
 "use strict";
 
-Components.utils.import("resource:///modules/devtools/shared/event-emitter.js");
+Components.utils.import("resource://gre/modules/devtools/event-emitter.js");
 
 const EXPORTED_SYMBOLS = ["Devices"];
 
 let addonInstalled = false;
 
 const Devices = {
   _devices: {},
 
--- a/toolkit/devtools/apps/Simulator.jsm
+++ b/toolkit/devtools/apps/Simulator.jsm
@@ -1,15 +1,15 @@
 /* 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/. */
 
 "use strict";
 
-Components.utils.import("resource:///modules/devtools/shared/event-emitter.js");
+Components.utils.import("resource://gre/modules/devtools/event-emitter.js");
 
 const EXPORTED_SYMBOLS = ["Simulator"];
 
 const Simulator = {
   _simulators: {},
 
   register: function (version, simulator) {
     this._simulators[version] = simulator;
--- a/toolkit/devtools/client/connection-manager.js
+++ b/toolkit/devtools/client/connection-manager.js
@@ -3,17 +3,17 @@
 /* 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/. */
 
 "use strict";
 
 const {Cc, Ci, Cu} = require("chrome");
 const {setTimeout, clearTimeout} = require('sdk/timers');
-const EventEmitter = require("devtools/shared/event-emitter");
+const EventEmitter = require("devtools/toolkit/event-emitter");
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
 Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
 
 /**
  * Connection Manager.
  *
--- a/toolkit/devtools/client/dbg-client.jsm
+++ b/toolkit/devtools/client/dbg-client.jsm
@@ -474,32 +474,31 @@ DebuggerClient.prototype = {
    * @param array aListeners
    *        The console listeners you want to start.
    * @param function aOnResponse
    *        Called with the response packet and a WebConsoleClient
    *        instance (which will be undefined on error).
    */
   attachConsole:
   function (aConsoleActor, aListeners, aOnResponse) {
-    if (this._consoleClients.has(aConsoleActor)) {
-      setTimeout(() => aOnResponse({}, this._consoleClients.get(aConsoleActor)), 0);
-      return;
-    }
-
     let packet = {
       to: aConsoleActor,
       type: "startListeners",
       listeners: aListeners,
     };
 
     this.request(packet, (aResponse) => {
       let consoleClient;
       if (!aResponse.error) {
-        consoleClient = new WebConsoleClient(this, aConsoleActor);
-        this._consoleClients.set(aConsoleActor, consoleClient);
+        if (this._consoleClients.has(aConsoleActor)) {
+          consoleClient = this._consoleClients.get(aConsoleActor);
+        } else {
+          consoleClient = new WebConsoleClient(this, aConsoleActor);
+          this._consoleClients.set(aConsoleActor, consoleClient);
+        }
       }
       aOnResponse(aResponse, consoleClient);
     });
   },
 
   /**
    * Attach to a global-scoped thread actor for chrome debugging.
    *
rename from browser/devtools/shared/event-emitter.js
rename to toolkit/devtools/event-emitter.js
--- a/toolkit/devtools/server/actors/webbrowser.js
+++ b/toolkit/devtools/server/actors/webbrowser.js
@@ -1040,17 +1040,17 @@ BrowserAddonActor.prototype = {
  * is resumed before the navigation begins.
  *
  * @param BrowserTabActor aBrowserTabActor
  *        The tab actor associated with this listener.
  */
 function DebuggerProgressListener(aBrowserTabActor) {
   this._tabActor = aBrowserTabActor;
   this._tabActor._tabbrowser.addProgressListener(this);
-  let EventEmitter = devtools.require("devtools/shared/event-emitter");
+  let EventEmitter = devtools.require("devtools/toolkit/event-emitter");
   EventEmitter.decorate(this);
 }
 
 DebuggerProgressListener.prototype = {
   onStateChange:
   makeInfallible(function DPL_onStateChange(aProgress, aRequest, aFlag, aStatus) {
     let isStart = aFlag & Ci.nsIWebProgressListener.STATE_START;
     let isStop = aFlag & Ci.nsIWebProgressListener.STATE_STOP;
--- a/toolkit/devtools/tests/mochitest/chrome.ini
+++ b/toolkit/devtools/tests/mochitest/chrome.ini
@@ -1,1 +1,2 @@
+[test_eventemitter_basic.html]
 [test_loader_paths.html]
rename from browser/devtools/shared/test/browser_eventemitter_basic.js
rename to toolkit/devtools/tests/mochitest/test_eventemitter_basic.html
--- a/browser/devtools/shared/test/browser_eventemitter_basic.js
+++ b/toolkit/devtools/tests/mochitest/test_eventemitter_basic.html
@@ -1,154 +1,179 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
+<!DOCTYPE html>
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
 
-"use strict";
+<html>
 
-const promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {}).Promise;
-const EventEmitter = Cu.import("resource:///modules/devtools/shared/event-emitter.js", {}).EventEmitter;
+  <head>
+    <meta charset="utf8">
+    <title></title>
 
-function test() {
-  waitForExplicitFinish();
-
-  testEmitter();
-  testEmitter({});
+    <script type="application/javascript"
+            src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+    <link rel="stylesheet" type="text/css"
+          href="chrome://mochikit/content/tests/SimpleTest/test.css">
+  </head>
 
-  Task.spawn(testPromise).then(null, ok.bind(null, false)).then(finish);
-}
+  <body>
 
-function testEmitter(aObject) {
-  let emitter;
+    <script type="application/javascript;version=1.8">
+      "use strict";
 
-  if (aObject) {
-    emitter = aObject;
-    EventEmitter.decorate(emitter);
-  } else {
-    emitter = new EventEmitter();
-  }
+      const { utils: Cu } = Components;
+      const { Promise: promise } =
+        Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {});
+      const { EventEmitter } =
+        Cu.import("resource://gre/modules/devtools/event-emitter.js", {});
+      const { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
 
-  ok(emitter, "We have an event emitter");
+      SimpleTest.waitForExplicitFinish();
 
-  emitter.on("next", next);
-  emitter.emit("next", "abc", "def");
+      testEmitter();
+      testEmitter({});
+
+      Task.spawn(testPromise)
+          .then(null, ok.bind(null, false))
+          .then(SimpleTest.finish);
 
-  let beenHere1 = false;
-  function next(eventName, str1, str2) {
-    is(eventName, "next", "Got event");
-    is(str1, "abc", "Argument 1 is correct");
-    is(str2, "def", "Argument 2 is correct");
+      function testEmitter(aObject) {
+        let emitter;
 
-    ok(!beenHere1, "first time in next callback");
-    beenHere1 = true;
+        if (aObject) {
+          emitter = aObject;
+          EventEmitter.decorate(emitter);
+        } else {
+          emitter = new EventEmitter();
+        }
 
-    emitter.off("next", next);
+        ok(emitter, "We have an event emitter");
 
-    emitter.emit("next");
+        emitter.on("next", next);
+        emitter.emit("next", "abc", "def");
 
-    emitter.once("onlyonce", onlyOnce);
-
-    emitter.emit("onlyonce");
-    emitter.emit("onlyonce");
-  }
+        let beenHere1 = false;
+        function next(eventName, str1, str2) {
+          is(eventName, "next", "Got event");
+          is(str1, "abc", "Argument 1 is correct");
+          is(str2, "def", "Argument 2 is correct");
 
-  let beenHere2 = false;
-  function onlyOnce() {
-    ok(!beenHere2, "\"once\" listner has been called once");
-    beenHere2 = true;
-    emitter.emit("onlyonce");
+          ok(!beenHere1, "first time in next callback");
+          beenHere1 = true;
 
-    killItWhileEmitting();
-  }
+          emitter.off("next", next);
+
+          emitter.emit("next");
+
+          emitter.once("onlyonce", onlyOnce);
 
-  function killItWhileEmitting() {
-    function c1() {
-      ok(true, "c1 called");
-    }
-    function c2() {
-      ok(true, "c2 called");
-      emitter.off("tick", c3);
-    }
-    function c3() {
-      ok(false, "c3 should not be called");
-    }
-    function c4() {
-      ok(true, "c4 called");
-    }
+          emitter.emit("onlyonce");
+          emitter.emit("onlyonce");
+        }
+
+        let beenHere2 = false;
+        function onlyOnce() {
+          ok(!beenHere2, "\"once\" listner has been called once");
+          beenHere2 = true;
+          emitter.emit("onlyonce");
+
+          killItWhileEmitting();
+        }
 
-    emitter.on("tick", c1);
-    emitter.on("tick", c2);
-    emitter.on("tick", c3);
-    emitter.on("tick", c4);
-
-    emitter.emit("tick");
-
-    offAfterOnce();
-  }
+        function killItWhileEmitting() {
+          function c1() {
+            ok(true, "c1 called");
+          }
+          function c2() {
+            ok(true, "c2 called");
+            emitter.off("tick", c3);
+          }
+          function c3() {
+            ok(false, "c3 should not be called");
+          }
+          function c4() {
+            ok(true, "c4 called");
+          }
 
-  function offAfterOnce() {
-    let enteredC1 = false;
+          emitter.on("tick", c1);
+          emitter.on("tick", c2);
+          emitter.on("tick", c3);
+          emitter.on("tick", c4);
 
-    function c1() {
-      enteredC1 = true;
-    }
-
-    emitter.once("oao", c1);
-    emitter.off("oao", c1);
+          emitter.emit("tick");
 
-    emitter.emit("oao");
+          offAfterOnce();
+        }
 
-    ok(!enteredC1, "c1 should not be called");
-  }
-}
+        function offAfterOnce() {
+          let enteredC1 = false;
 
-function testPromise() {
-  let emitter = new EventEmitter();
-  let p = emitter.once("thing");
+          function c1() {
+            enteredC1 = true;
+          }
 
-  // Check that the promise is only resolved once event though we
-  // emit("thing") more than once
-  let firstCallbackCalled = false;
-  let check1 = p.then(arg => {
-    is(firstCallbackCalled, false, "first callback called only once");
-    firstCallbackCalled = true;
-    is(arg, "happened", "correct arg in promise");
-    return "rval from c1";
-  });
+          emitter.once("oao", c1);
+          emitter.off("oao", c1);
+
+          emitter.emit("oao");
+
+          ok(!enteredC1, "c1 should not be called");
+        }
+      }
+
+      function testPromise() {
+        let emitter = new EventEmitter();
+        let p = emitter.once("thing");
 
-  emitter.emit("thing", "happened", "ignored");
+        // Check that the promise is only resolved once event though we
+        // emit("thing") more than once
+        let firstCallbackCalled = false;
+        let check1 = p.then(arg => {
+          is(firstCallbackCalled, false, "first callback called only once");
+          firstCallbackCalled = true;
+          is(arg, "happened", "correct arg in promise");
+          return "rval from c1";
+        });
+
+        emitter.emit("thing", "happened", "ignored");
 
-  // Check that the promise is resolved asynchronously
-  let secondCallbackCalled = false;
-  let check2 = p.then(arg => {
-    ok(true, "second callback called");
-    is(arg, "happened", "correct arg in promise");
-    secondCallbackCalled = true;
-    is(arg, "happened", "correct arg in promise (a second time)");
-    return "rval from c2";
-  });
+        // Check that the promise is resolved asynchronously
+        let secondCallbackCalled = false;
+        let check2 = p.then(arg => {
+          ok(true, "second callback called");
+          is(arg, "happened", "correct arg in promise");
+          secondCallbackCalled = true;
+          is(arg, "happened", "correct arg in promise (a second time)");
+          return "rval from c2";
+        });
 
-  // Shouldn't call any of the above listeners
-  emitter.emit("thing", "trashinate");
-
-  // Check that we can still separate events with different names
-  // and that it works with no parameters
-  let pfoo = emitter.once("foo");
-  let pbar = emitter.once("bar");
+        // Shouldn't call any of the above listeners
+        emitter.emit("thing", "trashinate");
 
-  let check3 = pfoo.then(arg => {
-    ok(arg === undefined, "no arg for foo event");
-    return "rval from c3";
-  });
+        // Check that we can still separate events with different names
+        // and that it works with no parameters
+        let pfoo = emitter.once("foo");
+        let pbar = emitter.once("bar");
 
-  pbar.then(() => {
-    ok(false, "pbar should not be called");
-  });
+        let check3 = pfoo.then(arg => {
+          ok(arg === undefined, "no arg for foo event");
+          return "rval from c3";
+        });
+
+        pbar.then(() => {
+          ok(false, "pbar should not be called");
+        });
 
-  emitter.emit("foo");
+        emitter.emit("foo");
 
-  is(secondCallbackCalled, false, "second callback not called yet");
+        is(secondCallbackCalled, false, "second callback not called yet");
 
-  return promise.all([ check1, check2, check3 ]).then(args => {
-    is(args[0], "rval from c1", "callback 1 done good");
-    is(args[1], "rval from c2", "callback 2 done good");
-    is(args[2], "rval from c3", "callback 3 done good");
-  });
-}
+        return promise.all([ check1, check2, check3 ]).then(args => {
+          is(args[0], "rval from c1", "callback 1 done good");
+          is(args[1], "rval from c2", "callback 2 done good");
+          is(args[2], "rval from c3", "callback 3 done good");
+        });
+      }
+    </script>
+  </body>
+</html>
--- a/toolkit/modules/TelemetryTimestamps.jsm
+++ b/toolkit/modules/TelemetryTimestamps.jsm
@@ -1,14 +1,16 @@
 /* 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/. */
 
 this.EXPORTED_SYMBOLS = ["TelemetryTimestamps"];
 
+const Cu = Components.utils;
+
 /**
  * This module's purpose is to collect timestamps for important
  * application-specific events.
  *
  * The TelemetryPing component attaches the timestamps stored by this module to
  * the telemetry submission, substracting the process lifetime so that the times
  * are relative to process startup. The overall goal is to produce a basic
  * timeline of the startup process.
@@ -41,12 +43,12 @@ this.TelemetryTimestamps = {
   },
 
   /**
    * Returns a JS object containing all of the timeStamps as properties (can be
    * easily serialized to JSON). Used by TelemetryPing to retrieve the data
    * to attach to the telemetry submission.
    */
   get: function TT_get() {
-    // Return a copy of the object by passing it through JSON.
-    return JSON.parse(JSON.stringify(timeStamps));
+    // Return a copy of the object.
+    return Cu.cloneInto(timeStamps, {});
   }
 };