merge fx-team to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Tue, 01 Dec 2015 12:00:42 +0100
changeset 308831 66a6d7ec9534b9d7847b665142fef0dd87623768
parent 308806 89ae375e24d7560f613b75a585e9ed4238604494 (current diff)
parent 308830 3307a801862270294770042f6e9b19ff92ed5b24 (diff)
child 309025 974fe614d5299159dc16d98d97d76af653158d29
push id5513
push userraliiev@mozilla.com
push dateMon, 25 Jan 2016 13:55:34 +0000
treeherdermozilla-beta@5ee97dd05b5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone45.0a1
first release with
nightly linux32
66a6d7ec9534 / 45.0a1 / 20151201030226 / files
nightly linux64
66a6d7ec9534 / 45.0a1 / 20151201030226 / files
nightly mac
66a6d7ec9534 / 45.0a1 / 20151201030226 / files
nightly win32
66a6d7ec9534 / 45.0a1 / 20151201030226 / files
nightly win64
66a6d7ec9534 / 45.0a1 / 20151201030226 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge fx-team to mozilla-central a=merge
--- a/browser/base/content/tab-content.js
+++ b/browser/base/content/tab-content.js
@@ -508,26 +508,36 @@ var PageStyleHandler = {
       // Skip any stylesheets that don't match the screen media type.
       if (currentStyleSheet.media.length > 0) {
         let mediaQueryList = currentStyleSheet.media.mediaText;
         if (!content.matchMedia(mediaQueryList).matches) {
           continue;
         }
       }
 
-      // We won't send data URIs all of the way up to the parent, as these
-      // can be arbitrarily large.
-      let URI = Services.io.newURI(currentStyleSheet.href, null, null);
-      let sentURI = URI.scheme == "data" ? null : URI.spec;
+      let URI;
+      try {
+        URI = Services.io.newURI(currentStyleSheet.href, null, null);
+      } catch(e) {
+        if (e.result != Cr.NS_ERROR_MALFORMED_URI) {
+          throw e;
+        }
+      }
 
-      result.push({
-        title: currentStyleSheet.title,
-        disabled: currentStyleSheet.disabled,
-        href: sentURI,
-      });
+      if (URI) {
+        // We won't send data URIs all of the way up to the parent, as these
+        // can be arbitrarily large.
+        let sentURI = URI.scheme == "data" ? null : URI.spec;
+
+        result.push({
+          title: currentStyleSheet.title,
+          disabled: currentStyleSheet.disabled,
+          href: sentURI,
+        });
+      }
     }
 
     return result;
   },
 };
 PageStyleHandler.init();
 
 // Keep a reference to the translation content handler to avoid it it being GC'ed.
--- a/browser/components/customizableui/CustomizableUI.jsm
+++ b/browser/components/customizableui/CustomizableUI.jsm
@@ -51,16 +51,23 @@ const kSubviewEvents = [
 
 /**
  * The current version. We can use this to auto-add new default widgets as necessary.
  * (would be const but isn't because of testing purposes)
  */
 var kVersion = 4;
 
 /**
+ * Buttons removed from built-ins by version they were removed. kVersion must be
+ * bumped any time a new id is added to this. Use the button id as key, and
+ * version the button is removed in as the value.  e.g. "pocket-button": 5
+ */
+var ObsoleteBuiltinButtons = {};
+
+/**
  * gPalette is a map of every widget that CustomizableUI.jsm knows about, keyed
  * on their IDs.
  */
 var gPalette = new Map();
 
 /**
  * gAreas maps area IDs to Sets of properties about those areas. An area is a
  * place where a widget can be put.
@@ -149,16 +156,17 @@ var gModuleName = "[CustomizableUI]";
 var CustomizableUIInternal = {
   initialize: function() {
     LOG("Initializing");
 
     this.addListener(this);
     this._defineBuiltInWidgets();
     this.loadSavedState();
     this._introduceNewBuiltinWidgets();
+    this._markObsoleteBuiltinButtonsSeen();
 
     let panelPlacements = [
       "edit-controls",
       "zoom-controls",
       "new-window-button",
       "privatebrowsing-button",
       "save-page-button",
       "print-button",
@@ -347,16 +355,36 @@ var CustomizableUIInternal = {
       CustomizableUI.removeWidgetFromArea("loop-call-button");
     }
 
     if (currentVersion < 4) {
       CustomizableUI.removeWidgetFromArea("loop-button-throttled");
     }
   },
 
+  /**
+   * _markObsoleteBuiltinButtonsSeen
+   * when upgrading, ensure obsoleted buttons are in seen state.
+   */
+  _markObsoleteBuiltinButtonsSeen: function() {
+    if (!gSavedState)
+      return;
+    let currentVersion = gSavedState.currentVersion;
+    if (currentVersion >= kVersion)
+      return;
+    // we're upgrading, update state if necessary
+    for (let id in ObsoleteBuiltinButtons) {
+      let version = ObsoleteBuiltinButtons[id]
+      if (version == kVersion) {
+        gSeenWidgets.add(id);
+        gDirty = true;
+      }
+    }
+  },
+
   _placeNewDefaultWidgetsInArea: function(aArea) {
     let futurePlacedWidgets = gFuturePlacements.get(aArea);
     let savedPlacements = gSavedState && gSavedState.placements && gSavedState.placements[aArea];
     let defaultPlacements = gAreas.get(aArea).get("defaultPlacements");
     if (!savedPlacements || !savedPlacements.length || !futurePlacedWidgets || !defaultPlacements ||
         !defaultPlacements.length) {
       return;
     }
@@ -584,17 +612,17 @@ var CustomizableUIInternal = {
     try {
       let placements = gPlacements.get(area);
       if (!placements && areaProperties.has("legacy")) {
         let legacyState = aToolbar.getAttribute("currentset");
         if (legacyState) {
           legacyState = legacyState.split(",").filter(s => s);
         }
 
-        // Manually restore the state here, so the legacy state can be converted. 
+        // Manually restore the state here, so the legacy state can be converted.
         this.restoreStateForArea(area, legacyState);
         placements = gPlacements.get(area);
       }
 
       // Check that the current children and the current placements match. If
       // not, mark it as dirty:
       if (aExistingChildren.length != placements.length ||
           aExistingChildren.every((id, i) => id == placements[i])) {
@@ -1615,17 +1643,17 @@ var CustomizableUIInternal = {
       if (isInteractive) {
         return;
       }
     }
 
     // We can't use event.target because we might have passed a panelview
     // anonymous content boundary as well, and so target points to the
     // panelmultiview in that case. Unfortunately, this means we get
-    // anonymous child nodes instead of the real ones, so looking for the 
+    // anonymous child nodes instead of the real ones, so looking for the
     // 'stoooop, don't close me' attributes is more involved.
     let target = aEvent.originalTarget;
     let closemenu = "auto";
     let widgetType = "button";
     while (target.parentNode && target.localName != "panel") {
       closemenu = target.getAttribute("closemenu");
       widgetType = target.getAttribute("widget-type");
       if (closemenu == "none" || closemenu == "single" ||
@@ -1858,17 +1886,17 @@ var CustomizableUIInternal = {
 
     this.notifyListeners("onWidgetMoved", aWidgetId, oldPlacement.area,
                          oldPlacement.position, aPosition);
   },
 
   // Note that this does not populate gPlacements, which is done lazily so that
   // the legacy state can be migrated, which is only available once a browser
   // window is openned.
-  // The panel area is an exception here, since it has no legacy state and is 
+  // The panel area is an exception here, since it has no legacy state and is
   // built lazily - and therefore wouldn't otherwise result in restoring its
   // state immediately when a browser window opens, which is important for
   // other consumers of this API.
   loadSavedState: function() {
     let state = null;
     try {
       state = Services.prefs.getCharPref(kPrefCustomizationState);
     } catch (e) {
@@ -3838,17 +3866,17 @@ function XULWidgetGroupWrapper(aWidgetId
   this.__defineGetter__("instances", function() {
     return [this.forWindow(win) for ([win,] of gBuildWindows)];
   });
 
   Object.freeze(this);
 }
 
 /**
- * A XULWidgetSingleWrapper is a wrapper around a single instance of a XUL 
+ * A XULWidgetSingleWrapper is a wrapper around a single instance of a XUL
  * widget in a particular window.
  */
 function XULWidgetSingleWrapper(aWidgetId, aNode, aDocument) {
   this.isGroup = false;
 
   this.id = aWidgetId;
   this.type = "custom";
   this.provider = CustomizableUI.PROVIDER_XUL;
--- a/browser/components/sessionstore/FrameTree.jsm
+++ b/browser/components/sessionstore/FrameTree.jsm
@@ -214,16 +214,25 @@ FrameTreeInternal.prototype = {
   onStateChange: function (webProgress, request, stateFlags, status) {
     // Ignore state changes for subframes because we're only interested in the
     // top-document starting or stopping its load. We thus only care about any
     // changes to the root of the frame tree, not to any of its nodes/leafs.
     if (!webProgress.isTopLevel || webProgress.DOMWindow != this.content) {
       return;
     }
 
+    // onStateChange will be fired when loading the initial about:blank URI for
+    // a browser, which we don't actually care about. This is particularly for
+    // the case of unrestored background tabs, where the content has not yet
+    // been restored: we don't want to accidentally send any updates to the
+    // parent when the about:blank placeholder page has loaded.
+    if (!this._chromeGlobal.docShell.hasLoadedNonBlankURI) {
+      return;
+    }
+
     if (stateFlags & Ci.nsIWebProgressListener.STATE_START) {
       // Clear the list of frames until we can recollect it.
       this._frames.clear();
 
       // Notify observers that the frame tree has been reset.
       this.notifyObservers("onFrameTreeReset");
     } else if (stateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
       // The document and its resources have finished loading.
--- a/browser/components/sessionstore/test/browser_scrollPositions.js
+++ b/browser/components/sessionstore/test/browser_scrollPositions.js
@@ -1,15 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
-const URL = ROOT + "browser_scrollPositions_sample.html";
-const URL_FRAMESET = ROOT + "browser_scrollPositions_sample_frameset.html";
+const BASE = "http://example.com/browser/browser/components/sessionstore/test/"
+const URL = BASE + "browser_scrollPositions_sample.html";
+const URL_FRAMESET = BASE + "browser_scrollPositions_sample_frameset.html";
 
 // Randomized set of scroll positions we will use in this test.
 const SCROLL_X = Math.round(100 * (1 + Math.random()));
 const SCROLL_Y = Math.round(200 * (1 + Math.random()));
 const SCROLL_STR = SCROLL_X + "," + SCROLL_Y;
 
 const SCROLL2_X = Math.round(300 * (1 + Math.random()));
 const SCROLL2_Y = Math.round(400 * (1 + Math.random()));
@@ -97,15 +98,62 @@ add_task(function test_scroll_nested() {
   yield sendMessage(browser, "ss-test:setScrollPosition", {x: 0, y: 0, frame: 1});
   yield checkScroll(tab, null, "no scroll stored");
 
   // Cleanup.
   yield promiseRemoveTab(tab);
   yield promiseRemoveTab(tab2);
 });
 
+/**
+ * Test that scroll positions persist after restoring background tabs in
+ * a restored window (bug 1228518).
+ */
+add_task(function test_scroll_background_tabs() {
+  pushPrefs(["browser.sessionstore.restore_on_demand", true]);
+
+  let newWin = yield BrowserTestUtils.openNewBrowserWindow();
+  let tab = newWin.gBrowser.addTab(URL);
+  let browser = tab.linkedBrowser;
+  yield BrowserTestUtils.browserLoaded(browser);
+
+  // Scroll down a little.
+  yield sendMessage(browser, "ss-test:setScrollPosition", {x: SCROLL_X, y: SCROLL_Y});
+  yield checkScroll(tab, {scroll: SCROLL_STR}, "scroll is fine");
+
+  // Close the window
+  yield BrowserTestUtils.closeWindow(newWin);
+
+  // Now restore the window
+  newWin = ss.undoCloseWindow(0);
+
+  // Make sure to wait for the window to be restored.
+  yield BrowserTestUtils.waitForEvent(newWin, "SSWindowStateReady");
+
+  is(newWin.gBrowser.tabs.length, 2, "There should be two tabs");
+
+  // The second tab should be the one we loaded URL at still
+  tab = newWin.gBrowser.tabs[1];
+  yield promiseTabRestoring(tab);
+
+  ok(tab.hasAttribute("pending"), "Tab should be pending");
+  browser = tab.linkedBrowser;
+
+  // Ensure there are no pending queued messages in the child.
+  yield TabStateFlusher.flush(browser);
+
+  // Now check to see if the background tab remembers where it
+  // should be scrolled to.
+  newWin.gBrowser.selectedTab = tab;
+  yield promiseTabRestored(tab);
+
+  yield checkScroll(tab, {scroll: SCROLL_STR}, "scroll is still fine");
+
+  yield BrowserTestUtils.closeWindow(newWin);
+});
+
 function* checkScroll(tab, expected, msg) {
   let browser = tab.linkedBrowser;
   yield TabStateFlusher.flush(browser);
 
   let scroll = JSON.parse(ss.getTabState(tab)).scroll || null;
   is(JSON.stringify(scroll), JSON.stringify(expected), msg);
 }
--- a/browser/extensions/loop/bootstrap.js
+++ b/browser/extensions/loop/bootstrap.js
@@ -503,29 +503,29 @@ var WindowListener = {
         // Don't show the infobar if it's been permanently disabled from the menu.
         if (!this.MozLoopService.getLoopPref(kPrefBrowserSharingInfoBar)) {
           return;
         }
 
         let box = gBrowser.getNotificationBox();
         let paused = false;
         let bar = box.appendNotification(
-          this._getString("infobar_screenshare_browser_message"),
+          this._getString("infobar_screenshare_browser_message2"),
           kBrowserSharingNotificationId,
           // Icon is defined in browser theme CSS.
           null,
           box.PRIORITY_WARNING_LOW,
           [{
             label: this._getString("infobar_button_pause_label"),
             accessKey: this._getString("infobar_button_pause_accesskey"),
             isDefault: false,
             callback: (event, buttonInfo, buttonNode) => {
               paused = !paused;
               bar.label = paused ? this._getString("infobar_screenshare_paused_browser_message") :
-                this._getString("infobar_screenshare_browser_message");
+                this._getString("infobar_screenshare_browser_message2");
               bar.classList.toggle("paused", paused);
               buttonNode.label = paused ? this._getString("infobar_button_resume_label") :
                 this._getString("infobar_button_pause_label");
               buttonNode.accessKey = paused ? this._getString("infobar_button_resume_accesskey") :
                 this._getString("infobar_button_pause_accesskey");
               return true;
             }
           },
--- a/browser/extensions/loop/content/shared/js/loopapi-client.js
+++ b/browser/extensions/loop/content/shared/js/loopapi-client.js
@@ -146,17 +146,21 @@ var loop = loop || {};
   loop.subscribe = function subscribe(name, callback) {
     if (!gListeningForPushMessages) {
       gRootObj.addMessageListener(kPushMessageName, gListeningForPushMessages = function(message) {
         var eventName = message.data[0];
         if (!gSubscriptionsMap[eventName]) {
           return;
         }
         gSubscriptionsMap[eventName].forEach(function(cb) {
-          cb.apply(null, message.data[1]);
+          var data = message.data[1];
+          if (!Array.isArray(data)) {
+            data = [data];
+          }
+          cb.apply(null, data);
         });
       });
     }
 
     if (!gSubscriptionsMap[name]) {
       gSubscriptionsMap[name] = [];
     }
     gSubscriptionsMap[name].push(callback);
--- a/browser/extensions/loop/run-all-loop-tests.sh
+++ b/browser/extensions/loop/run-all-loop-tests.sh
@@ -11,17 +11,17 @@ fi
 set -e
 
 # Main tests
 
 LOOPDIR=browser/extensions/loop
 ESLINT=standalone/node_modules/.bin/eslint
 if [ -x "${LOOPDIR}/${ESLINT}" ]; then
   echo 'running eslint; see http://eslint.org/docs/rules/ for error info'
-  (cd ${LOOPDIR} && ./${ESLINT} --ext .js --ext .jsm --ext .jsx .)
+  (./${LOOPDIR}/${ESLINT} --ext .js --ext .jsm --ext .jsx ${LOOPDIR})
   if [ $? != 0 ]; then
     exit 1;
   fi
   echo 'eslint run finished.'
 fi
 
 # Build tests coverage.
 MISSINGDEPSMSG="\nMake sure all dependencies are up to date by running
--- a/browser/extensions/loop/test/shared/loopapi-client_test.js
+++ b/browser/extensions/loop/test/shared/loopapi-client_test.js
@@ -238,16 +238,26 @@ describe("loopapi-client", function() {
 
       sinon.assert.calledOnce(stub1);
       sinon.assert.calledWithExactly(stub1, "Foo", "Bar");
       sinon.assert.calledOnce(stub2);
       sinon.assert.calledWithExactly(stub2, "Foo", "Bar");
       sinon.assert.calledOnce(stub3);
       sinon.assert.calledWithExactly(stub3, "Foo", "Bar");
     });
+
+    it("should invoke subscription with non-array arguments too", function() {
+      var stub = sinon.stub();
+      loop.subscribe("LoopStatusChanged", stub);
+
+      sendMessage({ data: ["LoopStatusChanged", "Foo"] });
+
+      sinon.assert.calledOnce(stub);
+      sinon.assert.calledWithExactly(stub, "Foo");
+    });
   });
 
   describe("unsubscribe", function() {
     it("should remove subscriptions from the map", function() {
       var handler = function() {};
       loop.subscribe("LoopStatusChanged", handler);
 
       loop.unsubscribe("LoopStatusChanged", handler);
--- a/browser/extensions/pdfjs/README.mozilla
+++ b/browser/extensions/pdfjs/README.mozilla
@@ -1,3 +1,3 @@
 This is the pdf.js project output, https://github.com/mozilla/pdf.js
 
-Current extension version is: 1.3.14
+Current extension version is: 1.3.42
--- a/browser/extensions/pdfjs/content/PdfJs.jsm
+++ b/browser/extensions/pdfjs/content/PdfJs.jsm
@@ -7,16 +7,21 @@
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+/* jshint esnext:true */
+/* globals Components, Services, XPCOMUtils, PdfjsChromeUtils,
+           PdfjsContentUtils, DEFAULT_PREFERENCES, PdfStreamConverter */
+
+'use strict';
 
 var EXPORTED_SYMBOLS = ['PdfJs'];
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 const Cm = Components.manager;
 const Cu = Components.utils;
--- a/browser/extensions/pdfjs/content/PdfjsChromeUtils.jsm
+++ b/browser/extensions/pdfjs/content/PdfjsChromeUtils.jsm
@@ -7,16 +7,20 @@
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+/* jshint esnext:true */
+/* globals Components, Services, XPCOMUtils, DEFAULT_PREFERENCES */
+
+'use strict';
 
 var EXPORTED_SYMBOLS = ['PdfjsChromeUtils'];
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 const Cu = Components.utils;
 
--- a/browser/extensions/pdfjs/content/build/pdf.js
+++ b/browser/extensions/pdfjs/content/build/pdf.js
@@ -15,18 +15,18 @@
 /*jshint globalstrict: false */
 /* globals PDFJS */
 
 // Initializing PDFJS global object (if still undefined)
 if (typeof PDFJS === 'undefined') {
   (typeof window !== 'undefined' ? window : this).PDFJS = {};
 }
 
-PDFJS.version = '1.3.14';
-PDFJS.build = 'df46b64';
+PDFJS.version = '1.3.42';
+PDFJS.build = '84a47f8';
 
 (function pdfjsWrapper() {
   // Use strict in our context only - users might not want it
   'use strict';
 
 
 
 var globalScope = (typeof window === 'undefined') ? this : window;
@@ -55,16 +55,29 @@ var ImageKind = {
 };
 
 var AnnotationType = {
   WIDGET: 1,
   TEXT: 2,
   LINK: 3
 };
 
+var AnnotationFlag = {
+  INVISIBLE: 0x01,
+  HIDDEN: 0x02,
+  PRINT: 0x04,
+  NOZOOM: 0x08,
+  NOROTATE: 0x10,
+  NOVIEW: 0x20,
+  READONLY: 0x40,
+  LOCKED: 0x80,
+  TOGGLENOVIEW: 0x100,
+  LOCKEDCONTENTS: 0x200
+};
+
 var AnnotationBorderStyleType = {
   SOLID: 1,
   DASHED: 2,
   BEVELED: 3,
   INSET: 4,
   UNDERLINE: 5
 };
 
@@ -1181,78 +1194,79 @@ PDFJS.createObjectURL = (function create
       var d3 = i + 1 < ii ? ((b2 & 0xF) << 2) | (b3 >> 6) : 64;
       var d4 = i + 2 < ii ? (b3 & 0x3F) : 64;
       buffer += digits[d1] + digits[d2] + digits[d3] + digits[d4];
     }
     return buffer;
   };
 })();
 
-function MessageHandler(name, comObj) {
-  this.name = name;
+function MessageHandler(sourceName, targetName, comObj) {
+  this.sourceName = sourceName;
+  this.targetName = targetName;
   this.comObj = comObj;
   this.callbackIndex = 1;
   this.postMessageTransfers = true;
   var callbacksCapabilities = this.callbacksCapabilities = {};
   var ah = this.actionHandler = {};
 
-  ah['console_log'] = [function ahConsoleLog(data) {
-    console.log.apply(console, data);
-  }];
-  ah['console_error'] = [function ahConsoleError(data) {
-    console.error.apply(console, data);
-  }];
-  ah['_unsupported_feature'] = [function ah_unsupportedFeature(data) {
-    UnsupportedManager.notify(data);
-  }];
-
-  comObj.onmessage = function messageHandlerComObjOnMessage(event) {
+  this._onComObjOnMessage = function messageHandlerComObjOnMessage(event) {
     var data = event.data;
+    if (data.targetName !== this.sourceName) {
+      return;
+    }
     if (data.isReply) {
       var callbackId = data.callbackId;
       if (data.callbackId in callbacksCapabilities) {
         var callback = callbacksCapabilities[callbackId];
         delete callbacksCapabilities[callbackId];
         if ('error' in data) {
           callback.reject(data.error);
         } else {
           callback.resolve(data.data);
         }
       } else {
         error('Cannot resolve callback ' + callbackId);
       }
     } else if (data.action in ah) {
       var action = ah[data.action];
       if (data.callbackId) {
+        var sourceName = this.sourceName;
+        var targetName = data.sourceName;
         Promise.resolve().then(function () {
           return action[0].call(action[1], data.data);
         }).then(function (result) {
           comObj.postMessage({
+            sourceName: sourceName,
+            targetName: targetName,
             isReply: true,
             callbackId: data.callbackId,
             data: result
           });
         }, function (reason) {
           if (reason instanceof Error) {
             // Serialize error to avoid "DataCloneError"
             reason = reason + '';
           }
           comObj.postMessage({
+            sourceName: sourceName,
+            targetName: targetName,
             isReply: true,
             callbackId: data.callbackId,
             error: reason
           });
         });
       } else {
         action[0].call(action[1], data.data);
       }
     } else {
       error('Unknown action from worker: ' + data.action);
     }
-  };
+  }.bind(this);
+  comObj.addEventListener('message', this._onComObjOnMessage);
 }
 
 MessageHandler.prototype = {
   on: function messageHandlerOn(actionName, handler, scope) {
     var ah = this.actionHandler;
     if (ah[actionName]) {
       error('There is already an actionName called "' + actionName + '"');
     }
@@ -1261,16 +1275,18 @@ MessageHandler.prototype = {
   /**
    * Sends a message to the comObj to invoke the action with the supplied data.
    * @param {String} actionName Action to call.
    * @param {JSON} data JSON data to send.
    * @param {Array} [transfers] Optional list of transfers/ArrayBuffers
    */
   send: function messageHandlerSend(actionName, data, transfers) {
     var message = {
+      sourceName: this.sourceName,
+      targetName: this.targetName,
       action: actionName,
       data: data
     };
     this.postMessage(message, transfers);
   },
   /**
    * Sends a message to the comObj to invoke the action with the supplied data.
    * Expects that other side will callback with the response.
@@ -1278,16 +1294,18 @@ MessageHandler.prototype = {
    * @param {JSON} data JSON data to send.
    * @param {Array} [transfers] Optional list of transfers/ArrayBuffers.
    * @returns {Promise} Promise to be resolved with response data.
    */
   sendWithPromise:
     function messageHandlerSendWithPromise(actionName, data, transfers) {
     var callbackId = this.callbackIndex++;
     var message = {
+      sourceName: this.sourceName,
+      targetName: this.targetName,
       action: actionName,
       data: data,
       callbackId: callbackId
     };
     var capability = createPromiseCapability();
     this.callbacksCapabilities[callbackId] = capability;
     try {
       this.postMessage(message, transfers);
@@ -1303,16 +1321,20 @@ MessageHandler.prototype = {
    * @param transfers List of transfers/ArrayBuffers, or undefined.
    */
   postMessage: function (message, transfers) {
     if (transfers && this.postMessageTransfers) {
       this.comObj.postMessage(message, transfers);
     } else {
       this.comObj.postMessage(message);
     }
+  },
+
+  destroy: function () {
+    this.comObj.removeEventListener('message', this._onComObjOnMessage);
   }
 };
 
 function loadJpegStream(id, imageUrl, objs) {
   var img = new Image();
   img.onload = (function loadJpegStream_onloadClosure() {
     objs.resolve(id, img);
   });
@@ -1471,16 +1493,19 @@ PDFJS.verbosity = (PDFJS.verbosity === u
  * @var {number}
  */
 PDFJS.maxCanvasPixels = (PDFJS.maxCanvasPixels === undefined ?
                          16777216 : PDFJS.maxCanvasPixels);
 
 /**
  * (Deprecated) Opens external links in a new window if enabled.
  * The default behavior opens external links in the PDF.js window.
+ *
+ * NOTE: This property has been deprecated, please use
+ *       `PDFJS.externalLinkTarget = PDFJS.LinkTarget.BLANK` instead.
  * @var {boolean}
  */
 PDFJS.openExternalLinksInNewWindow = (
   PDFJS.openExternalLinksInNewWindow === undefined ?
     false : PDFJS.openExternalLinksInNewWindow);
 
 /**
  * Specifies the |target| attribute for external links.
@@ -1520,16 +1545,18 @@ PDFJS.isEvalSupported = (PDFJS.isEvalSup
  *   all of the pdf data. Used by the extension since some data is already
  *   loaded before the switch to range requests.
  * @property {number}     length - The PDF file length. It's used for progress
  *   reports and range requests operations.
  * @property {PDFDataRangeTransport} range
  * @property {number}     rangeChunkSize - Optional parameter to specify
  *   maximum number of bytes fetched per range request. The default value is
  *   2^16 = 65536.
+ * @property {PDFWorker}  worker - The worker that will be used for the loading
+ *   and parsing of the PDF data.
  */
 
 /**
  * @typedef {Object} PDFDocumentStats
  * @property {Array} streamTypes - Used stream types in the document (an item
  *   is set to true if specific stream ID was used in the document).
  * @property {Array} fontTypes - Used font type in the document (an item is set
  *   to true if specific font ID was used in the document).
@@ -1582,17 +1609,16 @@ PDFJS.getDocument = function getDocument
       }
     }
     src = Object.create(src);
     src.range = pdfDataRangeTransport;
   }
   task.onPassword = passwordCallback || null;
   task.onProgress = progressCallback || null;
 
-  var workerInitializedCapability, transport;
   var source;
   if (typeof src === 'string') {
     source = { url: src };
   } else if (isArrayBuffer(src)) {
     source = { data: src };
   } else if (src instanceof PDFDataRangeTransport) {
     source = { range: src };
   } else {
@@ -1603,22 +1629,28 @@ PDFJS.getDocument = function getDocument
     if (!src.url && !src.data && !src.range) {
       error('Invalid parameter object: need either .data, .range or .url');
     }
 
     source = src;
   }
 
   var params = {};
+  var rangeTransport = null;
+  var worker = null;
   for (var key in source) {
     if (key === 'url' && typeof window !== 'undefined') {
       // The full path is required in the 'url' field.
       params[key] = combineUrl(window.location.href, source[key]);
       continue;
     } else if (key === 'range') {
+      rangeTransport = source[key];
+      continue;
+    } else if (key === 'worker') {
+      worker = source[key];
       continue;
     } else if (key === 'data' && !(source[key] instanceof Uint8Array)) {
       // Converting string or array-like data to Uint8Array.
       var pdfBytes = source[key];
       if (typeof pdfBytes === 'string') {
         params[key] = stringToBytes(pdfBytes);
       } else if (typeof pdfBytes === 'object' && pdfBytes !== null &&
                  !isNaN(pdfBytes.length)) {
@@ -1629,37 +1661,108 @@ PDFJS.getDocument = function getDocument
         error('Invalid PDF binary data: either typed array, string or ' +
               'array-like object is expected in the data property.');
       }
       continue;
     }
     params[key] = source[key];
   }
 
-  params.rangeChunkSize = source.rangeChunkSize || DEFAULT_RANGE_CHUNK_SIZE;
-
-  workerInitializedCapability = createPromiseCapability();
-  transport = new WorkerTransport(workerInitializedCapability, source.range);
-  workerInitializedCapability.promise.then(function transportInitialized() {
-    transport.fetchDocument(task, params);
-  });
-  task._transport = transport;
+  params.rangeChunkSize = params.rangeChunkSize || DEFAULT_RANGE_CHUNK_SIZE;
+
+  if (!worker) {
+    // Worker was not provided -- creating and owning our own.
+    worker = new PDFWorker();
+    task._worker = worker;
+  }
+  var docId = task.docId;
+  worker.promise.then(function () {
+    if (task.destroyed) {
+      throw new Error('Loading aborted');
+    }
+    return _fetchDocument(worker, params, rangeTransport, docId).then(
+        function (workerId) {
+      if (task.destroyed) {
+        throw new Error('Loading aborted');
+      }
+      var messageHandler = new MessageHandler(docId, workerId, worker.port);
+      messageHandler.send('Ready', null);
+      var transport = new WorkerTransport(messageHandler, task, rangeTransport);
+      task._transport = transport;
+    });
+  }, task._capability.reject);
 
   return task;
 };
 
 /**
+ * Starts fetching of specified PDF document/data.
+ * @param {PDFWorker} worker
+ * @param {Object} source
+ * @param {PDFDataRangeTransport} pdfDataRangeTransport
+ * @param {string} docId Unique document id, used as MessageHandler id.
+ * @returns {Promise} The promise, which is resolved when worker id of
+ *                    MessageHandler is known.
+ * @private
+ */
+function _fetchDocument(worker, source, pdfDataRangeTransport, docId) {
+  if (worker.destroyed) {
+    return Promise.reject(new Error('Worker was destroyed'));
+  }
+
+  source.disableAutoFetch = PDFJS.disableAutoFetch;
+  source.disableStream = PDFJS.disableStream;
+  source.chunkedViewerLoading = !!pdfDataRangeTransport;
+  if (pdfDataRangeTransport) {
+    source.length = pdfDataRangeTransport.length;
+    source.initialData = pdfDataRangeTransport.initialData;
+  }
+  return worker.messageHandler.sendWithPromise('GetDocRequest', {
+    docId: docId,
+    source: source,
+    disableRange: PDFJS.disableRange,
+    maxImageSize: PDFJS.maxImageSize,
+    cMapUrl: PDFJS.cMapUrl,
+    cMapPacked: PDFJS.cMapPacked,
+    disableFontFace: PDFJS.disableFontFace,
+    disableCreateObjectURL: PDFJS.disableCreateObjectURL,
+    verbosity: PDFJS.verbosity
+  }).then(function (workerId) {
+    if (worker.destroyed) {
+      throw new Error('Worker was destroyed');
+    }
+    return workerId;
+  });
+}
+
+/**
  * PDF document loading operation.
  * @class
  * @alias PDFDocumentLoadingTask
  */
 var PDFDocumentLoadingTask = (function PDFDocumentLoadingTaskClosure() {
+  var nextDocumentId = 0;
+
+  /** @constructs PDFDocumentLoadingTask */
   function PDFDocumentLoadingTask() {
     this._capability = createPromiseCapability();
     this._transport = null;
+    this._worker = null;
+
+    /**
+     * Unique document loading task id -- used in MessageHandlers.
+     * @type {string}
+     */
+    this.docId = 'd' + (nextDocumentId++);
+
+    /**
+     * Shows if loading task is destroyed.
+     * @type {boolean}
+     */
+    this.destroyed = false;
 
     /**
      * Callback to request a password if wrong or no password was provided.
      * The callback receives two parameters: function that needs to be called
      * with new password and reason (see {PasswordResponses}).
      */
     this.onPassword = null;
 
@@ -1681,17 +1784,27 @@ var PDFDocumentLoadingTask = (function P
     },
 
     /**
      * Aborts all network requests and destroys worker.
      * @return {Promise} A promise that is resolved after destruction activity
      *                   is completed.
      */
     destroy: function () {
-      return this._transport.destroy();
+      this.destroyed = true;
+
+      var transportDestroyed = !this._transport ? Promise.resolve() :
+        this._transport.destroy();
+      return transportDestroyed.then(function () {
+        this._transport = null;
+        if (this._worker) {
+          this._worker.destroy();
+          this._worker = null;
+        }
+      }.bind(this));
     },
 
     /**
      * Registers callbacks to indicate the document loading completion.
      *
      * @param {function} onFulfilled The callback for the loading completion.
      * @param {function} onRejected The callback for the loading failure.
      * @return {Promise} A promise that is resolved after the onFulfilled or
@@ -1910,23 +2023,31 @@ var PDFDocumentProxy = (function PDFDocu
      */
     cleanup: function PDFDocumentProxy_cleanup() {
       this.transport.startCleanup();
     },
     /**
      * Destroys current document instance and terminates worker.
      */
     destroy: function PDFDocumentProxy_destroy() {
-      return this.transport.destroy();
+      return this.loadingTask.destroy();
     }
   };
   return PDFDocumentProxy;
 })();
 
 /**
+ * Page getTextContent parameters.
+ *
+ * @typedef {Object} getTextContentParameters
+ * @param {boolean} normalizeWhitespace - replaces all occurrences of
+ *   whitespace with standard spaces (0x20). The default value is `false`.
+ */
+
+/**
  * Page text content.
  *
  * @typedef {Object} TextContent
  * @property {array} items - array of {@link TextItem}
  * @property {Object} styles - {@link TextStyles} objects, indexed by font
  *                    name.
  */
 
@@ -1948,16 +2069,26 @@ var PDFDocumentProxy = (function PDFDocu
  * @typedef {Object} TextStyle
  * @property {number} ascent - font ascent.
  * @property {number} descent - font descent.
  * @property {boolean} vertical - text is in vertical mode.
  * @property {string} fontFamily - possible font family
  */
 
 /**
+ * Page annotation parameters.
+ *
+ * @typedef {Object} GetAnnotationsParameters
+ * @param {string} intent - Determines the annotations that will be fetched,
+ *                 can be either 'display' (viewable annotations) or 'print'
+ *                 (printable annotations).
+ *                 If the parameter is omitted, all annotations are fetched.
+ */
+
+/**
  * Page render parameters.
  *
  * @typedef {Object} RenderParameters
  * @property {Object} canvasContext - A 2D context of a DOM Canvas object.
  * @property {PDFJS.PageViewport} viewport - Rendering viewport obtained by
  *                                calling of PDFPage.getViewport method.
  * @property {string} intent - Rendering intent, can be 'display' or 'print'
  *                    (default value is 'display').
@@ -2035,22 +2166,27 @@ var PDFPageProxy = (function PDFPageProx
      */
     getViewport: function PDFPageProxy_getViewport(scale, rotate) {
       if (arguments.length < 2) {
         rotate = this.rotate;
       }
       return new PDFJS.PageViewport(this.view, scale, rotate, 0, 0);
     },
     /**
+     * @param {GetAnnotationsParameters} params - Annotation parameters.
      * @return {Promise} A promise that is resolved with an {Array} of the
      * annotation objects.
      */
-    getAnnotations: function PDFPageProxy_getAnnotations() {
-      if (!this.annotationsPromise) {
-        this.annotationsPromise = this.transport.getAnnotations(this.pageIndex);
+    getAnnotations: function PDFPageProxy_getAnnotations(params) {
+      var intent = (params && params.intent) || null;
+
+      if (!this.annotationsPromise || this.annotationsIntent !== intent) {
+        this.annotationsPromise = this.transport.getAnnotations(this.pageIndex,
+                                                                intent);
+        this.annotationsIntent = intent;
       }
       return this.annotationsPromise;
     },
     /**
      * Begins the process of rendering a page to the desired context.
      * @param {RenderParameters} params Page render parameters.
      * @return {RenderTask} An object that contains the promise, which
      *                      is resolved when the page finishes rendering.
@@ -2179,22 +2315,26 @@ var PDFPageProxy = (function PDFPageProx
           pageIndex: this.pageIndex,
           intent: renderingIntent
         });
       }
       return intentState.opListReadCapability.promise;
     },
 
     /**
+     * @param {getTextContentParameters} params - getTextContent parameters.
      * @return {Promise} That is resolved a {@link TextContent}
      * object that represent the page text content.
      */
-    getTextContent: function PDFPageProxy_getTextContent() {
+    getTextContent: function PDFPageProxy_getTextContent(params) {
+      var normalizeWhitespace = (params && params.normalizeWhitespace) || false;
+
       return this.transport.messageHandler.sendWithPromise('GetTextContent', {
-        pageIndex: this.pageNumber - 1
+        pageIndex: this.pageNumber - 1,
+        normalizeWhitespace: normalizeWhitespace,
       });
     },
 
     /**
      * Destroys page object.
      */
     _destroy: function PDFPageProxy_destroy() {
       this.destroyed = true;
@@ -2292,83 +2432,219 @@ var PDFPageProxy = (function PDFPageProx
         this._tryCleanup();
       }
     }
   };
   return PDFPageProxy;
 })();
 
 /**
+ * PDF.js web worker abstraction, it controls instantiation of PDF documents and
+ * WorkerTransport for them.  If creation of a web worker is not possible,
+ * a "fake" worker will be used instead.
+ * @class
+ */
+var PDFWorker = (function PDFWorkerClosure() {
+  var nextFakeWorkerId = 0;
+
+  // Loads worker code into main thread.
+  function setupFakeWorkerGlobal() {
+    if (!PDFJS.fakeWorkerFilesLoadedCapability) {
+      PDFJS.fakeWorkerFilesLoadedCapability = createPromiseCapability();
+      // In the developer build load worker_loader which in turn loads all the
+      // other files and resolves the promise. In production only the
+      // pdf.worker.js file is needed.
+      Util.loadScript(PDFJS.workerSrc, function() {
+        PDFJS.fakeWorkerFilesLoadedCapability.resolve();
+      });
+    }
+    return PDFJS.fakeWorkerFilesLoadedCapability.promise;
+  }
+
+  function PDFWorker(name) {
+    this.name = name;
+    this.destroyed = false;
+
+    this._readyCapability = createPromiseCapability();
+    this._port = null;
+    this._webWorker = null;
+    this._messageHandler = null;
+    this._initialize();
+  }
+
+  PDFWorker.prototype =  /** @lends PDFWorker.prototype */ {
+    get promise() {
+      return this._readyCapability.promise;
+    },
+
+    get port() {
+      return this._port;
+    },
+
+    get messageHandler() {
+      return this._messageHandler;
+    },
+
+    _initialize: function PDFWorker_initialize() {
+      // If worker support isn't disabled explicit and the browser has worker
+      // support, create a new web worker and test if it/the browser fullfills
+      // all requirements to run parts of pdf.js in a web worker.
+      // Right now, the requirement is, that an Uint8Array is still an
+      // Uint8Array as it arrives on the worker. (Chrome added this with v.15.)
+      if (!globalScope.PDFJS.disableWorker && typeof Worker !== 'undefined') {
+        var workerSrc = PDFJS.workerSrc;
+        if (!workerSrc) {
+          error('No PDFJS.workerSrc specified');
+        }
+
+        try {
+          // Some versions of FF can't create a worker on localhost, see:
+          // https://bugzilla.mozilla.org/show_bug.cgi?id=683280
+          var worker = new Worker(workerSrc);
+          var messageHandler = new MessageHandler('main', 'worker', worker);
+
+          messageHandler.on('test', function PDFWorker_test(data) {
+            if (this.destroyed) {
+              this._readyCapability.reject(new Error('Worker was destroyed'));
+              messageHandler.destroy();
+              worker.terminate();
+              return; // worker was destroyed
+            }
+            var supportTypedArray = data && data.supportTypedArray;
+            if (supportTypedArray) {
+              this._messageHandler = messageHandler;
+              this._port = worker;
+              this._webWorker = worker;
+              if (!data.supportTransfers) {
+                PDFJS.postMessageTransfers = false;
+              }
+              this._readyCapability.resolve();
+            } else {
+              this._setupFakeWorker();
+              messageHandler.destroy();
+              worker.terminate();
+            }
+          }.bind(this));
+
+          messageHandler.on('console_log', function (data) {
+            console.log.apply(console, data);
+          });
+          messageHandler.on('console_error', function (data) {
+            console.error.apply(console, data);
+          });
+          messageHandler.on('_unsupported_feature', function (data) {
+            UnsupportedManager.notify(data);
+          });
+
+          var testObj = new Uint8Array([PDFJS.postMessageTransfers ? 255 : 0]);
+          // Some versions of Opera throw a DATA_CLONE_ERR on serializing the
+          // typed array. Also, checking if we can use transfers.
+          try {
+            messageHandler.send('test', testObj, [testObj.buffer]);
+          } catch (ex) {
+            info('Cannot use postMessage transfers');
+            testObj[0] = 0;
+            messageHandler.send('test', testObj);
+          }
+          return;
+        } catch (e) {
+          info('The worker has been disabled.');
+        }
+      }
+      // Either workers are disabled, not supported or have thrown an exception.
+      // Thus, we fallback to a faked worker.
+      this._setupFakeWorker();
+    },
+
+    _setupFakeWorker: function PDFWorker_setupFakeWorker() {
+      warn('Setting up fake worker.');
+      globalScope.PDFJS.disableWorker = true;
+
+      setupFakeWorkerGlobal().then(function () {
+        if (this.destroyed) {
+          this._readyCapability.reject(new Error('Worker was destroyed'));
+          return;
+        }
+
+        // If we don't use a worker, just post/sendMessage to the main thread.
+        var port = {
+          _listeners: [],
+          postMessage: function (obj) {
+            var e = {data: obj};
+            this._listeners.forEach(function (listener) {
+              listener.call(this, e);
+            }, this);
+          },
+          addEventListener: function (name, listener) {
+            this._listeners.push(listener);
+          },
+          removeEventListener: function (name, listener) {
+            var i = this._listeners.indexOf(listener);
+            this._listeners.splice(i, 1);
+          },
+          terminate: function () {}
+        };
+        this._port = port;
+
+        // All fake workers use the same port, making id unique.
+        var id = 'fake' + (nextFakeWorkerId++);
+
+        // If the main thread is our worker, setup the handling for the
+        // messages -- the main thread sends to it self.
+        var workerHandler = new MessageHandler(id + '_worker', id, port);
+        PDFJS.WorkerMessageHandler.setup(workerHandler, port);
+
+        var messageHandler = new MessageHandler(id, id + '_worker', port);
+        this._messageHandler = messageHandler;
+        this._readyCapability.resolve();
+      }.bind(this));
+    },
+
+    /**
+     * Destroys the worker instance.
+     */
+    destroy: function PDFWorker_destroy() {
+      this.destroyed = true;
+      if (this._webWorker) {
+        // We need to terminate only web worker created resource.
+        this._webWorker.terminate();
+        this._webWorker = null;
+      }
+      this._port = null;
+      if (this._messageHandler) {
+        this._messageHandler.destroy();
+        this._messageHandler = null;
+      }
+    }
+  };
+
+  return PDFWorker;
+})();
+PDFJS.PDFWorker = PDFWorker;
+
+/**
  * For internal use only.
  * @ignore
  */
 var WorkerTransport = (function WorkerTransportClosure() {
-  function WorkerTransport(workerInitializedCapability, pdfDataRangeTransport) {
+  function WorkerTransport(messageHandler, loadingTask, pdfDataRangeTransport) {
+    this.messageHandler = messageHandler;
+    this.loadingTask = loadingTask;
     this.pdfDataRangeTransport = pdfDataRangeTransport;
-    this.workerInitializedCapability = workerInitializedCapability;
     this.commonObjs = new PDFObjects();
-
-    this.loadingTask = null;
+    this.fontLoader = new FontLoader(loadingTask.docId);
+
     this.destroyed = false;
     this.destroyCapability = null;
 
     this.pageCache = [];
     this.pagePromises = [];
     this.downloadInfoCapability = createPromiseCapability();
 
-    // If worker support isn't disabled explicit and the browser has worker
-    // support, create a new web worker and test if it/the browser fullfills
-    // all requirements to run parts of pdf.js in a web worker.
-    // Right now, the requirement is, that an Uint8Array is still an Uint8Array
-    // as it arrives on the worker. Chrome added this with version 15.
-    if (!globalScope.PDFJS.disableWorker && typeof Worker !== 'undefined') {
-      var workerSrc = PDFJS.workerSrc;
-      if (!workerSrc) {
-        error('No PDFJS.workerSrc specified');
-      }
-
-      try {
-        // Some versions of FF can't create a worker on localhost, see:
-        // https://bugzilla.mozilla.org/show_bug.cgi?id=683280
-        var worker = new Worker(workerSrc);
-        var messageHandler = new MessageHandler('main', worker);
-        this.messageHandler = messageHandler;
-
-        messageHandler.on('test', function transportTest(data) {
-          var supportTypedArray = data && data.supportTypedArray;
-          if (supportTypedArray) {
-            this.worker = worker;
-            if (!data.supportTransfers) {
-              PDFJS.postMessageTransfers = false;
-            }
-            this.setupMessageHandler(messageHandler);
-            workerInitializedCapability.resolve();
-          } else {
-            this.setupFakeWorker();
-          }
-        }.bind(this));
-
-        var testObj = new Uint8Array([PDFJS.postMessageTransfers ? 255 : 0]);
-        // Some versions of Opera throw a DATA_CLONE_ERR on serializing the
-        // typed array. Also, checking if we can use transfers.
-        try {
-          messageHandler.send('test', testObj, [testObj.buffer]);
-        } catch (ex) {
-          info('Cannot use postMessage transfers');
-          testObj[0] = 0;
-          messageHandler.send('test', testObj);
-        }
-        return;
-      } catch (e) {
-        info('The worker has been disabled.');
-      }
-    }
-    // Either workers are disabled, not supported or have thrown an exception.
-    // Thus, we fallback to a faked worker.
-    this.setupFakeWorker();
+    this.setupMessageHandler();
   }
   WorkerTransport.prototype = {
     destroy: function WorkerTransport_destroy() {
       if (this.destroyCapability) {
         return this.destroyCapability.promise;
       }
 
       this.destroyed = true;
@@ -2384,66 +2660,33 @@ var WorkerTransport = (function WorkerTr
       });
       this.pageCache = [];
       this.pagePromises = [];
       var self = this;
       // We also need to wait for the worker to finish its long running tasks.
       var terminated = this.messageHandler.sendWithPromise('Terminate', null);
       waitOn.push(terminated);
       Promise.all(waitOn).then(function () {
-        FontLoader.clear();
-        if (self.worker) {
-          self.worker.terminate();
-        }
+        self.fontLoader.clear();
         if (self.pdfDataRangeTransport) {
           self.pdfDataRangeTransport.abort();
           self.pdfDataRangeTransport = null;
         }
-        self.messageHandler = null;
+        if (self.messageHandler) {
+          self.messageHandler.destroy();
+          self.messageHandler = null;
+        }
         self.destroyCapability.resolve();
       }, this.destroyCapability.reject);
       return this.destroyCapability.promise;
     },
 
-    setupFakeWorker: function WorkerTransport_setupFakeWorker() {
-      globalScope.PDFJS.disableWorker = true;
-
-      if (!PDFJS.fakeWorkerFilesLoadedCapability) {
-        PDFJS.fakeWorkerFilesLoadedCapability = createPromiseCapability();
-        // In the developer build load worker_loader which in turn loads all the
-        // other files and resolves the promise. In production only the
-        // pdf.worker.js file is needed.
-        Util.loadScript(PDFJS.workerSrc, function() {
-          PDFJS.fakeWorkerFilesLoadedCapability.resolve();
-        });
-      }
-      PDFJS.fakeWorkerFilesLoadedCapability.promise.then(function () {
-        warn('Setting up fake worker.');
-        // If we don't use a worker, just post/sendMessage to the main thread.
-        var fakeWorker = {
-          postMessage: function WorkerTransport_postMessage(obj) {
-            fakeWorker.onmessage({data: obj});
-          },
-          terminate: function WorkerTransport_terminate() {}
-        };
-
-        var messageHandler = new MessageHandler('main', fakeWorker);
-        this.setupMessageHandler(messageHandler);
-
-        // If the main thread is our worker, setup the handling for the messages
-        // the main thread sends to it self.
-        PDFJS.WorkerMessageHandler.setup(messageHandler);
-
-        this.workerInitializedCapability.resolve();
-      }.bind(this));
-    },
-
     setupMessageHandler:
-      function WorkerTransport_setupMessageHandler(messageHandler) {
-      this.messageHandler = messageHandler;
+      function WorkerTransport_setupMessageHandler() {
+      var messageHandler = this.messageHandler;
 
       function updatePassword(password) {
         messageHandler.send('UpdatePassword', password);
       }
 
       var pdfDataRangeTransport = this.pdfDataRangeTransport;
       if (pdfDataRangeTransport) {
         pdfDataRangeTransport.addRangeListener(function(begin, chunk) {
@@ -2573,17 +2816,17 @@ var WorkerTransport = (function WorkerTr
               var error = exportedData.error;
               warn('Error during font loading: ' + error);
               this.commonObjs.resolve(id, error);
               break;
             } else {
               font = new FontFaceObject(exportedData);
             }
 
-            FontLoader.bind(
+            this.fontLoader.bind(
               [font],
               function fontReady(fontObjs) {
                 this.commonObjs.resolve(id, font);
               }.bind(this)
             );
             break;
           case 'FontPath':
             this.commonObjs.resolve(id, data[2]);
@@ -2698,44 +2941,16 @@ var WorkerTransport = (function WorkerTr
           img.onerror = function () {
             reject(new Error('JpegDecode failed to load image'));
           };
           img.src = imageUrl;
         });
       }, this);
     },
 
-    fetchDocument: function WorkerTransport_fetchDocument(loadingTask, source) {
-      if (this.destroyed) {
-        loadingTask._capability.reject(new Error('Loading aborted'));
-        this.destroyCapability.resolve();
-        return;
-      }
-
-      this.loadingTask = loadingTask;
-
-      source.disableAutoFetch = PDFJS.disableAutoFetch;
-      source.disableStream = PDFJS.disableStream;
-      source.chunkedViewerLoading = !!this.pdfDataRangeTransport;
-      if (this.pdfDataRangeTransport) {
-        source.length = this.pdfDataRangeTransport.length;
-        source.initialData = this.pdfDataRangeTransport.initialData;
-      }
-      this.messageHandler.send('GetDocRequest', {
-        source: source,
-        disableRange: PDFJS.disableRange,
-        maxImageSize: PDFJS.maxImageSize,
-        cMapUrl: PDFJS.cMapUrl,
-        cMapPacked: PDFJS.cMapPacked,
-        disableFontFace: PDFJS.disableFontFace,
-        disableCreateObjectURL: PDFJS.disableCreateObjectURL,
-        verbosity: PDFJS.verbosity
-      });
-    },
-
     getData: function WorkerTransport_getData() {
       return this.messageHandler.sendWithPromise('GetData', null);
     },
 
     getPage: function WorkerTransport_getPage(pageNumber, capability) {
       if (pageNumber <= 0 || pageNumber > this.numPages ||
           (pageNumber|0) !== pageNumber) {
         return Promise.reject(new Error('Invalid page request'));
@@ -2758,27 +2973,29 @@ var WorkerTransport = (function WorkerTr
       this.pagePromises[pageIndex] = promise;
       return promise;
     },
 
     getPageIndex: function WorkerTransport_getPageIndexByRef(ref) {
       return this.messageHandler.sendWithPromise('GetPageIndex', { ref: ref });
     },
 
-    getAnnotations: function WorkerTransport_getAnnotations(pageIndex) {
-      return this.messageHandler.sendWithPromise('GetAnnotations',
-        { pageIndex: pageIndex });
+    getAnnotations: function WorkerTransport_getAnnotations(pageIndex, intent) {
+      return this.messageHandler.sendWithPromise('GetAnnotations', {
+        pageIndex: pageIndex,
+        intent: intent,
+      });
     },
 
     getDestinations: function WorkerTransport_getDestinations() {
       return this.messageHandler.sendWithPromise('GetDestinations', null);
     },
 
     getDestination: function WorkerTransport_getDestination(id) {
-      return this.messageHandler.sendWithPromise('GetDestination', { id: id } );
+      return this.messageHandler.sendWithPromise('GetDestination', { id: id });
     },
 
     getAttachments: function WorkerTransport_getAttachments() {
       return this.messageHandler.sendWithPromise('GetAttachments', null);
     },
 
     getJavaScript: function WorkerTransport_getJavaScript() {
       return this.messageHandler.sendWithPromise('GetJavaScript', null);
@@ -2807,17 +3024,17 @@ var WorkerTransport = (function WorkerTr
         then(function endCleanup() {
         for (var i = 0, ii = this.pageCache.length; i < ii; i++) {
           var page = this.pageCache[i];
           if (page) {
             page.cleanup();
           }
         }
         this.commonObjs.clear();
-        FontLoader.clear();
+        this.fontLoader.clear();
       }.bind(this));
     }
   };
   return WorkerTransport;
 
 })();
 
 /**
@@ -6156,101 +6373,119 @@ var TilingPattern = (function TilingPatt
   };
 
   return TilingPattern;
 })();
 
 
 PDFJS.disableFontFace = false;
 
-var FontLoader = {
+function FontLoader(docId) {
+  this.docId = docId;
+  this.styleElement = null;
+}
+FontLoader.prototype = {
   insertRule: function fontLoaderInsertRule(rule) {
-    var styleElement = document.getElementById('PDFJS_FONT_STYLE_TAG');
+    var styleElement = this.styleElement;
     if (!styleElement) {
-      styleElement = document.createElement('style');
-      styleElement.id = 'PDFJS_FONT_STYLE_TAG';
+      styleElement = this.styleElement = document.createElement('style');
+      styleElement.id = 'PDFJS_FONT_STYLE_TAG_' + this.docId;
       document.documentElement.getElementsByTagName('head')[0].appendChild(
         styleElement);
     }
 
     var styleSheet = styleElement.sheet;
     styleSheet.insertRule(rule, styleSheet.cssRules.length);
   },
 
   clear: function fontLoaderClear() {
-    var styleElement = document.getElementById('PDFJS_FONT_STYLE_TAG');
+    var styleElement = this.styleElement;
     if (styleElement) {
       styleElement.parentNode.removeChild(styleElement);
     }
   },
   bind: function fontLoaderBind(fonts, callback) {
     assert(!isWorker, 'bind() shall be called from main thread');
   
     for (var i = 0, ii = fonts.length; i < ii; i++) {
       var font = fonts[i];
       if (font.attached) {
         continue;
       }
   
       font.attached = true;
-      font.bindDOM()
+      var rule = font.createFontFaceRule();
+      if (rule) {
+        this.insertRule(rule);
+      }
     }
   
     setTimeout(callback);
   }
 };
 
 var FontFaceObject = (function FontFaceObjectClosure() {
-  function FontFaceObject(name, file, properties) {
+  function FontFaceObject(translatedData) {
     this.compiledGlyphs = {};
-    if (arguments.length === 1) {
-      // importing translated data
-      var data = arguments[0];
-      for (var i in data) {
-        this[i] = data[i];
-      }
-      return;
+    // importing translated data
+    for (var i in translatedData) {
+      this[i] = translatedData[i];
     }
   }
+  Object.defineProperty(FontFaceObject, 'isEvalSupported', {
+    get: function () {
+      var evalSupport = false;
+      if (PDFJS.isEvalSupported) {
+        try {
+          /* jshint evil: true */
+          new Function('');
+          evalSupport = true;
+        } catch (e) {}
+      }
+      return shadow(this, 'isEvalSupported', evalSupport);
+    },
+    enumerable: true,
+    configurable: true
+  });
   FontFaceObject.prototype = {
 
-    bindDOM: function FontFaceObject_bindDOM() {
+    createFontFaceRule: function FontFaceObject_createFontFaceRule() {
       if (!this.data) {
         return null;
       }
 
       if (PDFJS.disableFontFace) {
         this.disableFontFace = true;
         return null;
       }
 
       var data = bytesToString(new Uint8Array(this.data));
       var fontName = this.loadedName;
 
       // Add the font-face rule to the document
       var url = ('url(data:' + this.mimetype + ';base64,' +
                  window.btoa(data) + ');');
       var rule = '@font-face { font-family:"' + fontName + '";src:' + url + '}';
-      FontLoader.insertRule(rule);
 
       if (PDFJS.pdfBug && 'FontInspector' in globalScope &&
           globalScope['FontInspector'].enabled) {
         globalScope['FontInspector'].fontAdded(this, url);
       }
 
       return rule;
     },
 
-    getPathGenerator: function FontLoader_getPathGenerator(objs, character) {
+    getPathGenerator:
+        function FontFaceObject_getPathGenerator(objs, character) {
       if (!(character in this.compiledGlyphs)) {
         var cmds = objs.get(this.loadedName + '_path_' + character);
         var current, i, len;
 
         // If we can, compile cmds into JS for MAXIMUM SPEED
-        if (FontLoader.isEvalSupported) {
+        if (FontFaceObject.isEvalSupported) {
           var args, js = '';
           for (i = 0, len = cmds.length; i < len; i++) {
             current = cmds[i];
 
             if (current.args !== undefined) {
               args = current.args.join(',');
             } else {
               args = '';
--- a/browser/extensions/pdfjs/content/build/pdf.worker.js
+++ b/browser/extensions/pdfjs/content/build/pdf.worker.js
@@ -15,18 +15,18 @@
 /*jshint globalstrict: false */
 /* globals PDFJS */
 
 // Initializing PDFJS global object (if still undefined)
 if (typeof PDFJS === 'undefined') {
   (typeof window !== 'undefined' ? window : this).PDFJS = {};
 }
 
-PDFJS.version = '1.3.14';
-PDFJS.build = 'df46b64';
+PDFJS.version = '1.3.42';
+PDFJS.build = '84a47f8';
 
 (function pdfjsWrapper() {
   // Use strict in our context only - users might not want it
   'use strict';
 
 
 
 var globalScope = (typeof window === 'undefined') ? this : window;
@@ -55,16 +55,29 @@ var ImageKind = {
 };
 
 var AnnotationType = {
   WIDGET: 1,
   TEXT: 2,
   LINK: 3
 };
 
+var AnnotationFlag = {
+  INVISIBLE: 0x01,
+  HIDDEN: 0x02,
+  PRINT: 0x04,
+  NOZOOM: 0x08,
+  NOROTATE: 0x10,
+  NOVIEW: 0x20,
+  READONLY: 0x40,
+  LOCKED: 0x80,
+  TOGGLENOVIEW: 0x100,
+  LOCKEDCONTENTS: 0x200
+};
+
 var AnnotationBorderStyleType = {
   SOLID: 1,
   DASHED: 2,
   BEVELED: 3,
   INSET: 4,
   UNDERLINE: 5
 };
 
@@ -1181,78 +1194,79 @@ PDFJS.createObjectURL = (function create
       var d3 = i + 1 < ii ? ((b2 & 0xF) << 2) | (b3 >> 6) : 64;
       var d4 = i + 2 < ii ? (b3 & 0x3F) : 64;
       buffer += digits[d1] + digits[d2] + digits[d3] + digits[d4];
     }
     return buffer;
   };
 })();
 
-function MessageHandler(name, comObj) {
-  this.name = name;
+function MessageHandler(sourceName, targetName, comObj) {
+  this.sourceName = sourceName;
+  this.targetName = targetName;
   this.comObj = comObj;
   this.callbackIndex = 1;
   this.postMessageTransfers = true;
   var callbacksCapabilities = this.callbacksCapabilities = {};
   var ah = this.actionHandler = {};
 
-  ah['console_log'] = [function ahConsoleLog(data) {
-    console.log.apply(console, data);
-  }];
-  ah['console_error'] = [function ahConsoleError(data) {
-    console.error.apply(console, data);
-  }];
-  ah['_unsupported_feature'] = [function ah_unsupportedFeature(data) {
-    UnsupportedManager.notify(data);
-  }];
-
-  comObj.onmessage = function messageHandlerComObjOnMessage(event) {
+  this._onComObjOnMessage = function messageHandlerComObjOnMessage(event) {
     var data = event.data;
+    if (data.targetName !== this.sourceName) {
+      return;
+    }
     if (data.isReply) {
       var callbackId = data.callbackId;
       if (data.callbackId in callbacksCapabilities) {
         var callback = callbacksCapabilities[callbackId];
         delete callbacksCapabilities[callbackId];
         if ('error' in data) {
           callback.reject(data.error);
         } else {
           callback.resolve(data.data);
         }
       } else {
         error('Cannot resolve callback ' + callbackId);
       }
     } else if (data.action in ah) {
       var action = ah[data.action];
       if (data.callbackId) {
+        var sourceName = this.sourceName;
+        var targetName = data.sourceName;
         Promise.resolve().then(function () {
           return action[0].call(action[1], data.data);
         }).then(function (result) {
           comObj.postMessage({
+            sourceName: sourceName,
+            targetName: targetName,
             isReply: true,
             callbackId: data.callbackId,
             data: result
           });
         }, function (reason) {
           if (reason instanceof Error) {
             // Serialize error to avoid "DataCloneError"
             reason = reason + '';
           }
           comObj.postMessage({
+            sourceName: sourceName,
+            targetName: targetName,
             isReply: true,
             callbackId: data.callbackId,
             error: reason
           });
         });
       } else {
         action[0].call(action[1], data.data);
       }
     } else {
       error('Unknown action from worker: ' + data.action);
     }
-  };
+  }.bind(this);
+  comObj.addEventListener('message', this._onComObjOnMessage);
 }
 
 MessageHandler.prototype = {
   on: function messageHandlerOn(actionName, handler, scope) {
     var ah = this.actionHandler;
     if (ah[actionName]) {
       error('There is already an actionName called "' + actionName + '"');
     }
@@ -1261,16 +1275,18 @@ MessageHandler.prototype = {
   /**
    * Sends a message to the comObj to invoke the action with the supplied data.
    * @param {String} actionName Action to call.
    * @param {JSON} data JSON data to send.
    * @param {Array} [transfers] Optional list of transfers/ArrayBuffers
    */
   send: function messageHandlerSend(actionName, data, transfers) {
     var message = {
+      sourceName: this.sourceName,
+      targetName: this.targetName,
       action: actionName,
       data: data
     };
     this.postMessage(message, transfers);
   },
   /**
    * Sends a message to the comObj to invoke the action with the supplied data.
    * Expects that other side will callback with the response.
@@ -1278,16 +1294,18 @@ MessageHandler.prototype = {
    * @param {JSON} data JSON data to send.
    * @param {Array} [transfers] Optional list of transfers/ArrayBuffers.
    * @returns {Promise} Promise to be resolved with response data.
    */
   sendWithPromise:
     function messageHandlerSendWithPromise(actionName, data, transfers) {
     var callbackId = this.callbackIndex++;
     var message = {
+      sourceName: this.sourceName,
+      targetName: this.targetName,
       action: actionName,
       data: data,
       callbackId: callbackId
     };
     var capability = createPromiseCapability();
     this.callbacksCapabilities[callbackId] = capability;
     try {
       this.postMessage(message, transfers);
@@ -1303,16 +1321,20 @@ MessageHandler.prototype = {
    * @param transfers List of transfers/ArrayBuffers, or undefined.
    */
   postMessage: function (message, transfers) {
     if (transfers && this.postMessageTransfers) {
       this.comObj.postMessage(message, transfers);
     } else {
       this.comObj.postMessage(message);
     }
+  },
+
+  destroy: function () {
+    this.comObj.removeEventListener('message', this._onComObjOnMessage);
   }
 };
 
 function loadJpegStream(id, imageUrl, objs) {
   var img = new Image();
   img.onload = (function loadJpegStream_onloadClosure() {
     objs.resolve(id, img);
   });
@@ -1856,16 +1878,20 @@ var ChunkedStreamManager = (function Chu
 
 // 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 = {
+    get docId() {
+      return this._docId;
+    },
+
     onLoadedStream: function BasePdfManager_onLoadedStream() {
       throw new NotImplementedException();
     },
 
     ensureDoc: function BasePdfManager_ensureDoc(prop, args) {
       return this.ensure(this.pdfDocument, prop, args);
     },
 
@@ -1917,17 +1943,18 @@ var BasePdfManager = (function BasePdfMa
       return new NotImplementedException();
     }
   };
 
   return BasePdfManager;
 })();
 
 var LocalPdfManager = (function LocalPdfManagerClosure() {
-  function LocalPdfManager(data, password) {
+  function LocalPdfManager(docId, data, password) {
+    this._docId = docId;
     var stream = new Stream(data);
     this.pdfDocument = new PDFDocument(this, stream, password);
     this._loadedStreamCapability = createPromiseCapability();
     this._loadedStreamCapability.resolve(stream);
   }
 
   LocalPdfManager.prototype = Object.create(BasePdfManager.prototype);
   LocalPdfManager.prototype.constructor = LocalPdfManager;
@@ -1968,18 +1995,18 @@ var LocalPdfManager = (function LocalPdf
       function LocalPdfManager_terminate() {
     return;
   };
 
   return LocalPdfManager;
 })();
 
 var NetworkPdfManager = (function NetworkPdfManagerClosure() {
-  function NetworkPdfManager(args, msgHandler) {
-
+  function NetworkPdfManager(docId, args, msgHandler) {
+    this._docId = docId;
     this.msgHandler = msgHandler;
 
     var params = {
       msgHandler: msgHandler,
       httpHeaders: args.httpHeaders,
       withCredentials: args.withCredentials,
       chunkedViewerLoading: args.chunkedViewerLoading,
       disableAutoFetch: args.disableAutoFetch,
@@ -2246,17 +2273,18 @@ var Page = (function PageClosure() {
           annotations, pageOpList, pdfManager, partialEvaluator, task, intent);
         return annotationsReadyPromise.then(function () {
           pageOpList.flush(true);
           return pageOpList;
         });
       });
     },
 
-    extractTextContent: function Page_extractTextContent(task) {
+    extractTextContent: function Page_extractTextContent(task,
+                                                         normalizeWhitespace) {
       var handler = {
         on: function nullHandlerOn() {},
         send: function nullHandlerSend() {}
       };
 
       var self = this;
 
       var pdfManager = this.pdfManager;
@@ -2276,38 +2304,45 @@ var Page = (function PageClosure() {
         var partialEvaluator = new PartialEvaluator(pdfManager, self.xref,
                                                     handler, self.pageIndex,
                                                     'p' + self.pageIndex + '_',
                                                     self.idCounters,
                                                     self.fontCache);
 
         return partialEvaluator.getTextContent(contentStream,
                                                task,
-                                               self.resources);
+                                               self.resources,
+                                               /* stateManager = */ null,
+                                               normalizeWhitespace);
       });
     },
 
-    getAnnotationsData: function Page_getAnnotationsData() {
+    getAnnotationsData: function Page_getAnnotationsData(intent) {
       var annotations = this.annotations;
       var annotationsData = [];
       for (var i = 0, n = annotations.length; i < n; ++i) {
+        if (intent) {
+          if (!(intent === 'display' && annotations[i].viewable) &&
+              !(intent === 'print' && annotations[i].printable)) {
+            continue;
+          }
+        }
         annotationsData.push(annotations[i].data);
       }
       return annotationsData;
     },
 
     get annotations() {
       var annotations = [];
       var annotationRefs = this.getInheritedPageProp('Annots') || [];
       var annotationFactory = new AnnotationFactory();
       for (var i = 0, n = annotationRefs.length; i < n; ++i) {
         var annotationRef = annotationRefs[i];
         var annotation = annotationFactory.create(this.xref, annotationRef);
-        if (annotation &&
-            (annotation.isViewable() || annotation.isPrintable())) {
+        if (annotation) {
           annotations.push(annotation);
         }
       }
       return shadow(this, 'annotations', annotations);
     }
   };
 
   return Page;
@@ -4506,17 +4541,19 @@ var Annotation = (function AnnotationClo
     return appearance;
   }
 
   function Annotation(params) {
     var dict = params.dict;
     var data = this.data = {};
 
     data.subtype = dict.get('Subtype').name;
-    data.annotationFlags = dict.get('F');
+
+    this.setFlags(dict.get('F'));
+    data.annotationFlags = this.flags;
 
     this.setRectangle(dict.get('Rect'));
     data.rect = this.rectangle;
 
     this.setColor(dict.get('C'));
     data.color = this.color;
 
     this.borderStyle = data.borderStyle = new AnnotationBorderStyle();
@@ -4524,16 +4561,74 @@ var Annotation = (function AnnotationClo
 
     this.appearance = getDefaultAppearance(dict);
     data.hasAppearance = !!this.appearance;
     data.id = params.ref.num;
   }
 
   Annotation.prototype = {
     /**
+     * @return {boolean}
+     */
+    get viewable() {
+      if (this.flags) {
+        return !this.hasFlag(AnnotationFlag.INVISIBLE) &&
+               !this.hasFlag(AnnotationFlag.HIDDEN) &&
+               !this.hasFlag(AnnotationFlag.NOVIEW);
+      }
+      return true;
+    },
+
+    /**
+     * @return {boolean}
+     */
+    get printable() {
+      if (this.flags) {
+        return this.hasFlag(AnnotationFlag.PRINT) &&
+               !this.hasFlag(AnnotationFlag.INVISIBLE) &&
+               !this.hasFlag(AnnotationFlag.HIDDEN);
+      }
+      return false;
+    },
+
+    /**
+     * Set the flags.
+     *
+     * @public
+     * @memberof Annotation
+     * @param {number} flags - Unsigned 32-bit integer specifying annotation
+     *                         characteristics
+     * @see {@link shared/util.js}
+     */
+    setFlags: function Annotation_setFlags(flags) {
+      if (isInt(flags)) {
+        this.flags = flags;
+      } else {
+        this.flags = 0;
+      }
+    },
+
+    /**
+     * Check if a provided flag is set.
+     *
+     * @public
+     * @memberof Annotation
+     * @param {number} flag - Hexadecimal representation for an annotation
+     *                        characteristic
+     * @return {boolean}
+     * @see {@link shared/util.js}
+     */
+    hasFlag: function Annotation_hasFlag(flag) {
+      if (this.flags) {
+        return (this.flags & flag) > 0;
+      }
+      return false;
+    },
+
+    /**
      * Set the rectangle.
      *
      * @public
      * @memberof Annotation
      * @param {Array} rectangle - The rectangle array with exactly four entries
      */
     setRectangle: function Annotation_setRectangle(rectangle) {
       if (isArray(rectangle) && rectangle.length === 4) {
@@ -4622,42 +4717,16 @@ var Annotation = (function AnnotationClo
         // specification, we should draw a solid border of width 1 in that
         // case, but Adobe Reader did not implement that part of the
         // specification and instead draws no border at all, so we do the same.
         // See also https://github.com/mozilla/pdf.js/issues/6179.
         this.borderStyle.setWidth(0);
       }
     },
 
-    isInvisible: function Annotation_isInvisible() {
-      var data = this.data;
-      return !!(data &&
-                data.annotationFlags &&            // Default: not invisible
-                data.annotationFlags & 0x1);       // Invisible
-    },
-
-    isViewable: function Annotation_isViewable() {
-      var data = this.data;
-      return !!(!this.isInvisible() &&
-                data &&
-                (!data.annotationFlags ||
-                 !(data.annotationFlags & 0x22)) &&  // Hidden or NoView
-                data.rect);                          // rectangle is necessary
-    },
-
-    isPrintable: function Annotation_isPrintable() {
-      var data = this.data;
-      return !!(!this.isInvisible() &&
-                data &&
-                data.annotationFlags &&              // Default: not printable
-                data.annotationFlags & 0x4 &&        // Print
-                !(data.annotationFlags & 0x2) &&     // Hidden
-                data.rect);                          // rectangle is necessary
-    },
-
     loadResources: function Annotation_loadResources(keys) {
       return new Promise(function (resolve, reject) {
         this.appearance.dict.getAsync('Resources').then(function (resources) {
           if (!resources) {
             resolve();
             return;
           }
           var objectLoader = new ObjectLoader(resources.map,
@@ -4714,18 +4783,18 @@ var Annotation = (function AnnotationClo
     function reject(e) {
       annotationsReadyCapability.reject(e);
     }
 
     var annotationsReadyCapability = createPromiseCapability();
 
     var annotationPromises = [];
     for (var i = 0, n = annotations.length; i < n; ++i) {
-      if (intent === 'display' && annotations[i].isViewable() ||
-          intent === 'print' && annotations[i].isPrintable()) {
+      if (intent === 'display' && annotations[i].viewable ||
+          intent === 'print' && annotations[i].printable) {
         annotationPromises.push(
           annotations[i].getOperatorList(partialEvaluator, task));
       }
     }
     Promise.all(annotationPromises).then(function(datas) {
       opList.addOp(OPS.beginAnnotations, []);
       for (var i = 0, n = datas.length; i < n; ++i) {
         var annotOpList = datas[i];
@@ -4891,16 +4960,22 @@ var WidgetAnnotation = (function WidgetA
       Util.getInheritableProperty(dict, 'V') || '');
     data.alternativeText = stringToPDFString(dict.get('TU') || '');
     data.defaultAppearance = Util.getInheritableProperty(dict, 'DA') || '';
     var fieldType = Util.getInheritableProperty(dict, 'FT');
     data.fieldType = isName(fieldType) ? fieldType.name : '';
     data.fieldFlags = Util.getInheritableProperty(dict, 'Ff') || 0;
     this.fieldResources = Util.getInheritableProperty(dict, 'DR') || Dict.empty;
 
+    // Hide unsupported Widget signatures.
+    if (data.fieldType === 'Sig') {
+      warn('unimplemented annotation type: Widget signature');
+      this.setFlags(AnnotationFlag.HIDDEN);
+    }
+
     // Building the full field name by collecting the field and
     // its ancestors 'T' data and joining them using '.'.
     var fieldName = [];
     var namedItem = dict;
     var ref = params.ref;
     while (namedItem) {
       var parent = namedItem.get('Parent');
       var parentRef = namedItem.getRaw('Parent');
@@ -4924,27 +4999,17 @@ var WidgetAnnotation = (function WidgetA
         fieldName.unshift('`' + j);
       }
       namedItem = parent;
       ref = parentRef;
     }
     data.fullName = fieldName.join('.');
   }
 
-  var parent = Annotation.prototype;
-  Util.inherit(WidgetAnnotation, Annotation, {
-    isViewable: function WidgetAnnotation_isViewable() {
-      if (this.data.fieldType === 'Sig') {
-        warn('unimplemented annotation type: Widget signature');
-        return false;
-      }
-
-      return parent.isViewable.call(this);
-    }
-  });
+  Util.inherit(WidgetAnnotation, Annotation, {});
 
   return WidgetAnnotation;
 })();
 
 var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() {
   function TextWidgetAnnotation(params) {
     WidgetAnnotation.call(this, params);
 
@@ -5033,17 +5098,17 @@ var LinkAnnotation = (function LinkAnnot
         } 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 = '';
         }
-        // According to ISO 32000-1:2008, section 12.6.4.7, 
+        // According to ISO 32000-1:2008, section 12.6.4.7,
         // URI should to be encoded in 7-bit ASCII.
         // Some bad PDFs may have URIs in UTF-8 encoding, see Bugzilla 1122280.
         try {
           data.url = stringToUTF8String(url);
         } catch (e) {
           // Fall back to a simple copy.
           data.url = url;
         }
@@ -10557,16 +10622,19 @@ var PartialEvaluator = (function Partial
       return this.loadFont(fontName, fontRef, this.xref, resources).then(
           function (translated) {
         if (!translated.font.isType3Font) {
           return translated;
         }
         return translated.loadType3Data(self, resources, operatorList, task).
           then(function () {
           return translated;
+        }, function (reason) {
+          return new TranslatedFont('g_font_error',
+            new ErrorFont('Type3 font load error: ' + reason), translated.font);
         });
       }).then(function (translated) {
         state.font = translated.font;
         translated.send(self.handler);
         return translated.loadedName;
       });
     },
 
@@ -10765,17 +10833,17 @@ var PartialEvaluator = (function Partial
       // fontName in font.loadedName below.
       var fontRefIsDict = isDict(fontRef);
       if (!fontRefIsDict) {
         this.fontCache.put(fontRef, fontCapability.promise);
       }
 
       // Keep track of each font we translated so the caller can
       // load them asynchronously before calling display on a page.
-      font.loadedName = 'g_font_' + (fontRefIsDict ?
+      font.loadedName = 'g_' + this.pdfManager.docId + '_f' + (fontRefIsDict ?
         fontName.replace(/\W/g, '') : fontID);
 
       font.translated = fontCapability.promise;
 
       // TODO move promises into translate font
       var translatedPromise;
       try {
         translatedPromise = Promise.resolve(
@@ -11144,22 +11212,25 @@ var PartialEvaluator = (function Partial
         // Closing those for them.
         for (i = 0, ii = preprocessor.savedStatesDepth; i < ii; i++) {
           operatorList.addOp(OPS.restore, []);
         }
         resolve();
       });
     },
 
-    getTextContent: function PartialEvaluator_getTextContent(stream, task,
-                                                             resources,
-                                                             stateManager) {
+    getTextContent:
+        function PartialEvaluator_getTextContent(stream, task, resources,
+                                                 stateManager,
+                                                 normalizeWhitespace) {
 
       stateManager = (stateManager || new StateManager(new TextState()));
 
+      var WhitespaceRegexp = /\s/g;
+
       var textContent = {
         items: [],
         styles: Object.create(null)
       };
       var textContentItem = {
         initialized: false,
         str: [],
         width: 0,
@@ -11263,21 +11334,33 @@ var PartialEvaluator = (function Partial
           textContentItem.textRunBreakAllowed = false;
         }
 
 
         textContentItem.initialized = true;
         return textContentItem;
       }
 
+      function replaceWhitespace(str) {
+        // Replaces all whitespaces with standard spaces (0x20), to avoid
+        // alignment issues between the textLayer and the canvas if the text
+        // contains e.g. tabs (fixes issue6612.pdf).
+        var i = 0, ii = str.length, code;
+        while (i < ii && (code = str.charCodeAt(i)) >= 0x20 && code <= 0x7F) {
+          i++;
+        }
+        return (i < ii ? str.replace(WhitespaceRegexp, ' ') : str);
+      }
+
       function runBidiTransform(textChunk) {
         var str = textChunk.str.join('');
         var bidiResult = PDFJS.bidi(str, -1, textChunk.vertical);
         return {
-          str: bidiResult.str,
+          str: (normalizeWhitespace ? replaceWhitespace(bidiResult.str) :
+                                      bidiResult.str),
           dir: bidiResult.dir,
           width: textChunk.width,
           height: textChunk.height,
           transform: textChunk.transform,
           fontName: textChunk.fontName
         };
       }
 
@@ -11588,18 +11671,18 @@ var PartialEvaluator = (function Partial
 
               stateManager.save();
               var matrix = xobj.dict.get('Matrix');
               if (isArray(matrix) && matrix.length === 6) {
                 stateManager.transform(matrix);
               }
 
               return self.getTextContent(xobj, task,
-                xobj.dict.get('Resources') || resources, stateManager).
-                then(function (formTextContent) {
+                xobj.dict.get('Resources') || resources, stateManager,
+                normalizeWhitespace).then(function (formTextContent) {
                   Util.appendToArray(textContent.items, formTextContent.items);
                   Util.extendObj(textContent.styles, formTextContent.styles);
                   stateManager.restore();
 
                   xobjsCache.key = name;
                   xobjsCache.texts = formTextContent;
 
                   next(resolve, reject);
@@ -33832,22 +33915,61 @@ var WorkerTask = (function WorkerTaskClo
       }
     }
   };
 
   return WorkerTask;
 })();
 
 var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
-  setup: function wphSetup(handler) {
+  setup: function wphSetup(handler, port) {
+    handler.on('test', function wphSetupTest(data) {
+      // check if Uint8Array can be sent to worker
+      if (!(data instanceof Uint8Array)) {
+        handler.send('test', 'main', false);
+        return;
+      }
+      // making sure postMessage transfers are working
+      var supportTransfers = data[0] === 255;
+      handler.postMessageTransfers = supportTransfers;
+      // check if the response property is supported by xhr
+      var xhr = new XMLHttpRequest();
+      var responseExists = 'response' in xhr;
+      // check if the property is actually implemented
+      try {
+        var dummy = xhr.responseType;
+      } catch (e) {
+        responseExists = false;
+      }
+      if (!responseExists) {
+        handler.send('test', false);
+        return;
+      }
+      handler.send('test', {
+        supportTypedArray: true,
+        supportTransfers: supportTransfers
+      });
+    });
+
+    handler.on('GetDocRequest', function wphSetupDoc(data) {
+      return WorkerMessageHandler.createDocumentHandler(data, port);
+    });
+  },
+  createDocumentHandler: function wphCreateDocumentHandler(docParams, port) {
+    // This context is actually holds references on pdfManager and handler,
+    // until the latter is destroyed.
     var pdfManager;
     var terminated = false;
     var cancelXHRs = null;
     var WorkerTasks = [];
 
+    var docId = docParams.docId;
+    var workerHandlerName = docParams.docId + '_worker';
+    var handler = new MessageHandler(workerHandlerName, docId, port);
+
     function ensureNotTerminated() {
       if (terminated) {
         throw new Error('Worker was terminated');
       }
     }
 
     function startWorkerTask(task) {
       WorkerTasks.push(task);
@@ -33895,25 +34017,25 @@ var WorkerMessageHandler = PDFJS.WorkerM
     function getPdfManager(data) {
       var pdfManagerCapability = createPromiseCapability();
       var pdfManager;
 
       var source = data.source;
       var disableRange = data.disableRange;
       if (source.data) {
         try {
-          pdfManager = new LocalPdfManager(source.data, source.password);
+          pdfManager = new LocalPdfManager(docId, source.data, source.password);
           pdfManagerCapability.resolve(pdfManager);
         } catch (ex) {
           pdfManagerCapability.reject(ex);
         }
         return pdfManagerCapability.promise;
       } else if (source.chunkedViewerLoading) {
         try {
-          pdfManager = new NetworkPdfManager(source, handler);
+          pdfManager = new NetworkPdfManager(docId, source, handler);
           pdfManagerCapability.resolve(pdfManager);
         } catch (ex) {
           pdfManagerCapability.reject(ex);
         }
         return pdfManagerCapability.promise;
       }
 
       var networkManager = new NetworkManager(source.url, {
@@ -33960,17 +34082,17 @@ var WorkerMessageHandler = PDFJS.WorkerM
             // 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);
           }
 
           try {
-            pdfManager = new NetworkPdfManager(source, handler);
+            pdfManager = new NetworkPdfManager(docId, source, handler);
             pdfManagerCapability.resolve(pdfManager);
           } catch (ex) {
             pdfManagerCapability.reject(ex);
           }
           cancelXHRs = null;
         },
 
         onProgressiveData: source.disableStream ? null :
@@ -34005,17 +34127,17 @@ var WorkerMessageHandler = PDFJS.WorkerM
             });
             pdfFile = pdfFileArray.buffer;
           } else {
             pdfFile = args.chunk;
           }
 
           // the data is array, instantiating directly from it
           try {
-            pdfManager = new LocalPdfManager(pdfFile, source.password);
+            pdfManager = new LocalPdfManager(docId, pdfFile, source.password);
             pdfManagerCapability.resolve(pdfManager);
           } catch (ex) {
             pdfManagerCapability.reject(ex);
           }
           cancelXHRs = null;
         },
 
         onError: function onError(status) {
@@ -34043,45 +34165,17 @@ var WorkerMessageHandler = PDFJS.WorkerM
 
       cancelXHRs = function () {
         networkManager.abortRequest(fullRequestXhrId);
       };
 
       return pdfManagerCapability.promise;
     }
 
-    handler.on('test', function wphSetupTest(data) {
-      // check if Uint8Array can be sent to worker
-      if (!(data instanceof Uint8Array)) {
-        handler.send('test', false);
-        return;
-      }
-      // making sure postMessage transfers are working
-      var supportTransfers = data[0] === 255;
-      handler.postMessageTransfers = supportTransfers;
-      // check if the response property is supported by xhr
-      var xhr = new XMLHttpRequest();
-      var responseExists = 'response' in xhr;
-      // check if the property is actually implemented
-      try {
-        var dummy = xhr.responseType;
-      } catch (e) {
-        responseExists = false;
-      }
-      if (!responseExists) {
-        handler.send('test', false);
-        return;
-      }
-      handler.send('test', {
-        supportTypedArray: true,
-        supportTransfers: supportTransfers
-      });
-    });
-
-    handler.on('GetDocRequest', function wphSetupDoc(data) {
+    var setupDoc = function(data) {
       var onSuccess = function(doc) {
         ensureNotTerminated();
         handler.send('GetDoc', { pdfInfo: doc });
       };
 
       var onFailure = function(e) {
         if (e instanceof PasswordException) {
           if (e.code === PasswordResponses.NEED_PASSWORD) {
@@ -34116,17 +34210,16 @@ var WorkerMessageHandler = PDFJS.WorkerM
         if (terminated) {
           // We were in a process of setting up the manager, but it got
           // terminated in the middle.
           newPdfManager.terminate();
           throw new Error('Worker was terminated');
         }
 
         pdfManager = newPdfManager;
-
         handler.send('PDFManagerReady', null);
         pdfManager.onLoadedStream().then(function(stream) {
           handler.send('DataLoaded', { length: stream.bytes.byteLength });
         });
       }).then(function pdfManagerReady() {
         ensureNotTerminated();
 
         loadDocument(false).then(onSuccess, function loadFailure(ex) {
@@ -34147,17 +34240,17 @@ var WorkerMessageHandler = PDFJS.WorkerM
           pdfManager.requestLoadedStream();
           pdfManager.onLoadedStream().then(function() {
             ensureNotTerminated();
 
             loadDocument(true).then(onSuccess, onFailure);
           });
         }, onFailure);
       }, onFailure);
-    });
+    };
 
     handler.on('GetPage', function wphSetupGetPage(data) {
       return pdfManager.getPage(data.pageIndex).then(function(page) {
         var rotatePromise = pdfManager.ensure(page, 'rotate');
         var refPromise = pdfManager.ensure(page, 'ref');
         var viewPromise = pdfManager.ensure(page, 'view');
 
         return Promise.all([rotatePromise, refPromise, viewPromise]).then(
@@ -34180,17 +34273,17 @@ var WorkerMessageHandler = PDFJS.WorkerM
     handler.on('GetDestinations',
       function wphSetupGetDestinations(data) {
         return pdfManager.ensureCatalog('destinations');
       }
     );
 
     handler.on('GetDestination',
       function wphSetupGetDestination(data) {
-        return pdfManager.ensureCatalog('getDestination', [ data.id ]);
+        return pdfManager.ensureCatalog('getDestination', [data.id]);
       }
     );
 
     handler.on('GetAttachments',
       function wphSetupGetAttachments(data) {
         return pdfManager.ensureCatalog('attachments');
       }
     );
@@ -34228,17 +34321,17 @@ var WorkerMessageHandler = PDFJS.WorkerM
     );
 
     handler.on('UpdatePassword', function wphSetupUpdatePassword(data) {
       pdfManager.updatePassword(data);
     });
 
     handler.on('GetAnnotations', function wphSetupGetAnnotations(data) {
       return pdfManager.getPage(data.pageIndex).then(function(page) {
-        return pdfManager.ensure(page, 'getAnnotationsData', []);
+        return pdfManager.ensure(page, 'getAnnotationsData', [data.intent]);
       });
     });
 
     handler.on('RenderPageRequest', function wphSetupRenderPage(data) {
       var pageIndex = data.pageIndex;
       pdfManager.getPage(pageIndex).then(function(page) {
         var task = new WorkerTask('RenderPageRequest: page ' + pageIndex);
         startWorkerTask(task);
@@ -34287,22 +34380,24 @@ var WorkerMessageHandler = PDFJS.WorkerM
             intent: data.intent
           });
         });
       });
     }, this);
 
     handler.on('GetTextContent', function wphExtractText(data) {
       var pageIndex = data.pageIndex;
+      var normalizeWhitespace = data.normalizeWhitespace;
       return pdfManager.getPage(pageIndex).then(function(page) {
         var task = new WorkerTask('GetTextContent: page ' + pageIndex);
         startWorkerTask(task);
         var pageNum = pageIndex + 1;
         var start = Date.now();
-        return page.extractTextContent(task).then(function(textContent) {
+        return page.extractTextContent(task, normalizeWhitespace).then(
+            function(textContent) {
           finishWorkerTask(task);
           info('text indexing: page=' + pageNum + ' - time=' +
                (Date.now() - start) + 'ms');
           return textContent;
         }, function (reason) {
           finishWorkerTask(task);
           if (task.terminated) {
             return; // ignoring errors from the terminated thread
@@ -34327,35 +34422,48 @@ var WorkerMessageHandler = PDFJS.WorkerM
       }
 
       var waitOn = [];
       WorkerTasks.forEach(function (task) {
         waitOn.push(task.finished);
         task.terminate();
       });
 
-      return Promise.all(waitOn).then(function () {});
+      return Promise.all(waitOn).then(function () {
+        // Notice that even if we destroying handler, resolved response promise
+        // must be sent back.
+        handler.destroy();
+        handler = null;
+      });
     });
+
+    handler.on('Ready', function wphReady(data) {
+      setupDoc(docParams);
+      docParams = null; // we don't need docParams anymore -- saving memory.
+    });
+    return workerHandlerName;
   }
 };
 
 var consoleTimer = {};
 
 var workerConsole = {
   log: function log() {
     var args = Array.prototype.slice.call(arguments);
     globalScope.postMessage({
+      targetName: 'main',
       action: 'console_log',
       data: args
     });
   },
 
   error: function error() {
     var args = Array.prototype.slice.call(arguments);
     globalScope.postMessage({
+      targetName: 'main',
       action: 'console_error',
       data: args
     });
     throw 'pdf.js execution error';
   },
 
   time: function time(name) {
     consoleTimer[name] = Date.now();
@@ -34375,23 +34483,24 @@ var workerConsole = {
 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({
+      targetName: 'main',
       action: '_unsupported_feature',
       data: msg
     });
   });
 
-  var handler = new MessageHandler('worker_processor', this);
-  WorkerMessageHandler.setup(handler);
+  var handler = new MessageHandler('worker', 'main', this);
+  WorkerMessageHandler.setup(handler, this);
 }
 
 
 /* This class implements the QM Coder decoding as defined in
  *   JPEG 2000 Part I Final Committee Draft Version 1.0
  *   Annex C.3 Arithmetic decoding procedure
  * available at http://www.jpeg.org/public/fcd15444-1.pdf
  *
--- a/browser/extensions/pdfjs/content/web/viewer.js
+++ b/browser/extensions/pdfjs/content/web/viewer.js
@@ -7,16 +7,28 @@
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+/* globals PDFJS, PDFBug, FirefoxCom, Stats, Cache, ProgressBar,
+           DownloadManager, getFileName, getPDFFileNameFromURL,
+           PDFHistory, Preferences, SidebarView, ViewHistory, Stats,
+           PDFThumbnailViewer, URL, noContextMenuHandler, SecondaryToolbar,
+           PasswordPrompt, PDFPresentationMode, PDFDocumentProperties, HandTool,
+           Promise, PDFLinkService, PDFOutlineView, PDFAttachmentView,
+           OverlayManager, PDFFindController, PDFFindBar, PDFViewer,
+           PDFRenderingQueue, PresentationModeState, parseQueryString,
+           RenderingStates, UNKNOWN_SCALE, DEFAULT_SCALE_VALUE,
+           IGNORE_CURRENT_POSITION_ON_ZOOM: true */
+
+'use strict';
 
 var DEFAULT_URL = 'compressed.tracemonkey-pldi-09.pdf';
 var DEFAULT_SCALE_DELTA = 1.1;
 var MIN_SCALE = 0.25;
 var MAX_SCALE = 10.0;
 var SCALE_SELECT_CONTAINER_PADDING = 8;
 var SCALE_SELECT_PADDING = 22;
 var PAGE_NUMBER_LOADING_INDICATOR = 'visiblePageIsLoading';
@@ -1022,17 +1034,16 @@ var PDFFindController = (function PDFFin
       '\u201B': '\'', // Single high-reversed-9 quotation mark
       '\u201C': '"', // Left double quotation mark
       '\u201D': '"', // Right double quotation mark
       '\u201E': '"', // Double low-9 quotation mark
       '\u201F': '"', // Double high-reversed-9 quotation mark
       '\u00BC': '1/4', // Vulgar fraction one quarter
       '\u00BD': '1/2', // Vulgar fraction one half
       '\u00BE': '3/4', // Vulgar fraction three quarters
-      '\u00A0': ' ' // No-break space
     };
     this.findBar = options.findBar || null;
 
     // Compile the regular expression for text normalization once
     var replace = Object.keys(this.charactersToNormalize).join('');
     this.normalizationRegex = new RegExp('[' + replace + ']', 'g');
 
     var events = [
@@ -3670,17 +3681,17 @@ var PDFPageView = (function PDFPageViewC
         CustomStyle.setProp('transform', textLayerDiv,
             'rotate(' + textAbsRotation + 'deg) ' +
             'scale(' + scale + ', ' + scale + ') ' +
             'translate(' + transX + ', ' + transY + ')');
         CustomStyle.setProp('transformOrigin', textLayerDiv, '0% 0%');
       }
 
       if (redrawAnnotations && this.annotationLayer) {
-        this.annotationLayer.setupAnnotations(this.viewport);
+        this.annotationLayer.setupAnnotations(this.viewport, 'display');
       }
     },
 
     get width() {
       return this.viewport.width;
     },
 
     get height() {
@@ -3873,17 +3884,17 @@ var PDFPageView = (function PDFPageViewC
       };
       var renderTask = this.renderTask = this.pdfPage.render(renderContext);
       renderTask.onContinue = renderContinueCallback;
 
       this.renderTask.promise.then(
         function pdfPageRenderCallback() {
           pageViewDrawCallback(null);
           if (textLayer) {
-            self.pdfPage.getTextContent().then(
+            self.pdfPage.getTextContent({ normalizeWhitespace: true }).then(
               function textContentResolved(textContent) {
                 textLayer.setTextContent(textContent);
                 textLayer.render(TEXT_LAYER_RENDER_DELAY);
               }
             );
           }
         },
         function pdfPageRenderError(error) {
@@ -3891,17 +3902,17 @@ var PDFPageView = (function PDFPageViewC
         }
       );
 
       if (this.annotationsLayerFactory) {
         if (!this.annotationLayer) {
           this.annotationLayer = this.annotationsLayerFactory.
             createAnnotationsLayerBuilder(div, this.pdfPage);
         }
-        this.annotationLayer.setupAnnotations(this.viewport);
+        this.annotationLayer.setupAnnotations(this.viewport, 'display');
       }
       div.setAttribute('data-loaded', true);
 
       if (self.onBeforeDraw) {
         self.onBeforeDraw();
       }
       return promise;
     },
@@ -4308,19 +4319,20 @@ var AnnotationsLayerBuilder = (function 
 
     this.div = null;
   }
   AnnotationsLayerBuilder.prototype =
       /** @lends AnnotationsLayerBuilder.prototype */ {
 
     /**
      * @param {PageViewport} viewport
+     * @param {string} intent (default value is 'display')
      */
     setupAnnotations:
-        function AnnotationsLayerBuilder_setupAnnotations(viewport) {
+        function AnnotationsLayerBuilder_setupAnnotations(viewport, intent) {
       function bindLink(link, dest) {
         link.href = linkService.getDestinationHash(dest);
         link.onclick = function annotationsLayerBuilderLinksOnclick() {
           if (dest) {
             linkService.navigateTo(dest);
           }
           return false;
         };
@@ -4336,18 +4348,22 @@ var AnnotationsLayerBuilder = (function 
           return false;
         };
         link.className = 'internalLink';
       }
 
       var linkService = this.linkService;
       var pdfPage = this.pdfPage;
       var self = this;
-
-      pdfPage.getAnnotations().then(function (annotationsData) {
+      var getAnnotationsParams = {
+        intent: (intent === undefined ? 'display' : intent),
+      };
+
+      pdfPage.getAnnotations(getAnnotationsParams).then(
+          function (annotationsData) {
         viewport = viewport.clone({ dontFlip: true });
         var transform = viewport.transform;
         var transformStr = 'matrix(' + transform.join(',') + ')';
         var data, element, i, ii;
 
         if (self.div) {
           // If an annotationLayer already exists, refresh its children's
           // transformation matrices
@@ -4877,17 +4893,17 @@ var PDFViewer = (function pdfViewer() {
      * @param {Array} dest - (optional) original PDF destination array:
      *   <page-ref> </XYZ|FitXXX> <args..>
      */
     scrollPageIntoView: function PDFViewer_scrollPageIntoView(pageNumber,
                                                               dest) {
       if (!this.pdfDocument) {
         return;
       }
-      
+
       var pageView = this._pages[pageNumber - 1];
 
       if (this.isInPresentationMode) {
         if (this._currentPageNumber !== pageView.id) {
           // Avoid breaking getVisiblePages in presentation mode.
           this.currentPageNumber = pageView.id;
           return;
         }
@@ -5135,17 +5151,17 @@ var PDFViewer = (function pdfViewer() {
         }.bind(this));
         return true;
       }
       return false;
     },
 
     getPageTextContent: function (pageIndex) {
       return this.pdfDocument.getPage(pageIndex + 1).then(function (page) {
-        return page.getTextContent();
+        return page.getTextContent({ normalizeWhitespace: true });
       });
     },
 
     /**
      * @param {HTMLDivElement} textLayerDiv
      * @param {number} pageIndex
      * @param {PageViewport} viewport
      * @returns {TextLayerBuilder}
@@ -7384,17 +7400,17 @@ document.addEventListener('pagerendered'
 
 document.addEventListener('textlayerrendered', function (e) {
   var pageIndex = e.detail.pageNumber - 1;
   var pageView = PDFViewerApplication.pdfViewer.getPageView(pageIndex);
 
   if (pageView.textLayer && pageView.textLayer.textDivs &&
       pageView.textLayer.textDivs.length > 0 &&
       !PDFViewerApplication.supportsDocumentColors) {
-    console.error(mozL10n.get('document_colors_disabled', null,
+    console.error(mozL10n.get('document_colors_not_allowed', null,
       'PDF documents are not allowed to use their own colors: ' +
       '\'Allow pages to choose their own colors\' ' +
       'is deactivated in the browser.'));
     PDFViewerApplication.fallback();
   }
 }, true);
 
 document.addEventListener('pagemode', function (evt) {
--- a/browser/locales/en-US/chrome/browser/accounts.properties
+++ b/browser/locales/en-US/chrome/browser/accounts.properties
@@ -10,8 +10,16 @@ autoDisconnectDescription = We've rebuil
 autoDisconnectSignIn.label = Sign in to Sync
 autoDisconnectSignIn.accessKey = S
 
 # LOCALIZATION NOTE (reconnectDescription) - %S = Email address of user's Firefox Account
 reconnectDescription = Reconnect %S
 
 # LOCALIZATION NOTE (verifyDescription) - %S = Email address of user's Firefox Account
 verifyDescription = Verify %S
+
+# These strings are shown in a flyout in the Sync preference panel after the
+# user requests we resend a verification email.
+verificationSentTitle = Verification Sent
+# LOCALIZATION NOTE (verificationSentFull) - %S = Email address of user's Firefox Account
+verificationSentFull = A verification link has been sent to %S. Please check your email and click the link to begin syncing.
+verificationNotSentTitle = Unable to Send Verification
+verificationNotSentFull = We are unable to send a verification mail at this time, please try again later.
--- a/browser/locales/en-US/chrome/browser/loop/loop.properties
+++ b/browser/locales/en-US/chrome/browser/loop/loop.properties
@@ -193,17 +193,17 @@ rooms_room_full_call_to_action_nonFx_lab
 rooms_room_full_call_to_action_label=Learn more about {{clientShortname}} ยป
 rooms_room_joined_label=Someone has joined the conversation!
 rooms_room_join_label=Join the conversation
 rooms_signout_alert=Open conversations will be closed
 room_name_untitled_page=Untitled Page
 
 # Infobar strings
 
-infobar_screenshare_browser_message=You are sharing your tabs. Any tab you click on can be seen by your friends
+infobar_screenshare_browser_message2=You are sharing your tabs. Any tab you click on can be seen by your friends
 infobar_screenshare_paused_browser_message=Tab sharing is paused
 infobar_button_pause_label=Pause
 infobar_button_resume_label=Resume
 infobar_button_stop_label=Stop
 infobar_button_pause_accesskey=P
 infobar_button_stop_accesskey=S
 infobar_button_resume_accesskey=R
 
--- a/browser/locales/en-US/pdfviewer/viewer.properties
+++ b/browser/locales/en-US/pdfviewer/viewer.properties
@@ -165,9 +165,9 @@ text_annotation_type.alt=[{{type}} Annot
 password_label=Enter the password to open this PDF file.
 password_invalid=Invalid password. Please try again.
 password_ok=OK
 password_cancel=Cancel
 
 printing_not_supported=Warning: Printing is not fully supported by this browser.
 printing_not_ready=Warning: The PDF is not fully loaded for printing.
 web_fonts_disabled=Web fonts are disabled: unable to use embedded PDF fonts.
-document_colors_disabled=PDF documents are not allowed to use their own colors: \'Allow pages to choose their own colors\' is deactivated in the browser.
+document_colors_not_allowed=PDF documents are not allowed to use their own colors: 'Allow pages to choose their own colors' is deactivated in the browser.
--- a/build/annotationProcessors/classloader/JarClassIterator.java
+++ b/build/annotationProcessors/classloader/JarClassIterator.java
@@ -3,60 +3,82 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.annotationProcessors.classloader;
 
 import java.util.Iterator;
 
 /**
  * Class for iterating over an IterableJarLoadingURLClassLoader's classes.
+ *
+ * This class is not thread safe: use it only from a single thread.
  */
 public class JarClassIterator implements Iterator<ClassWithOptions> {
     private IterableJarLoadingURLClassLoader mTarget;
     private Iterator<String> mTargetClassListIterator;
 
+    private ClassWithOptions lookAhead;
+
     public JarClassIterator(IterableJarLoadingURLClassLoader aTarget) {
         mTarget = aTarget;
         mTargetClassListIterator = aTarget.classNames.iterator();
     }
 
     @Override
     public boolean hasNext() {
-        return mTargetClassListIterator.hasNext();
+        return fillLookAheadIfPossible();
     }
 
     @Override
     public ClassWithOptions next() {
+        if (!fillLookAheadIfPossible()) {
+            throw new IllegalStateException("Failed to look ahead in next()!");
+        }
+        ClassWithOptions next = lookAhead;
+        lookAhead = null;
+        return next;
+    }
+
+    private boolean fillLookAheadIfPossible() {
+        if (lookAhead != null) {
+            return true;
+        }
+
+        if (!mTargetClassListIterator.hasNext()) {
+            return false;
+        }
+
         String className = mTargetClassListIterator.next();
         try {
             Class<?> ret = mTarget.loadClass(className);
 
             // Incremental builds can leave stale classfiles in the jar. Such classfiles will cause
             // an exception at this point. We can safely ignore these classes - they cannot possibly
             // ever be loaded as they conflict with their parent class and will be killed by
             // Proguard later on anyway.
             final Class<?> enclosingClass;
             try {
                 enclosingClass = ret.getEnclosingClass();
             } catch (IncompatibleClassChangeError e) {
-                return next();
+                return fillLookAheadIfPossible();
             }
 
             if (enclosingClass != null) {
                 // Anonymous inner class - unsupported.
                 // Or named inner class, which will be processed when we process the outer class.
-                return next();
+                return fillLookAheadIfPossible();
             }
 
-            return new ClassWithOptions(ret, ret.getSimpleName());
+            lookAhead = new ClassWithOptions(ret, ret.getSimpleName());
+            return true;
         } catch (ClassNotFoundException e) {
             System.err.println("Unable to enumerate class: " + className + ". Corrupted jar file?");
             e.printStackTrace();
             System.exit(2);
         }
-        return null;
+        return false;
     }
 
     @Override
     public void remove() {
         throw new UnsupportedOperationException("Removal of classes from iterator not supported.");
     }
 }
--- a/configure.in
+++ b/configure.in
@@ -8983,21 +8983,16 @@ AC_SUBST(SOCORRO_SYMBOL_UPLOAD_TOKEN_FIL
 AC_SUBST(MOZ_ENABLE_SZIP)
 AC_SUBST(MOZ_SZIP_FLAGS)
 
 AC_SUBST(DMG_TOOL)
 
 dnl Host JavaScript runtime, if any, to use during cross compiles.
 AC_SUBST(JS_BINARY)
 
-if test "$MOZ_DEBUG"; then
-    MOZ_EM_DEBUG=1
-fi
-AC_SUBST(MOZ_EM_DEBUG)
-
 AC_SUBST(NSS_EXTRA_SYMBOLS_FILE)
 
 if test -n "$COMPILE_ENVIRONMENT"; then
 AC_CHECK_FUNCS(posix_fadvise posix_fallocate)
 
 dnl Check for missing components
 if test "$MOZ_X11"; then
     if test "$WITHOUT_X11"; then
--- a/devtools/client/performance/performance-controller.js
+++ b/devtools/client/performance/performance-controller.js
@@ -303,34 +303,46 @@ var PerformanceController = {
    * @param nsILocalFile file
    *        The file to stream the data into.
    */
   exportRecording: Task.async(function*(_, recording, file) {
     yield recording.exportRecording(file);
     this.emit(EVENTS.RECORDING_EXPORTED, recording, file);
   }),
 
-  /**
-   * Clears all recordings from the list as well as the current recording.
-   * Emits `EVENTS.RECORDINGS_CLEARED` when complete so other components can clean up.
+   /**
+   * Clears all completed recordings from the list as well as the current non-console recording.
+   * Emits `EVENTS.RECORDING_DELETED` when complete so other components can clean up.
    */
   clearRecordings: Task.async(function* () {
-    let latest = this.getLatestManualRecording();
-    if (latest && latest.isRecording()) {
-      yield this.stopRecording();
+    for (let i = this._recordings.length - 1; i >= 0; i--) {
+      let model = this._recordings[i];
+      if (!model.isConsole() && model.isRecording()) {
+        yield this.stopRecording();
+      }
+      // If last recording is not recording, but finalizing itself,
+      // wait for that to finish
+      if (!model.isRecording() && !model.isCompleted()) {
+        yield this.waitForStateChangeOnRecording(model, "recording-stopped");
+      }
+      // If recording is completed,
+      // clean it up from UI and remove it from the _recordings array.
+      if (model.isCompleted()) {
+        this.emit(EVENTS.RECORDING_DELETED, model);
+        this._recordings.splice(i, 1);
+      }
     }
-    // If last recording is not recording, but finalizing itself,
-    // wait for that to finish
-    if (latest && !latest.isCompleted()) {
-      yield this.waitForStateChangeOnRecording(latest, "recording-stopped");
+    if (this._recordings.length > 0) {
+      if (!this._recordings.includes(this.getCurrentRecording())) {
+        this.setCurrentRecording(this._recordings[0]);
+      }
     }
-
-    this._recordings.length = 0;
-    this.setCurrentRecording(null);
-    this.emit(EVENTS.RECORDINGS_CLEARED);
+    else {
+      this.setCurrentRecording(null);
+    }
   }),
 
   /**
    * Loads a recording from a file, adding it to the recordings list. Emits
    * `EVENTS.RECORDING_IMPORTED` when the file was loaded.
    *
    * @param nsILocalFile file
    *        The file to import the data from.
--- a/devtools/client/performance/test/browser_perf-clear-02.js
+++ b/devtools/client/performance/test/browser_perf-clear-02.js
@@ -10,20 +10,32 @@ var test = Task.async(function*() {
   let { target, panel, toolbox } = yield initPerformance(SIMPLE_URL);
   let { EVENTS, PerformanceController, PerformanceView, RecordingsView } = panel.panelWin;
 
   yield startRecording(panel);
   yield stopRecording(panel);
 
   yield startRecording(panel);
 
+  let deleted = Promise.defer();
+  let deleteCount = 0;
+  function onDeleted () {
+    if (++deleteCount === 2) {
+      deleted.resolve();
+      PerformanceController.off(EVENTS.RECORDING_DELETED, onDeleted);
+    }
+  }
+
+  PerformanceController.on(EVENTS.RECORDING_DELETED, onDeleted);
+
   let stopped = Promise.all([
     once(PerformanceController, EVENTS.RECORDING_STOPPED),
-    once(PerformanceController, EVENTS.RECORDINGS_CLEARED)
+    deleted.promise
   ]);
+
   PerformanceController.clearRecordings();
   yield stopped;
 
   is(RecordingsView.itemCount, 0,
     "RecordingsView should be empty.");
   is(PerformanceView.getState(), "empty",
     "PerformanceView should be in an empty state.");
   is(PerformanceController.getCurrentRecording(), null,
--- a/devtools/client/performance/test/browser_perf-console-record-09.js
+++ b/devtools/client/performance/test/browser_perf-console-record-09.js
@@ -1,31 +1,41 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Tests that an error is not thrown when clearing out the recordings if there's
- * an in-progress console profile.
+ * an in-progress console profile and that console profiles are not cleared if in progress.
  */
 
 function* spawnTest() {
   PMM_loadFrameScripts(gBrowser);
   let { target, toolbox, panel } = yield initPerformance(SIMPLE_URL);
   let win = panel.panelWin;
   let { gFront, PerformanceController } = win;
 
+  yield startRecording(panel);
+  yield stopRecording(panel);
+
   info("Starting console.profile()...");
   yield consoleProfile(win);
   yield PerformanceController.clearRecordings();
-
+  let recordings = PerformanceController.getRecordings();
+  is(recordings.length, 1, "1 recording found");
+  is(recordings[0].isConsole(), true, "recording from console.profile is not cleared.");
   info("Ending console.profileEnd()...");
   consoleMethod("profileEnd");
   // Wait for the front to receive the stopped event
   yield once(gFront, "recording-stopped");
 
   // Wait an extra tick or two since the above promise will be resolved
   // the same time as _onRecordingStateChange, which should not cause any throwing
   yield idleWait(100);
   ok(true, "Stopping an in-progress console profile after clearing recordings does not throw.");
 
+  yield PerformanceController.clearRecordings();
+  is(recordings.length, 0, "No recordings found");
+  is(PerformanceController.getCurrentRecording(), null,
+    "There should be no current recording.");
+
   yield teardown(panel);
   finish();
 }
--- a/devtools/client/performance/views/recordings.js
+++ b/devtools/client/performance/views/recordings.js
@@ -12,35 +12,35 @@ var RecordingsView = Heritage.extend(Wid
    */
   initialize: function() {
     this.widget = new SideMenuWidget($("#recordings-list"));
 
     this._onSelect = this._onSelect.bind(this);
     this._onRecordingStateChange = this._onRecordingStateChange.bind(this);
     this._onNewRecording = this._onNewRecording.bind(this);
     this._onSaveButtonClick = this._onSaveButtonClick.bind(this);
-    this._onRecordingsCleared = this._onRecordingsCleared.bind(this);
+    this._onRecordingDeleted = this._onRecordingDeleted.bind(this);
     this._onRecordingExported = this._onRecordingExported.bind(this);
 
     this.emptyText = L10N.getStr("noRecordingsText");
 
     PerformanceController.on(EVENTS.RECORDING_STATE_CHANGE, this._onRecordingStateChange);
     PerformanceController.on(EVENTS.NEW_RECORDING, this._onNewRecording);
-    PerformanceController.on(EVENTS.RECORDINGS_CLEARED, this._onRecordingsCleared);
+    PerformanceController.on(EVENTS.RECORDING_DELETED, this._onRecordingDeleted);
     PerformanceController.on(EVENTS.RECORDING_EXPORTED, this._onRecordingExported);
     this.widget.addEventListener("select", this._onSelect, false);
   },
 
   /**
    * Destruction function, called when the tool is closed.
    */
   destroy: function() {
     PerformanceController.off(EVENTS.RECORDING_STATE_CHANGE, this._onRecordingStateChange);
     PerformanceController.off(EVENTS.NEW_RECORDING, this._onNewRecording);
-    PerformanceController.off(EVENTS.RECORDINGS_CLEARED, this._onRecordingsCleared);
+    PerformanceController.off(EVENTS.RECORDING_DELETED, this._onRecordingDeleted);
     PerformanceController.off(EVENTS.RECORDING_EXPORTED, this._onRecordingExported);
     this.widget.removeEventListener("select", this._onSelect, false);
   },
 
   /**
    * Adds an empty recording to this container.
    *
    * @param RecordingModel recording
@@ -138,20 +138,21 @@ var RecordingsView = Heritage.extend(Wid
 
     // Auto select imported items.
     if (recording.isImported()) {
       this.selectedItem = recordingItem;
     }
   },
 
   /**
-   * Clears out all recordings.
+   * Clears out all non-console recordings.
    */
-  _onRecordingsCleared: function () {
-    this.empty();
+  _onRecordingDeleted: function (_, recording) {
+    let recordingItem = this.getItemForPredicate(e => e.attachment === recording);
+    this.remove(recordingItem);
   },
 
   /**
    * Adds recording data to a recording item in this container.
    *
    * @param Item recordingItem
    *        An item inserted via `RecordingsView.addEmptyRecording`.
    */
--- a/devtools/client/shared/widgets/filter-widget.css
+++ b/devtools/client/shared/widgets/filter-widget.css
@@ -235,15 +235,14 @@ input {
   margin: 0 5px;
 }
 
 .add {
   background: url(chrome://devtools/skin/images/add.svg);
 }
 
 #toggle-presets {
-  background: url(chrome://devtools/skin/images/pseudo-class.svg#pseudo-class);
+  background: url(chrome://devtools/skin/images/pseudo-class.svg);
 }
 
 .show-presets #toggle-presets {
-  background: url(chrome://devtools/skin/images/pseudo-class.svg#pseudo-class-checked);
-  filter: none;
+  filter: url(chrome://devtools/skin/images/filters.svg#checked-icon-state);
 }
--- a/dom/base/test/browser.ini
+++ b/dom/base/test/browser.ini
@@ -19,10 +19,9 @@ tags = mcb
 [browser_messagemanager_targetframeloader.js]
 [browser_pagehide_on_tab_close.js]
 skip-if = e10s # this tests non-e10s behavior. it's not expected to work in e10s.
 [browser_messagemanager_unload.js]
 [browser_state_notifications.js]
 # skip-if = e10s # Bug ?????? - content-document-* notifications come while document's URI is still about:blank, but test expects real URL.
 skip-if = true # Intermittent failures - bug 987493. Restore the skip-if above once fixed
 [browser_bug1058164.js]
-skip-if = e10s # Bug 1220752.
 [browser_use_counters.js]
--- a/dom/base/test/browser_bug1058164.js
+++ b/dom/base/test/browser_bug1058164.js
@@ -1,106 +1,109 @@
 /* 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 kTimeout = 5000; // ms
-
-/**
- * Frame script injected in the test browser that sends
- * messages when it sees the pagehide and pageshow events
- * with the persisted property set to true.
- */
-function frame_script() {
-  addEventListener("pageshow", (event) => {
-    if (event.persisted) {
-      sendAsyncMessage("test:pageshow");
-    }
-  });
-  addEventListener("pagehide", (event) => {
-    if (event.persisted) {
-      sendAsyncMessage("test:pagehide");
-    }
-  });
-}
+const PAGE = "data:text/html,<html><body>A%20regular,%20everyday,%20normal%20page.";
 
 /**
- * Return a Promise that resolves when the browser's frame
- * script sees an event of type eventType. eventType can be
- * either "pagehide" or "pageshow". Times out after kTimeout
- * milliseconds if the event is never seen.
+ * Returns a Promise that resolves when it sees a pageshow and
+ * pagehide events in a particular order, where each event must
+ * have the persisted property set to true. Will cause a test
+ * failure to be logged if it sees an event out of order.
+ *
+ * @param browser (<xul:browser>)
+ *        The browser to expect the events from.
+ * @param expectedOrder (array)
+ *        An array of strings describing what order the pageshow
+ *        and pagehide events should be in.
+ *        Example:
+ *        ["pageshow", "pagehide", "pagehide", "pageshow"]
+ * @returns Promise
  */
-function prepareForPageEvent(browser, eventType) {
-  return new Promise((resolve, reject) => {
-    let mm = browser.messageManager;
-
-    let timeoutId = setTimeout(() => {
-      ok(false, "Timed out waiting for " + eventType)
-      reject();
-    }, kTimeout);
+function prepareForVisibilityEvents(browser, expectedOrder) {
+  return new Promise((resolve) => {
+    let order = [];
 
-    mm.addMessageListener("test:" + eventType, function onSawEvent(message) {
-      mm.removeMessageListener("test:" + eventType, onSawEvent);
-      ok(true, "Saw " + eventType + " event in frame script.");
-      clearTimeout(timeoutId);
-      resolve();
-    });
-  });
-}
+    let checkSatisfied = () => {
+      if (order.length < expectedOrder.length) {
+        // We're still waiting...
+        return;
+      } else {
+        browser.removeEventListener("pagehide", eventListener);
+        browser.removeEventListener("pageshow", eventListener);
 
-/**
- * Returns a Promise that resolves when both the pagehide
- * and pageshow events have been seen from the frame script.
- */
-function prepareForPageHideAndShow(browser) {
-  return Promise.all([prepareForPageEvent(browser, "pagehide"),
-                      prepareForPageEvent(browser, "pageshow")]);
-}
+        for (let i = 0; i < expectedOrder.length; ++i) {
+          is(order[i], expectedOrder[i], "Got expected event");
+        }
+        resolve();
+      }
+    };
 
-/**
- * Returns a Promise that resolves when the load event for
- * aWindow fires during the capture phase.
- */
-function waitForLoad(aWindow) {
-  return new Promise((resolve, reject) => {
-    aWindow.addEventListener("load", function onLoad(aEvent) {
-      aWindow.removeEventListener("load", onLoad, true);
-      resolve();
-    }, true);
+    let eventListener = (e) => {
+      if (e.persisted) {
+        order.push(e.type);
+        checkSatisfied();
+      }
+    };
+
+    browser.addEventListener("pagehide", eventListener);
+    browser.addEventListener("pageshow", eventListener);
   });
 }
 
 /**
  * Tests that frame scripts get pageshow / pagehide events when
  * swapping browser frameloaders (which occurs when moving a tab
  * into a different window).
  */
 add_task(function* test_swap_frameloader_pagevisibility_events() {
-  // Inject our frame script into a new browser.
-  let tab = gBrowser.addTab();
+  // Load a new tab that we'll tear out...
+  let tab = gBrowser.addTab(PAGE);
   gBrowser.selectedTab = tab;
-  let mm = window.getGroupMessageManager("browsers");
-  mm.loadFrameScript("data:,(" + frame_script.toString() + ")();", true);
-  let browser = gBrowser.selectedBrowser;
+  let firstBrowser = tab.linkedBrowser;
+  yield BrowserTestUtils.browserLoaded(firstBrowser);
 
   // Swap the browser out to a new window
   let newWindow = gBrowser.replaceTabWithWindow(tab);
+
   // We have to wait for the window to load so we can get the selected browser
   // to listen to.
-  yield waitForLoad(newWindow);
-  let pageHideAndShowPromise = prepareForPageHideAndShow(newWindow.gBrowser.selectedBrowser);
-  // Yield waiting for the pagehide and pageshow events.
-  yield pageHideAndShowPromise;
+  yield BrowserTestUtils.waitForEvent(newWindow, "load");
+  let newWindowBrowser = newWindow.gBrowser.selectedBrowser;
 
-  // Send the browser back to its original window
+  // Wait for the expected pagehide and pageshow events on the initial browser
+  yield prepareForVisibilityEvents(newWindowBrowser, ["pagehide", "pageshow"]);
+
+  // Now let's send the browser back to the original window
+
+  // First, create a new, empty browser tab to replace the window with
   let newTab = gBrowser.addTab();
   gBrowser.selectedTab = newTab;
-  browser = newWindow.gBrowser.selectedBrowser;
-  pageHideAndShowPromise = prepareForPageHideAndShow(gBrowser.selectedBrowser);
+  let emptyBrowser = newTab.linkedBrowser;
+
+  // Wait for that initial browser to show its pageshow event so that we
+  // don't confuse it with the other expected events. Note that we can't
+  // use BrowserTestUtils.waitForEvent here because we're using the
+  // e10s add-on shims in the e10s-case. I'm doing this because I couldn't
+  // find a way of sending down a frame script to the newly opened windows
+  // and tabs fast enough to attach the event handlers before they were
+  // fired.
+  yield new Promise((resolve) => {
+    emptyBrowser.addEventListener("pageshow", function onPageShow() {
+      emptyBrowser.removeEventListener("pageshow", onPageShow);
+      resolve();
+    });
+  });
+
+  // The empty tab we just added show now fire a pagehide as its replaced,
+  // and a pageshow once the swap is finished.
+  let emptyBrowserPromise =
+    prepareForVisibilityEvents(emptyBrowser, ["pagehide", "pageshow"]);
+
   gBrowser.swapBrowsersAndCloseOther(newTab, newWindow.gBrowser.selectedTab);
 
-  // Yield waiting for the pagehide and pageshow events.
-  yield pageHideAndShowPromise;
+  yield emptyBrowserPromise;
 
   gBrowser.removeTab(gBrowser.selectedTab);
 });
--- a/mobile/android/base/BrowserApp.java
+++ b/mobile/android/base/BrowserApp.java
@@ -1788,17 +1788,17 @@ public class BrowserApp extends GeckoApp
                                 getSupportFragmentManager().beginTransaction().disallowAddToBackStack().add(mpm, tag).commit();
                             }
                         } catch (Exception ex) {
                             Log.e(LOGTAG, "Error initializing media manager", ex);
                         }
                     }
                 }
 
-                if (AppConstants.MOZ_STUMBLER_BUILD_TIME_ENABLED && Restrictions.isAllowed(this, Restrictable.LOCATION_SERVICE)) {
+                if (AppConstants.MOZ_STUMBLER_BUILD_TIME_ENABLED && Restrictions.isAllowed(this, Restrictable.DATA_CHOICES)) {
                     // Start (this acts as ping if started already) the stumbler lib; if the stumbler has queued data it will upload it.
                     // Stumbler operates on its own thread, and startup impact is further minimized by delaying work (such as upload) a few seconds.
                     // Avoid any potential startup CPU/thread contention by delaying the pref broadcast.
                     final long oneSecondInMillis = 1000;
                     ThreadUtils.getBackgroundHandler().postDelayed(new Runnable() {
                         @Override
                         public void run() {
                              GeckoPreferences.broadcastStumblerPref(BrowserApp.this);
@@ -1818,17 +1818,17 @@ public class BrowserApp extends GeckoApp
                         if (menu != null) {
                             menu.findItem(R.id.settings).setEnabled(true);
                             menu.findItem(R.id.help).setEnabled(true);
                         }
                     }
                 });
 
                 // Display notification for Mozilla data reporting, if data should be collected.
-                if (AppConstants.MOZ_DATA_REPORTING) {
+                if (AppConstants.MOZ_DATA_REPORTING && Restrictions.isAllowed(this, Restrictable.DATA_CHOICES)) {
                     DataReportingNotification.checkAndNotifyPolicy(GeckoAppShell.getContext());
                 }
 
             } else if (event.equals("Search:Keyword")) {
                 storeSearchQuery(message.getString("query"));
             } else if (event.equals("LightweightTheme:Update")) {
                 ThreadUtils.postToUiThread(new Runnable() {
                     @Override
--- a/mobile/android/base/background/nativecode/NativeCrypto.java
+++ b/mobile/android/base/background/nativecode/NativeCrypto.java
@@ -46,15 +46,15 @@ public class NativeCrypto {
   /**
    * Wrapper to perform SHA-256 init in native code. Returns a SHA-256 context.
    */
   public native static byte[] sha256init();
 
   /**
    * Wrapper to update a SHA-256 context in native code.
    */
-  public native static void sha256update(byte[] ctx, byte[] str);
+  public native static void sha256update(byte[] ctx, byte[] str, int len);
 
   /**
    * Wrapper to finalize a SHA-256 context in native code. Returns digest.
    */
   public native static byte[] sha256finalize(byte[] ctx);
 }
--- a/mobile/android/base/locales/en-US/android_strings.dtd
+++ b/mobile/android/base/locales/en-US/android_strings.dtd
@@ -721,16 +721,18 @@ just addresses the organization to follo
 <!ENTITY restrictable_feature_private_browsing "Private Browsing">
 <!ENTITY restrictable_feature_private_browsing_description "Allows family members to browse without saving information about the sites and pages they\'ve visited.">
 <!ENTITY restrictable_feature_clear_history "Clear History">
 <!ENTITY restrictable_feature_clear_history_description "Allows family members to delete information about the sites and pages they\'ve visited.">
 <!ENTITY restrictable_feature_advanced_settings "Advanced Settings">
 <!ENTITY restrictable_feature_advanced_settings_description "This includes importing bookmarks, restoring tabs and automated updates. Turn off for simplified settings suitable for any family member.">
 <!ENTITY restrictable_feature_camera_microphone "Camera &amp; Microphone">
 <!ENTITY restrictable_feature_camera_microphone_description "Allows family members to engage in real time communication on websites.">
+<!ENTITY restrictable_feature_data_choices "Data Choices">
+<!ENTITY restrictable_feature_data_choices_description "Choose whether or not to send usage information to Mozilla to help make Firefox better.">
 
 <!-- Default Bookmarks titles-->
 <!-- LOCALIZATION NOTE (bookmarks_about_browser): link title for about:fennec -->
 <!ENTITY bookmarks_about_browser "Firefox: About your browser">
 <!-- LOCALIZATION NOTE (bookmarks_addons): link title for https://addons.mozilla.org/en-US/mobile -->
 <!ENTITY bookmarks_addons "Firefox: Customize with add-ons">
 <!-- LOCALIZATION NOTE (bookmarks_support): link title for https://support.mozilla.org/ -->
 <!ENTITY bookmarks_support "Firefox: Support">
--- a/mobile/android/base/preferences/GeckoPreferences.java
+++ b/mobile/android/base/preferences/GeckoPreferences.java
@@ -667,17 +667,17 @@ OnSharedPreferenceChangeListener
                 i--;
                 continue;
             }
 
             String key = pref.getKey();
             if (pref instanceof PreferenceGroup) {
                 // If datareporting is disabled, remove UI.
                 if (PREFS_DATA_REPORTING_PREFERENCES.equals(key)) {
-                    if (!AppConstants.MOZ_DATA_REPORTING) {
+                    if (!AppConstants.MOZ_DATA_REPORTING || !Restrictions.isAllowed(this, Restrictable.DATA_CHOICES)) {
                         preferences.removePreference(pref);
                         i--;
                         continue;
                     }
                 } else if (PREFS_SCREEN_ADVANCED.equals(key) &&
                         !Restrictions.isAllowed(this, Restrictable.ADVANCED_SETTINGS)) {
                     preferences.removePreference(pref);
                     i--;
@@ -709,37 +709,37 @@ OnSharedPreferenceChangeListener
                 } else if (PREFS_TRACKING_PROTECTION_PB.equals(key)) {
                     // Remove UI for private-browsing-only TP pref in Nightly builds.
                     if (AppConstants.NIGHTLY_BUILD) {
                         preferences.removePreference(pref);
                         i--;
                         continue;
                     }
                 } else if (PREFS_TELEMETRY_ENABLED.equals(key)) {
-                    if (!AppConstants.MOZ_TELEMETRY_REPORTING) {
+                    if (!AppConstants.MOZ_TELEMETRY_REPORTING || !Restrictions.isAllowed(this, Restrictable.DATA_CHOICES)) {
                         preferences.removePreference(pref);
                         i--;
                         continue;
                     }
                 } else if (PREFS_HEALTHREPORT_UPLOAD_ENABLED.equals(key) ||
                            PREFS_HEALTHREPORT_LINK.equals(key)) {
-                    if (!AppConstants.MOZ_SERVICES_HEALTHREPORT) {
+                    if (!AppConstants.MOZ_SERVICES_HEALTHREPORT || !Restrictions.isAllowed(this, Restrictable.DATA_CHOICES)) {
                         preferences.removePreference(pref);
                         i--;
                         continue;
                     }
                 } else if (PREFS_CRASHREPORTER_ENABLED.equals(key)) {
-                    if (!AppConstants.MOZ_CRASHREPORTER) {
+                    if (!AppConstants.MOZ_CRASHREPORTER || !Restrictions.isAllowed(this, Restrictable.DATA_CHOICES)) {
                         preferences.removePreference(pref);
                         i--;
                         continue;
                     }
                 } else if (PREFS_GEO_REPORTING.equals(key) ||
                            PREFS_GEO_LEARN_MORE.equals(key)) {
-                    if (!AppConstants.MOZ_STUMBLER_BUILD_TIME_ENABLED || !Restrictions.isAllowed(this, Restrictable.LOCATION_SERVICE)) {
+                    if (!AppConstants.MOZ_STUMBLER_BUILD_TIME_ENABLED || !Restrictions.isAllowed(this, Restrictable.DATA_CHOICES)) {
                         preferences.removePreference(pref);
                         i--;
                         continue;
                     }
                 } else if (PREFS_DEVTOOLS_REMOTE_USB_ENABLED.equals(key)) {
                     if (!Restrictions.isAllowed(this, Restrictable.REMOTE_DEBUGGING)) {
                         preferences.removePreference(pref);
                         i--;
--- a/mobile/android/base/restrictions/Restrictable.java
+++ b/mobile/android/base/restrictions/Restrictable.java
@@ -43,17 +43,19 @@ public enum Restrictable {
 
     IMPORT_SETTINGS(11, "import_settings", 0, 0),
 
     PRIVATE_BROWSING(
             12, "private_browsing",
             R.string.restrictable_feature_private_browsing,
             R.string.restrictable_feature_private_browsing_description),
 
-    LOCATION_SERVICE(13, "location_service", 0, 0),
+    DATA_CHOICES(13, "data_coices",
+            R.string.restrictable_feature_data_choices,
+            R.string.restrictable_feature_data_choices_description),
 
     CLEAR_HISTORY(14, "clear_history",
             R.string.restrictable_feature_clear_history,
             R.string.restrictable_feature_clear_history_description),
 
     MASTER_PASSWORD(15, "master_password", 0, 0),
 
     GUEST_BROWSING(16, "guest_browsing",  0, 0),
--- a/mobile/android/base/restrictions/RestrictedProfileConfiguration.java
+++ b/mobile/android/base/restrictions/RestrictedProfileConfiguration.java
@@ -11,44 +11,51 @@ import org.mozilla.gecko.util.ThreadUtil
 import android.annotation.TargetApi;
 import android.content.Context;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.StrictMode;
 import android.os.UserManager;
 
 import java.util.Arrays;
+import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Map;
 
 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
 public class RestrictedProfileConfiguration implements RestrictionConfiguration {
-    static List<Restrictable> DEFAULT_DISABLED_FEATURES = Arrays.asList(
-            Restrictable.INSTALL_EXTENSION,
-            Restrictable.PRIVATE_BROWSING,
-            Restrictable.LOCATION_SERVICE,
-            Restrictable.CLEAR_HISTORY,
-            Restrictable.MASTER_PASSWORD,
-            Restrictable.GUEST_BROWSING,
-            Restrictable.ADVANCED_SETTINGS,
-            Restrictable.CAMERA_MICROPHONE
-    );
+    // Mapping from restrictable feature to default state (on/off)
+    private static Map<Restrictable, Boolean> configuration = new LinkedHashMap<>();
+    static {
+        configuration.put(Restrictable.INSTALL_EXTENSION, false);
+        configuration.put(Restrictable.PRIVATE_BROWSING, false);
+        configuration.put(Restrictable.CLEAR_HISTORY, false);
+        configuration.put(Restrictable.MASTER_PASSWORD, false);
+        configuration.put(Restrictable.GUEST_BROWSING, false);
+        configuration.put(Restrictable.ADVANCED_SETTINGS, false);
+        configuration.put(Restrictable.CAMERA_MICROPHONE, false);
+        configuration.put(Restrictable.DATA_CHOICES, true);
+    }
 
     /**
      * These restrictions are hidden from the admin configuration UI.
      */
     private static List<Restrictable> hiddenRestrictions = Arrays.asList(
             Restrictable.MASTER_PASSWORD,
-            Restrictable.GUEST_BROWSING,
-            Restrictable.LOCATION_SERVICE
+            Restrictable.GUEST_BROWSING
     );
 
     /* package-private */ static boolean shouldHide(Restrictable restrictable) {
         return hiddenRestrictions.contains(restrictable);
     }
 
+    /* package-private */ static Map<Restrictable, Boolean> getConfiguration() {
+        return configuration;
+    }
+
     private Context context;
     private Bundle cachedAppRestrictions;
     private Bundle cachedUserRestrictions;
     private boolean isCacheInvalid = true;
 
     public RestrictedProfileConfiguration(Context context) {
         this.context = context.getApplicationContext();
     }
@@ -60,17 +67,17 @@ public class RestrictedProfileConfigurat
             isCacheInvalid = false;
         }
 
         // Special casing system/user restrictions
         if (restrictable == Restrictable.INSTALL_APPS || restrictable == Restrictable.MODIFY_ACCOUNTS) {
             return !cachedUserRestrictions.getBoolean(restrictable.name);
         }
 
-        return cachedAppRestrictions.getBoolean(restrictable.name, !DEFAULT_DISABLED_FEATURES.contains(restrictable));
+        return cachedAppRestrictions.getBoolean(restrictable.name, configuration.get(restrictable));
     }
 
     private void readRestrictions() {
         final UserManager mgr = (UserManager) context.getSystemService(Context.USER_SERVICE);
 
         StrictMode.ThreadPolicy policy = StrictMode.allowThreadDiskReads();
 
         try {
--- a/mobile/android/base/restrictions/RestrictionProvider.java
+++ b/mobile/android/base/restrictions/RestrictionProvider.java
@@ -13,16 +13,17 @@ import android.content.BroadcastReceiver
 import android.content.Context;
 import android.content.Intent;
 import android.content.RestrictionEntry;
 import android.os.Build;
 import android.os.Bundle;
 import android.text.TextUtils;
 
 import java.util.ArrayList;
+import java.util.Map;
 
 /**
  * Broadcast receiver providing supported restrictions to the system.
  */
 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
 public class RestrictionProvider extends BroadcastReceiver {
     @Override
     public void onReceive(final Context context, final Intent intent) {
@@ -48,27 +49,25 @@ public class RestrictionProvider extends
                 result.finish();
             }
         }.start();
     }
 
     private ArrayList<RestrictionEntry> initRestrictions(Context context, Bundle oldRestrictions) {
         ArrayList<RestrictionEntry> entries = new ArrayList<RestrictionEntry>();
 
-        for (Restrictable restrictable : RestrictedProfileConfiguration.DEFAULT_DISABLED_FEATURES) {
-            if (restrictable == Restrictable.LOCATION_SERVICE && !AppConstants.MOZ_STUMBLER_BUILD_TIME_ENABLED) {
-                continue;
-            }
+        final Map<Restrictable, Boolean> configuration = RestrictedProfileConfiguration.getConfiguration();
 
+        for (Restrictable restrictable : configuration.keySet()) {
             if (RestrictedProfileConfiguration.shouldHide(restrictable)) {
                 continue;
             }
 
             RestrictionEntry entry = createRestrictionEntryWithDefaultValue(context, restrictable,
-                    oldRestrictions.getBoolean(restrictable.name, false));
+                    oldRestrictions.getBoolean(restrictable.name, configuration.get(restrictable)));
             entries.add(entry);
         }
 
         return entries;
     }
 
     private RestrictionEntry createRestrictionEntryWithDefaultValue(Context context, Restrictable restrictable, boolean defaultValue) {
         RestrictionEntry entry = new RestrictionEntry(restrictable.name, defaultValue);
--- a/mobile/android/base/strings.xml.in
+++ b/mobile/android/base/strings.xml.in
@@ -570,16 +570,18 @@
   <string name="restrictable_feature_private_browsing">&restrictable_feature_private_browsing;</string>
   <string name="restrictable_feature_private_browsing_description">&restrictable_feature_private_browsing_description;</string>
   <string name="restrictable_feature_clear_history">&restrictable_feature_clear_history;</string>
   <string name="restrictable_feature_clear_history_description">&restrictable_feature_clear_history_description;</string>
   <string name="restrictable_feature_advanced_settings">&restrictable_feature_advanced_settings;</string>
   <string name="restrictable_feature_advanced_settings_description">&restrictable_feature_advanced_settings_description;</string>
   <string name="restrictable_feature_camera_microphone">&restrictable_feature_camera_microphone;</string>
   <string name="restrictable_feature_camera_microphone_description">&restrictable_feature_camera_microphone_description;</string>
+  <string name="restrictable_feature_data_choices">&restrictable_feature_data_choices;</string>
+  <string name="restrictable_feature_data_choices_description">&restrictable_feature_data_choices_description;</string>
 
   <!-- Miscellaneous -->
   <string name="ellipsis">&ellipsis;</string>
 
   <string name="colon">&colon;</string>
 
   <string name="percent">&percent;</string>
 
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testNativeCrypto.java
+++ b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testNativeCrypto.java
@@ -4,16 +4,18 @@
 
 package org.mozilla.gecko.tests;
 
 import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertArrayEquals;
 import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertEquals;
 import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertNotNull;
 import static org.mozilla.gecko.tests.helpers.AssertionHelper.fFail;
 
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 import java.security.GeneralSecurityException;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 
 import org.mozilla.gecko.background.nativecode.NativeCrypto;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.tests.helpers.GeckoHelper;
@@ -55,16 +57,17 @@ public class testNativeCrypto extends UI
     _testPBKDF2SHA256InvalidLenArg();
 
     _testSHA1();
     _testSHA1AgainstMessageDigest();
 
     _testSHA256();
     _testSHA256MultiPart();
     _testSHA256AgainstMessageDigest();
+    _testSHA256WithMultipleUpdatesFromStream();
   }
 
   public void _testPBKDF2SHA256A() throws UnsupportedEncodingException, GeneralSecurityException {
     final String  p = "password";
     final String  s = "salt";
     final int dkLen = 32;
 
     checkPBKDF2SHA256(p, s, 1, dkLen, "120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b");
@@ -187,32 +190,32 @@ public class testNativeCrypto extends UI
       "594847328451bdfa85056225462cc1d867d877fb388df0ce35f25ab5562bfbb5"
     };
 
     for (int i = 0; i < inputs.length; ++i) {
       final byte[] input = inputs[i].getBytes("US-ASCII");
       final String expected = expecteds[i];
 
       final byte[] ctx = NativeCrypto.sha256init();
-      NativeCrypto.sha256update(ctx, input);
+      NativeCrypto.sha256update(ctx, input, input.length);
       final byte[] actual = NativeCrypto.sha256finalize(ctx);
       fAssertNotNull("Hashed value is non-null", actual);
       assertExpectedBytes(expected, actual);
     }
   }
 
   private void _testSHA256MultiPart() throws UnsupportedEncodingException {
     final String input = "01234567";
     final int repetitions = 80;
     final String expected = "594847328451bdfa85056225462cc1d867d877fb388df0ce35f25ab5562bfbb5";
 
     final byte[] inputBytes = input.getBytes("US-ASCII");
     final byte[] ctx = NativeCrypto.sha256init();
     for (int i = 0; i < repetitions; ++i) {
-      NativeCrypto.sha256update(ctx, inputBytes);
+      NativeCrypto.sha256update(ctx, inputBytes, inputBytes.length);
     }
     final byte[] actual = NativeCrypto.sha256finalize(ctx);
     fAssertNotNull("Hashed value is non-null", actual);
     assertExpectedBytes(expected, actual);
   }
 
   private void _testSHA256AgainstMessageDigest() throws UnsupportedEncodingException,
       NoSuchAlgorithmException {
@@ -224,22 +227,43 @@ public class testNativeCrypto extends UI
 
     final MessageDigest digest = MessageDigest.getInstance("SHA-256");
     for (final String input : inputs) {
       final byte[] inputBytes = input.getBytes("US-ASCII");
 
       final byte[] mdBytes = digest.digest(inputBytes);
 
       final byte[] ctx = NativeCrypto.sha256init();
-      NativeCrypto.sha256update(ctx, inputBytes);
+      NativeCrypto.sha256update(ctx, inputBytes, inputBytes.length);
       final byte[] ourBytes = NativeCrypto.sha256finalize(ctx);
       fAssertArrayEquals("MessageDigest hash is the same as NativeCrypto SHA-256 hash", mdBytes, ourBytes);
     }
   }
 
+  private void _testSHA256WithMultipleUpdatesFromStream() throws UnsupportedEncodingException {
+    final String input = "HelloWorldThisIsASuperLongStringThatIsReadAsAStreamOfBytes";
+    final ByteArrayInputStream stream = new ByteArrayInputStream(input.getBytes("UTF-8"));
+    final String expected = "8b5cb76b80f7eb6fb83ee138bfd31e2922e71dd245daa21a8d9876e8dee9eef5";
+
+    byte[] buffer = new byte[10];
+    final byte[] ctx = NativeCrypto.sha256init();
+    int c;
+
+    try {
+      while ((c = stream.read(buffer)) != -1) {
+        NativeCrypto.sha256update(ctx, buffer, c);
+      }
+      final byte[] actual = NativeCrypto.sha256finalize(ctx);
+      fAssertNotNull("Hashed value is non-null", actual);
+      assertExpectedBytes(expected, actual);
+    } catch (IOException e) {
+      fFail("IOException while reading stream");
+    }
+  }
+
   private void checkPBKDF2SHA256(String p, String s, int c, int dkLen, final String expectedStr)
       throws GeneralSecurityException, UnsupportedEncodingException {
     final long start = SystemClock.elapsedRealtime();
 
     final byte[] key = NativeCrypto.pbkdf2SHA256(p.getBytes("US-ASCII"), s.getBytes("US-ASCII"), c, dkLen);
     fAssertNotNull("Hash result is non-null", key);
 
     final long end = SystemClock.elapsedRealtime();
--- a/mozglue/android/NativeCrypto.cpp
+++ b/mozglue/android/NativeCrypto.cpp
@@ -91,23 +91,22 @@ extern "C" JNIEXPORT jbyteArray MOZ_JNIC
 
   return out;
 }
 
 /**
  * Helper function to invoke native SHA-256 update with JNI arguments.
  */
 extern "C" JNIEXPORT void MOZ_JNICALL Java_org_mozilla_gecko_background_nativecode_NativeCrypto_sha256update
-    (JNIEnv *env, jclass jc, jbyteArray jctx, jbyteArray jstr) {
+    (JNIEnv *env, jclass jc, jbyteArray jctx, jbyteArray jstr, jint len) {
   jbyte *str = env->GetByteArrayElements(jstr, nullptr);
-  size_t strLen = env->GetArrayLength(jstr);
 
   SHA256_CTX *shaContext = (SHA256_CTX*)env->GetByteArrayElements(jctx, nullptr);
 
-  SHA256_Update(shaContext, (void*)str, strLen);
+  SHA256_Update(shaContext, (void*)str, (size_t) len);
 
   env->ReleaseByteArrayElements(jstr, str, JNI_ABORT);
   env->ReleaseByteArrayElements(jctx, (jbyte*)shaContext, 0);
 
   return;
 }
 
 /**
--- a/mozglue/android/NativeCrypto.h
+++ b/mozglue/android/NativeCrypto.h
@@ -32,17 +32,17 @@ JNIEXPORT jbyteArray JNICALL Java_org_mo
   (JNIEnv *, jclass);
 
 /*
  * Class:     org_mozilla_gecko_background_nativecode_NativeCrypto
  * Method:    sha256update
  * Signature: ([B[B)V
  */
 JNIEXPORT void JNICALL Java_org_mozilla_gecko_background_nativecode_NativeCrypto_sha256update
-  (JNIEnv *, jclass, jbyteArray, jbyteArray);
+  (JNIEnv *, jclass, jbyteArray, jbyteArray, jint);
 
 /*
  * Class:     org_mozilla_gecko_background_nativecode_NativeCrypto
  * Method:    sha256finalize
  * Signature: ([B)[B
  */
 JNIEXPORT jbyteArray JNICALL Java_org_mozilla_gecko_background_nativecode_NativeCrypto_sha256finalize
   (JNIEnv *, jclass, jbyteArray);
new file mode 100644
--- /dev/null
+++ b/services/sync/modules/SyncedTabs.jsm
@@ -0,0 +1,267 @@
+/* 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";
+
+this.EXPORTED_SYMBOLS = ["SyncedTabs"];
+
+
+const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+Cu.import("resource://gre/modules/Log.jsm");
+Cu.import("resource://gre/modules/PlacesUtils.jsm", this);
+Cu.import("resource://services-sync/main.js");
+Cu.import("resource://gre/modules/Preferences.jsm");
+
+// The Sync XPCOM service
+XPCOMUtils.defineLazyGetter(this, "weaveXPCService", function() {
+  return Cc["@mozilla.org/weave/service;1"]
+           .getService(Ci.nsISupports)
+           .wrappedJSObject;
+});
+
+// from MDN...
+function escapeRegExp(string) {
+  return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
+}
+
+// A topic we fire whenever we have new tabs available. This might be due
+// to a request made by this module to refresh the tab list, or as the result
+// of a regularly scheduled sync. The intent is that consumers just listen
+// for this notification and update their UI in response.
+const TOPIC_TABS_CHANGED = "services.sync.tabs.changed";
+
+// The interval, in seconds, before which we consider the existing list
+// of tabs "fresh enough" and don't force a new sync.
+const TABS_FRESH_ENOUGH_INTERVAL = 30;
+
+let log = Log.repository.getLogger("Sync.RemoteTabs");
+// A new scope to do the logging thang...
+(function() {
+  let level = Preferences.get("services.sync.log.logger.tabs");
+  if (level) {
+    let appender = new Log.DumpAppender();
+    log.level = appender.level = Log.Level[level] || Log.Level.Debug;
+    log.addAppender(appender);
+  }
+})();
+
+
+// A private singleton that does the work.
+let SyncedTabsInternal = {
+  _getClientIcon(id) {
+    let isMobile = Weave.Service.clientsEngine.isMobile(id);
+    if (isMobile) {
+      return "chrome://browser/skin/sync-mobileIcon.png";
+    }
+    return "chrome://browser/skin/sync-desktopIcon.png";
+  },
+
+  /* Make a "tab" record. Returns a promise */
+  _makeTab: Task.async(function* (client, tab, url) {
+    let icon = tab.icon;
+    if (!icon) {
+      try {
+        icon = (yield PlacesUtils.promiseFaviconLinkUrl(url)).spec;
+      } catch (ex) { /* no favicon avaiable */ }
+    }
+    if (!icon) {
+      icon = PlacesUtils.favicons.defaultFavicon.spec;
+    }
+    return {
+      type:  "tab",
+      title: tab.title || url,
+      url,
+      icon,
+      client: client.id,
+      lastUsed: tab.lastUsed,
+    };
+  }),
+
+  /* Make a "client" record. Returns a promise for consistency with _makeTab */
+  _makeClient: Task.async(function* (client) {
+    return {
+      id: client.id,
+      type: "client",
+      name: client.clientName,
+      icon:  this._getClientIcon(client.id),
+      tabs: []
+    };
+  }),
+
+  _tabMatchesFilter(tab, filter) {
+    let reFilter = new RegExp(escapeRegExp(filter), "i");
+    return tab.url.match(reFilter) || tab.title.match(reFilter);
+  },
+
+  getTabClients: Task.async(function* (filter) {
+    log.info("Generating tab list with filter", filter);
+    let result = [];
+
+    // If Sync isn't ready, don't try and get anything.
+    if (!weaveXPCService.ready) {
+      log.debug("Sync isn't yet ready, so returning an empty tab list");
+      return result;
+    }
+
+    let engine = Weave.Service.engineManager.get("tabs");
+
+    let seenURLs = new Set();
+    let parentIndex = 0;
+    let ntabs = 0;
+
+    for (let [guid, client] in Iterator(engine.getAllClients())) {
+      let clientRepr = yield this._makeClient(client);
+      log.debug("Processing client", clientRepr);
+
+      for (let tab of client.tabs) {
+        let url = tab.urlHistory[0];
+        log.debug("remote tab", url);
+        // Note there are some issues with tracking "seen" tabs, including:
+        // * We really can't return the entire urlHistory record as we are
+        //   only checking the first entry - others might be different.
+        // * We don't update the |lastUsed| timestamp to reflect the
+        //   most-recently-seen time.
+        // In a followup we should consider simply dropping this |seenUrls|
+        // check and return duplicate records - it seems the user will be more
+        // confused by tabs not showing up on a device (because it was detected
+        // as a dupe so it only appears on a different device) than being
+        // confused by seeing the same tab on different clients.
+        if (!url || seenURLs.has(url)) {
+          continue;
+        }
+        let tabRepr = yield this._makeTab(client, tab, url);
+        if (filter && !this._tabMatchesFilter(tabRepr, filter)) {
+          continue;
+        }
+        seenURLs.add(url);
+        clientRepr.tabs.push(tabRepr);
+      }
+      // We return all clients, even those without tabs - the consumer should
+      // filter it if they care.
+      ntabs += clientRepr.tabs.length;
+      result.push(clientRepr);
+    }
+    log.info(`Final tab list has ${result.length} clients with ${ntabs} tabs.`);
+    return result;
+  }),
+
+  syncTabs(force) {
+    if (!force) {
+      // Don't bother refetching tabs if we already did so recently
+      let lastFetch = Preferences.get("services.sync.lastTabFetch", 0);
+      let now = Math.floor(Date.now() / 1000);
+      if (now - lastFetch < TABS_FRESH_ENOUGH_INTERVAL) {
+        log.info("_refetchTabs was done recently, do not doing it again");
+        return Promise.resolve(false);
+      }
+    }
+
+    // If Sync isn't configured don't try and sync, else we will get reports
+    // of a login failure.
+    if (Weave.Status.checkSetup() == Weave.CLIENT_NOT_CONFIGURED) {
+      log.info("Sync client is not configured, so not attempting a tab sync");
+      return Promise.resolve(false);
+    }
+    // Ask Sync to just do the tabs engine if it can.
+    // Sync is currently synchronous, so do it after an event-loop spin to help
+    // keep the UI responsive.
+    return new Promise((resolve, reject) => {
+      Services.tm.currentThread.dispatch(() => {
+        try {
+          log.info("Doing a tab sync.");
+          Weave.Service.sync(["tabs"]);
+          resolve(true);
+        } catch (ex) {
+          log.error("Sync failed", ex);
+          reject(ex);
+        };
+      }, Ci.nsIThread.DISPATCH_NORMAL);
+    });
+  },
+
+  observe(subject, topic, data) {
+    log.trace(`observed topic=${topic}, data=${data}, subject=${subject}`);
+    switch (topic) {
+      case "weave:engine:sync:finish":
+        if (data != "tabs") {
+          return;
+        }
+        // The tabs engine just finished syncing
+        // Set our lastTabFetch pref here so it tracks both explicit sync calls
+        // and normally scheduled ones.
+        Preferences.set("services.sync.lastTabFetch", Math.floor(Date.now() / 1000));
+        Services.obs.notifyObservers(null, TOPIC_TABS_CHANGED, null);
+        break;
+      case "weave:service:start-over":
+        // start-over needs to notify so consumers find no tabs.
+        Preferences.reset("services.sync.lastTabFetch");
+        Services.obs.notifyObservers(null, TOPIC_TABS_CHANGED, null);
+        break;
+      default:
+        break;
+    }
+  },
+
+  // Returns true if Sync is configured to Sync tabs, false otherwise
+  get isConfiguredToSyncTabs() {
+    if (!weaveXPCService.ready) {
+      log.debug("Sync isn't yet ready; assuming tab engine is enabled");
+      return true;
+    }
+
+    let engine = Weave.Service.engineManager.get("tabs");
+    return engine && engine.enabled;
+  },
+
+  get hasSyncedThisSession() {
+    let engine = Weave.Service.engineManager.get("tabs");
+    return engine && engine.hasSyncedThisSession;
+  },
+};
+
+Services.obs.addObserver(SyncedTabsInternal, "weave:engine:sync:finish", false);
+Services.obs.addObserver(SyncedTabsInternal, "weave:service:start-over", false);
+
+// The public interface.
+this.SyncedTabs = {
+  // A mock-point for tests.
+  _internal: SyncedTabsInternal,
+
+  // We make the topic for the observer notification public.
+  TOPIC_TABS_CHANGED,
+
+  // Returns true if Sync is configured to Sync tabs, false otherwise
+  get isConfiguredToSyncTabs() {
+    return this._internal.isConfiguredToSyncTabs;
+  },
+
+  // Returns true if a tab sync has completed once this session. If this
+  // returns false, then getting back no clients/tabs possibly just means we
+  // are waiting for that first sync to complete.
+  get hasSyncedThisSession() {
+    return this._internal.hasSyncedThisSession;
+  },
+
+  // Return a promise that resolves with an array of client records, each with
+  // a .tabs array. Note that part of the contract for this module is that the
+  // returned objects are not shared between invocations, so callers are free
+  // to mutate the returned objects (eg, sort, truncate) however they see fit.
+  getTabClients(query) {
+    return this._internal.getTabClients(query);
+  },
+
+  // Starts a background request to start syncing tabs. Returns a promise that
+  // resolves when the sync is complete, but there's no resolved value -
+  // callers should be listening for TOPIC_TABS_CHANGED.
+  // If |force| is true we always sync. If false, we only sync if the most
+  // recent sync wasn't "recently".
+  syncTabs(force) {
+    return this._internal.syncTabs(force);
+  },
+};
+
--- a/services/sync/modules/engines/addons.js
+++ b/services/sync/modules/engines/addons.js
@@ -470,17 +470,17 @@ AddonsStore.prototype = {
       let addon = this.getAddonByGUID(guid);
       if (!addon) {
         this._log.debug("Ignoring add-on because it couldn't be obtained: " +
                         guid);
         continue;
       }
 
       this._log.info("Uninstalling add-on as part of wipe: " + addon.id);
-      Utils.catch(addon.uninstall)();
+      Utils.catch.call(this, () => addon.uninstall())();
     }
   },
 
   /***************************************************************************
    * Functions below are unique to this store and not part of the Store API  *
    ***************************************************************************/
 
   /**
--- a/services/sync/modules/engines/tabs.js
+++ b/services/sync/modules/engines/tabs.js
@@ -38,16 +38,21 @@ this.TabEngine = function TabEngine(serv
   // Reset the client on every startup so that we fetch recent tabs.
   this._resetClient();
 }
 TabEngine.prototype = {
   __proto__: SyncEngine.prototype,
   _storeObj: TabStore,
   _trackerObj: TabTracker,
   _recordObj: TabSetRecord,
+  // A flag to indicate if we have synced in this session. This is to help
+  // consumers of remote tabs that may want to differentiate between "I've an
+  // empty tab list as I haven't yet synced" vs "I've an empty tab list
+  // as there really are no tabs"
+  hasSyncedThisSession: false,
 
   syncPriority: 3,
 
   getChangedIDs: function () {
     // No need for a proper timestamp (no conflict resolution needed).
     let changedIDs = {};
     if (this._tracker.modified)
       changedIDs[this.service.clientsEngine.localID] = 0;
@@ -62,16 +67,17 @@ TabEngine.prototype = {
   getClientById: function (id) {
     return this._store._remoteClients[id];
   },
 
   _resetClient: function () {
     SyncEngine.prototype._resetClient.call(this);
     this._store.wipe();
     this._tracker.modified = true;
+    this.hasSyncedThisSession = false;
   },
 
   removeClientData: function () {
     let url = this.engineURL + "/" + this.service.clientsEngine.localID;
     this.service.resource(url).delete();
   },
 
   /**
@@ -89,17 +95,22 @@ TabEngine.prototype = {
     // Skip our own record.
     // TabStore.itemExists tests only against our local client ID.
     if (this._store.itemExists(item.id)) {
       this._log.trace("Ignoring incoming tab item because of its id: " + item.id);
       return false;
     }
 
     return SyncEngine.prototype._reconcile.call(this, item);
-  }
+  },
+
+  _syncFinish() {
+    this.hasSyncedThisSession = true;
+    return SyncEngine.prototype._syncFinish.call(this);
+  },
 };
 
 
 function TabStore(name, engine) {
   Store.call(this, name, engine);
 }
 TabStore.prototype = {
   __proto__: Store.prototype,
--- a/services/sync/moz.build
+++ b/services/sync/moz.build
@@ -31,16 +31,17 @@ EXTRA_JS_MODULES['services-sync'] += [
     'modules/keys.js',
     'modules/main.js',
     'modules/policies.js',
     'modules/record.js',
     'modules/resource.js',
     'modules/rest.js',
     'modules/service.js',
     'modules/status.js',
+    'modules/SyncedTabs.jsm',
     'modules/userapi.js',
     'modules/util.js',
 ]
 
 EXTRA_PP_JS_MODULES['services-sync'] += [
     'modules/constants.js',
 ]
 
new file mode 100644
--- /dev/null
+++ b/services/sync/tests/unit/test_syncedtabs.js
@@ -0,0 +1,125 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+ * vim:set ts=2 sw=2 sts=2 et:
+*/
+"use strict";
+
+Cu.import("resource://services-sync/main.js");
+Cu.import("resource://services-sync/SyncedTabs.jsm");
+Cu.import("resource://gre/modules/Log.jsm");
+
+Log.repository.getLogger("Sync.RemoteTabs").addAppender(new Log.DumpAppender());
+
+// A mock "Tabs" engine which the SyncedTabs module will use instead of the real
+// engine. We pass a constructor that Sync creates.
+function MockTabsEngine() {
+  this.clients = {}; // We'll set this dynamically
+}
+
+MockTabsEngine.prototype = {
+  name: "tabs",
+  enabled: true,
+
+  getAllClients() {
+    return this.clients;
+  },
+
+  getOpenURLs() {
+    return new Set();
+  },
+}
+
+// A clients engine that doesn't need to be a constructor.
+let MockClientsEngine = {
+  isMobile(guid) {
+    if (!guid.endsWith("desktop") && !guid.endsWith("mobile")) {
+      throw new Error("this module expected guids to end with 'desktop' or 'mobile'");
+    }
+    return guid.endsWith("mobile");
+  },
+}
+
+// Configure Sync with our mock tabs engine and force it to become initialized.
+Services.prefs.setCharPref("services.sync.username", "someone@somewhere.com");
+
+Weave.Service.engineManager.unregister("tabs");
+Weave.Service.engineManager.register(MockTabsEngine);
+Weave.Service.clientsEngine = MockClientsEngine;
+
+// Tell the Sync XPCOM service it is initialized.
+let weaveXPCService = Cc["@mozilla.org/weave/service;1"]
+                        .getService(Ci.nsISupports)
+                        .wrappedJSObject;
+weaveXPCService.ready = true;
+
+function configureClients(clients) {
+  // Configure the instance Sync created.
+  let engine = Weave.Service.engineManager.get("tabs");
+  // each client record is expected to have an id.
+  for (let [guid, client] in Iterator(clients)) {
+    client.id = guid;
+  }
+  engine.clients = clients;
+  // Send an observer that pretends the engine just finished a sync.
+  Services.obs.notifyObservers(null, "weave:engine:sync:finish", "tabs");
+}
+
+// The tests.
+add_task(function* test_noClients() {
+  // no clients, can't be tabs.
+  yield configureClients({});
+
+  let tabs = yield SyncedTabs.getTabClients();
+  equal(Object.keys(tabs).length, 0);
+});
+
+add_task(function* test_clientWithTabs() {
+  yield configureClients({
+    guid_desktop: {
+      clientName: "My Desktop",
+      tabs: [
+      {
+        urlHistory: ["http://foo.com/"],
+      }],
+    },
+    guid_mobile: {
+      clientName: "My Phone",
+      tabs: [],
+    }
+  });
+
+  let clients = yield SyncedTabs.getTabClients();
+  equal(clients.length, 2);
+  clients.sort((a, b) => { return a.name.localeCompare(b.name);});
+  equal(clients[0].tabs.length, 1);
+  equal(clients[0].tabs[0].url, "http://foo.com/");
+  // second client has no tabs.
+  equal(clients[1].tabs.length, 0);
+});
+
+add_task(function* test_filter() {
+  // Nothing matches.
+  yield configureClients({
+    guid_desktop: {
+      clientName: "My Desktop",
+      tabs: [
+      {
+        urlHistory: ["http://foo.com/"],
+        title: "A test page.",
+      },
+      {
+        urlHistory: ["http://bar.com/"],
+        title: "Another page.",
+      }],
+    },
+  });
+
+  let clients = yield SyncedTabs.getTabClients("foo");
+  equal(clients.length, 1);
+  equal(clients[0].tabs.length, 1);
+  equal(clients[0].tabs[0].url, "http://foo.com/");
+  // check it matches the title.
+  clients = yield SyncedTabs.getTabClients("test");
+  equal(clients.length, 1);
+  equal(clients[0].tabs.length, 1);
+  equal(clients[0].tabs[0].url, "http://foo.com/");
+});
--- a/services/sync/tests/unit/xpcshell.ini
+++ b/services/sync/tests/unit/xpcshell.ini
@@ -176,8 +176,11 @@ skip-if = debug
 
 [test_healthreport.js]
 skip-if = ! healthreport
 
 [test_warn_on_truncated_response.js]
 
 # FxA migration
 [test_fxa_migration.js]
+
+# Synced tabs.
+[test_syncedtabs.js]
--- a/toolkit/components/parentalcontrols/nsIParentalControlsService.idl
+++ b/toolkit/components/parentalcontrols/nsIParentalControlsService.idl
@@ -6,17 +6,17 @@
 
 #include "nsISupports.idl"
 
 interface nsIURI;
 interface nsIFile;
 interface nsIInterfaceRequestor;
 interface nsIArray;
 
-[scriptable, uuid(ec6ae96e-e161-481e-bb51-78b11fc1fdbe)]
+[scriptable, uuid(f35733bc-114b-49ce-a8dd-a423f19318bc)]
 interface nsIParentalControlsService : nsISupports
 {
   /**
    * Action types that can be blocked for users.
    */
   const short DOWNLOAD = 1; // Downloading files
   const short INSTALL_EXTENSION = 2; // Installing extensions
   const short INSTALL_APP = 3; // Installing webapps
@@ -24,17 +24,17 @@ interface nsIParentalControlsService : n
   const short SHARE = 5; // Sharing
   const short BOOKMARK = 6; // Creating bookmarks
   const short ADD_CONTACT = 7; // Add contacts to the system database
   const short SET_IMAGE = 8; // Setting images as wall paper
   const short MODIFY_ACCOUNTS = 9; // Modifying system accounts
   const short REMOTE_DEBUGGING = 10; // Remote debugging
   const short IMPORT_SETTINGS = 11; // Importing settings from other apps
   const short PRIVATE_BROWSING = 12; // Disallow usage of private browsing
-  const short LOCATION_SERVICE = 13; // Sharing of location data to location service
+  const short DATA_CHOICES = 13; // Choose whether or not to send usage information
   const short CLEAR_HISTORY = 14; // Clear browsing history
   const short MASTER_PASSWORD = 15; // Setting master password for logins
   const short GUEST_BROWSING = 16; // Disallow usage of guest browsing
   const short ADVANCED_SETTINGS = 17; // Advanced settings
   const short CAMERA_MICROPHONE = 18; // Camera and microphone (WebRTC)
 
   /**
    * @returns true if the current user account has parental controls
--- a/toolkit/mozapps/extensions/AddonManager.jsm
+++ b/toolkit/mozapps/extensions/AddonManager.jsm
@@ -16,16 +16,19 @@ const Cu = Components.utils;
 if ("@mozilla.org/xre/app-info;1" in Cc) {
   let runtime = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime);
   if (runtime.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) {
     // Refuse to run in child processes.
     throw new Error("You cannot use the AddonManager in child processes!");
   }
 }
 
+Cu.import("resource://gre/modules/AppConstants.jsm");
+
+const MOZ_COMPATIBILITY_NIGHTLY = !['aurora', 'beta', 'release', 'esr'].includes(AppConstants.MOZ_UPDATE_CHANNEL);
 
 const PREF_BLOCKLIST_PINGCOUNTVERSION = "extensions.blocklist.pingCountVersion";
 const PREF_DEFAULT_PROVIDERS_ENABLED  = "extensions.defaultProviders.enabled";
 const PREF_EM_UPDATE_ENABLED          = "extensions.update.enabled";
 const PREF_EM_LAST_APP_VERSION        = "extensions.lastAppVersion";
 const PREF_EM_LAST_PLATFORM_VERSION   = "extensions.lastPlatformVersion";
 const PREF_EM_AUTOUPDATE_DEFAULT      = "extensions.update.autoUpdateDefault";
 const PREF_EM_STRICT_COMPATIBILITY    = "extensions.strictCompatibility";
@@ -50,21 +53,19 @@ const CATEGORY_UPDATE_PARAMS          = 
 const XMLURI_BLOCKLIST                = "http://www.mozilla.org/2006/addons-blocklist";
 
 const KEY_PROFILEDIR                  = "ProfD";
 const KEY_APPDIR                      = "XCurProcD";
 const FILE_BLOCKLIST                  = "blocklist.xml";
 
 const BRANCH_REGEXP                   = /^([^\.]+\.[0-9]+[a-z]*).*/gi;
 const PREF_EM_CHECK_COMPATIBILITY_BASE = "extensions.checkCompatibility";
-#ifdef MOZ_COMPATIBILITY_NIGHTLY
-var PREF_EM_CHECK_COMPATIBILITY = PREF_EM_CHECK_COMPATIBILITY_BASE + ".nightly";
-#else
-var PREF_EM_CHECK_COMPATIBILITY;
-#endif
+var PREF_EM_CHECK_COMPATIBILITY = MOZ_COMPATIBILITY_NIGHTLY ?
+                                  PREF_EM_CHECK_COMPATIBILITY_BASE + ".nightly" :
+                                  undefined;
 
 const TOOLKIT_ID                      = "toolkit@mozilla.org";
 
 const VALID_TYPES_REGEXP = /^[\w\-]+$/;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/AsyncShutdown.jsm");
@@ -73,17 +74,17 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource://gre/modules/Task.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Promise",
                                   "resource://gre/modules/Promise.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "AddonRepository",
                                   "resource://gre/modules/addons/AddonRepository.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
                                   "resource://gre/modules/FileUtils.jsm");
 
-XPCOMUtils.defineLazyGetter(this, "CertUtils", function certUtilsLazyGetter() {
+XPCOMUtils.defineLazyGetter(this, "CertUtils", function() {
   let certUtils = {};
   Components.utils.import("resource://gre/modules/CertUtils.jsm", certUtils);
   return certUtils;
 });
 
 const INTEGER = /^[1-9]\d*$/;
 
 this.EXPORTED_SYMBOLS = [ "AddonManager", "AddonManagerPrivate" ];
@@ -131,23 +132,23 @@ function providerName(aProvider) {
 }
 
 /**
  * Preference listener which listens for a change in the
  * "extensions.logging.enabled" preference and changes the logging level of the
  * parent 'addons' level logger accordingly.
  */
 var PrefObserver = {
-    init: function PrefObserver_init() {
+    init: function() {
       Services.prefs.addObserver(PREF_LOGGING_ENABLED, this, false);
       Services.obs.addObserver(this, "xpcom-shutdown", false);
       this.observe(null, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, PREF_LOGGING_ENABLED);
     },
 
-    observe: function PrefObserver_observe(aSubject, aTopic, aData) {
+    observe: function(aSubject, aTopic, aData) {
       if (aTopic == "xpcom-shutdown") {
         Services.prefs.removeObserver(PREF_LOGGING_ENABLED, this);
         Services.obs.removeObserver(this, "xpcom-shutdown");
       }
       else if (aTopic == NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) {
         let debugLogEnabled = false;
         try {
           debugLogEnabled = Services.prefs.getBoolPref(PREF_LOGGING_ENABLED);
@@ -364,17 +365,17 @@ AsyncObjectCaller.prototype = {
   objects: null,
   method: null,
   listener: null,
 
   /**
    * Passes the next object to the listener or calls noMoreObjects if there
    * are none left.
    */
-  callNext: function AOC_callNext() {
+  callNext: function() {
     if (this.objects.length == 0) {
       this.listener.noMoreObjects(this);
       return;
     }
 
     let object = this.objects.shift();
     if (!this.method || this.method in object)
       this.listener.nextObject(this, object);
@@ -490,17 +491,17 @@ function AddonAuthor(aName, aURL) {
   this.url = aURL;
 }
 
 AddonAuthor.prototype = {
   name: null,
   url: null,
 
   // Returns the author's name, defaulting to the empty string
-  toString: function AddonAuthor_toString() {
+  toString: function() {
     return this.name || "";
   }
 }
 
 /**
  * This represents an screenshot for an add-on
  *
  * @param  aURL
@@ -534,17 +535,17 @@ AddonScreenshot.prototype = {
   width: null,
   height: null,
   thumbnailURL: null,
   thumbnailWidth: null,
   thumbnailHeight: null,
   caption: null,
 
   // Returns the screenshot URL, defaulting to the empty string
-  toString: function AddonScreenshot_toString() {
+  toString: function() {
     return this.url || "";
   }
 }
 
 
 /**
  * This represents a compatibility override for an addon.
  *
@@ -640,21 +641,19 @@ function AddonType(aID, aLocaleURI, aLoc
                                Cr.NS_ERROR_INVALID_ARG);
 
   this.id = aID;
   this.uiPriority = aUIPriority;
   this.viewType = aViewType;
   this.flags = aFlags;
 
   if (aLocaleURI) {
-    this.__defineGetter__("name", function nameGetter() {
-      delete this.name;
+    XPCOMUtils.defineLazyGetter(this, "name", () => {
       let bundle = Services.strings.createBundle(aLocaleURI);
-      this.name = bundle.GetStringFromName(aLocaleKey.replace("%ID%", aID));
-      return this.name;
+      return bundle.GetStringFromName(aLocaleKey.replace("%ID%", aID));
     });
   }
   else {
     this.name = aLocaleKey;
   }
 }
 
 var gStarted = false;
@@ -686,66 +685,66 @@ var AddonManagerInternal = {
   providerShutdowns: new Map(),
   types: {},
   startupChanges: {},
   // Store telemetry details per addon provider
   telemetryDetails: {},
 
   // A read-only wrapper around the types dictionary
   typesProxy: Proxy.create({
-    getOwnPropertyDescriptor: function typesProxy_getOwnPropertyDescriptor(aName) {
+    getOwnPropertyDescriptor: function(aName) {
       if (!(aName in AddonManagerInternal.types))
         return undefined;
 
       return {
         value: AddonManagerInternal.types[aName].type,
         writable: false,
         configurable: false,
         enumerable: true
       }
     },
 
-    getPropertyDescriptor: function typesProxy_getPropertyDescriptor(aName) {
+    getPropertyDescriptor: function(aName) {
       return this.getOwnPropertyDescriptor(aName);
     },
 
-    getOwnPropertyNames: function typesProxy_getOwnPropertyNames() {
+    getOwnPropertyNames: function() {
       return Object.keys(AddonManagerInternal.types);
     },
 
-    getPropertyNames: function typesProxy_getPropertyNames() {
+    getPropertyNames: function() {
       return this.getOwnPropertyNames();
     },
 
-    delete: function typesProxy_delete(aName) {
+    delete: function(aName) {
       // Not allowed to delete properties
       return false;
     },
 
-    defineProperty: function typesProxy_defineProperty(aName, aProperty) {
+    defineProperty: function(aName, aProperty) {
       // Ignore attempts to define properties
     },
 
-    fix: function typesProxy_fix(){
+    fix: function(){
       return undefined;
     },
 
     // Despite MDC's claims to the contrary, it is required that this trap
     // be defined
-    enumerate: function typesProxy_enumerate() {
+    enumerate: function() {
       // All properties are enumerable
       return this.getPropertyNames();
     }
   }),
 
-  recordTimestamp: function AMI_recordTimestamp(name, value) {
+  recordTimestamp: function(name, value) {
     this.TelemetryTimestamps.add(name, value);
   },
 
-  validateBlocklist: function AMI_validateBlocklist() {
+  validateBlocklist: function() {
     let appBlocklist = FileUtils.getFile(KEY_APPDIR, [FILE_BLOCKLIST]);
 
     // If there is no application shipped blocklist then there is nothing to do
     if (!appBlocklist.exists())
       return;
 
     let profileBlocklist = FileUtils.getFile(KEY_PROFILEDIR, [FILE_BLOCKLIST]);
 
@@ -869,17 +868,17 @@ var AddonManagerInternal = {
         return provider;
     }
   },
 
   /**
    * Initializes the AddonManager, loading any known providers and initializing
    * them.
    */
-  startup: function AMI_startup() {
+  startup: function() {
     try {
       if (gStarted)
         return;
 
       this.recordTimestamp("AMI_startup_begin");
 
       // clear this for xpcshell test restarts
       for (let provider in this.telemetryDetails)
@@ -906,20 +905,20 @@ var AddonManagerInternal = {
                                    Services.appinfo.version);
         Services.prefs.setCharPref(PREF_EM_LAST_PLATFORM_VERSION,
                                    Services.appinfo.platformVersion);
         Services.prefs.setIntPref(PREF_BLOCKLIST_PINGCOUNTVERSION,
                                   (appChanged === undefined ? 0 : -1));
         this.validateBlocklist();
       }
 
-#ifndef MOZ_COMPATIBILITY_NIGHTLY
-      PREF_EM_CHECK_COMPATIBILITY = PREF_EM_CHECK_COMPATIBILITY_BASE + "." +
-                                    Services.appinfo.version.replace(BRANCH_REGEXP, "$1");
-#endif
+      if (!MOZ_COMPATIBILITY_NIGHTLY) {
+        PREF_EM_CHECK_COMPATIBILITY = PREF_EM_CHECK_COMPATIBILITY_BASE + "." +
+                                      Services.appinfo.version.replace(BRANCH_REGEXP, "$1");
+      }
 
       try {
         gCheckCompatibility = Services.prefs.getBoolPref(PREF_EM_CHECK_COMPATIBILITY);
       } catch (e) {}
       Services.prefs.addObserver(PREF_EM_CHECK_COMPATIBILITY, this, false);
 
       try {
         gStrictCompatibility = Services.prefs.getBoolPref(PREF_EM_STRICT_COMPATIBILITY);
@@ -1045,51 +1044,48 @@ var AddonManagerInternal = {
   /**
    * Registers a new AddonProvider.
    *
    * @param  aProvider
    *         The provider to register
    * @param  aTypes
    *         An optional array of add-on types
    */
-  registerProvider: function AMI_registerProvider(aProvider, aTypes) {
+  registerProvider: function(aProvider, aTypes) {
     if (!aProvider || typeof aProvider != "object")
       throw Components.Exception("aProvider must be specified",
                                  Cr.NS_ERROR_INVALID_ARG);
 
     if (aTypes && !Array.isArray(aTypes))
       throw Components.Exception("aTypes must be an array or null",
                                  Cr.NS_ERROR_INVALID_ARG);
 
     this.pendingProviders.add(aProvider);
 
     if (aTypes) {
-      aTypes.forEach(function(aType) {
-        if (!(aType.id in this.types)) {
-          if (!VALID_TYPES_REGEXP.test(aType.id)) {
-            logger.warn("Ignoring invalid type " + aType.id);
+      for (let type of aTypes) {
+        if (!(type.id in this.types)) {
+          if (!VALID_TYPES_REGEXP.test(type.id)) {
+            logger.warn("Ignoring invalid type " + type.id);
             return;
           }
 
-          this.types[aType.id] = {
-            type: aType,
+          this.types[type.id] = {
+            type: type,
             providers: [aProvider]
           };
 
           let typeListeners = this.typeListeners.slice(0);
-          for (let listener of typeListeners) {
-            safeCall(function listenerSafeCall() {
-              listener.onTypeAdded(aType);
-            });
-          }
+          for (let listener of typeListeners)
+            safeCall(() => listener.onTypeAdded(type));
         }
         else {
-          this.types[aType.id].providers.push(aProvider);
+          this.types[type.id].providers.push(aProvider);
         }
-      }, this);
+      }
     }
 
     // If we're registering after startup call this provider's startup.
     if (gStarted) {
       this._startProvider(aProvider);
     }
   },
 
@@ -1097,17 +1093,17 @@ var AddonManagerInternal = {
    * Unregisters an AddonProvider.
    *
    * @param  aProvider
    *         The provider to unregister
    * @return Whatever the provider's 'shutdown' method returns (if anything).
    *         For providers that have async shutdown methods returning Promises,
    *         the caller should wait for that Promise to resolve.
    */
-  unregisterProvider: function AMI_unregisterProvider(aProvider) {
+  unregisterProvider: function(aProvider) {
     if (!aProvider || typeof aProvider != "object")
       throw Components.Exception("aProvider must be specified",
                                  Cr.NS_ERROR_INVALID_ARG);
 
     this.providers.delete(aProvider);
     // The test harness will unregister XPIProvider *after* shutdown, which is
     // after the provider will have been moved from providers to
     // pendingProviders.
@@ -1115,21 +1111,18 @@ var AddonManagerInternal = {
 
     for (let type in this.types) {
       this.types[type].providers = this.types[type].providers.filter(p => p != aProvider);
       if (this.types[type].providers.length == 0) {
         let oldType = this.types[type].type;
         delete this.types[type];
 
         let typeListeners = this.typeListeners.slice(0);
-        for (let listener of typeListeners) {
-          safeCall(function listenerSafeCall() {
-            listener.onTypeRemoved(oldType);
-          });
-        }
+        for (let listener of typeListeners)
+          safeCall(() => listener.onTypeRemoved(oldType));
       }
     }
 
     // If we're unregistering after startup but before shutting down,
     // remove the blocker for this provider's shutdown and call it.
     // If we're already shutting down, just let gShutdownBarrier call it to avoid races.
     if (gStarted && !gShutdownInProgress) {
       logger.debug("Unregistering shutdown blocker for " + providerName(aProvider));
@@ -1152,17 +1145,17 @@ var AddonManagerInternal = {
    * it won't be used by any of the AddonManager APIs. markProviderSafe()
    * allows a provider to mark itself as safe during its startup; this can be
    * useful if the provider wants to perform tasks that block startup, which
    * happen after its required initialization tasks and therefore when the
    * provider is in a safe state.
    *
    * @param aProvider Provider object to mark safe
    */
-  markProviderSafe: function AMI_markProviderSafe(aProvider) {
+  markProviderSafe: function(aProvider) {
     if (!gStarted) {
       throw Components.Exception("AddonManager is not initialized",
                                  Cr.NS_ERROR_NOT_INITIALIZED);
     }
 
     if (!aProvider || typeof aProvider != "object") {
       throw Components.Exception("aProvider must be specified",
                                  Cr.NS_ERROR_INVALID_ARG);
@@ -1182,17 +1175,17 @@ var AddonManagerInternal = {
    * method parameter are passed to the provider's method.
    * WARNING: Do not use for asynchronous calls; callProviders() does not
    * invoke callbacks if provider methods throw synchronous exceptions.
    *
    * @param  aMethod
    *         The method name to call
    * @see    callProvider
    */
-  callProviders: function AMI_callProviders(aMethod, ...aArgs) {
+  callProviders: function(aMethod, ...aArgs) {
     if (!aMethod || typeof aMethod != "string")
       throw Components.Exception("aMethod must be a non-empty string",
                                  Cr.NS_ERROR_INVALID_ARG);
 
     let providers = [...this.providers];
     for (let provider of providers) {
       try {
         if (aMethod in provider)
@@ -1223,17 +1216,17 @@ var AddonManagerInternal = {
   },
 
   /**
    * Shuts down the addon manager and all registered providers, this must clean
    * up everything in order for automated tests to fake restarts.
    * @return Promise{null} that resolves when all providers and dependent modules
    *                       have finished shutting down
    */
-  shutdownManager: Task.async(function* () {
+  shutdownManager: Task.async(function*() {
     logger.debug("shutdown");
     this.callManagerListeners("onShutdown");
 
     gRepoShutdownState = "pending";
     gShutdownInProgress = true;
     // Clean up listeners
     Services.prefs.removeObserver(PREF_EM_CHECK_COMPATIBILITY, this);
     Services.prefs.removeObserver(PREF_EM_STRICT_COMPATIBILITY, this);
@@ -1294,27 +1287,27 @@ var AddonManagerInternal = {
     function filterProperties(plugin) {
       let filtered = {};
       for (let prop of NEEDED_PROPS) {
         filtered[prop] = plugin[prop];
       }
       return filtered;
     }
 
-    AddonManager.getAddonsByTypes(["plugin"], function (aPlugins) {
+    AddonManager.getAddonsByTypes(["plugin"], function(aPlugins) {
       port.sendAsyncMessage("PluginList", [filterProperties(p) for (p of aPlugins)]);
     });
   },
 
   /**
    * Notified when a preference we're interested in has changed.
    *
    * @see nsIObserver
    */
-  observe: function AMI_observe(aSubject, aTopic, aData) {
+  observe: function(aSubject, aTopic, aData) {
     switch (aData) {
       case PREF_EM_CHECK_COMPATIBILITY: {
         let oldValue = gCheckCompatibility;
         try {
           gCheckCompatibility = Services.prefs.getBoolPref(PREF_EM_CHECK_COMPATIBILITY);
         } catch(e) {
           gCheckCompatibility = true;
         }
@@ -1400,17 +1393,17 @@ var AddonManagerInternal = {
    * @param  aAddon
    *         The Addon representing the add-on
    * @param  aUri
    *         The string representation of the URI to escape
    * @param  aAppVersion
    *         The optional application version to use for %APP_VERSION%
    * @return The appropriately escaped URI.
    */
-  escapeAddonURI: function AMI_escapeAddonURI(aAddon, aUri, aAppVersion)
+  escapeAddonURI: function(aAddon, aUri, aAppVersion)
   {
     if (!aAddon || typeof aAddon != "object")
       throw Components.Exception("aAddon must be an Addon object",
                                  Cr.NS_ERROR_INVALID_ARG);
 
     if (!aUri || typeof aUri != "string")
       throw Components.Exception("aUri must be a non-empty string",
                                  Cr.NS_ERROR_INVALID_ARG);
@@ -1445,17 +1438,17 @@ var AddonManagerInternal = {
     uri = uri.replace(/%APP_OS%/g, Services.appinfo.OS);
     uri = uri.replace(/%APP_ABI%/g, xpcomABI);
     uri = uri.replace(/%APP_LOCALE%/g, getLocale());
     uri = uri.replace(/%CURRENT_APP_VERSION%/g, Services.appinfo.version);
 
     // Replace custom parameters (names of custom parameters must have at
     // least 3 characters to prevent lookups for something like %D0%C8)
     var catMan = null;
-    uri = uri.replace(/%(\w{3,})%/g, function parameterReplace(aMatch, aParam) {
+    uri = uri.replace(/%(\w{3,})%/g, function(aMatch, aParam) {
       if (!catMan) {
         catMan = Cc["@mozilla.org/categorymanager;1"].
                  getService(Ci.nsICategoryManager);
       }
 
       try {
         var contractID = catMan.getCategoryEntry(CATEGORY_UPDATE_PARAMS, aParam);
         var paramHandler = Cc[contractID].getService(Ci.nsIPropertyBag2);
@@ -1471,22 +1464,22 @@ var AddonManagerInternal = {
   },
 
   /**
    * Performs a background update check by starting an update for all add-ons
    * that can be updated.
    * @return Promise{null} Resolves when the background update check is complete
    *                       (the resulting addon installations may still be in progress).
    */
-  backgroundUpdateCheck: function AMI_backgroundUpdateCheck() {
+  backgroundUpdateCheck: function() {
     if (!gStarted)
       throw Components.Exception("AddonManager is not initialized",
                                  Cr.NS_ERROR_NOT_INITIALIZED);
 
-    let buPromise = Task.spawn(function* backgroundUpdateTask() {
+    let buPromise = Task.spawn(function*() {
       let hotfixID = this.hotfixID;
 
       let appUpdateEnabled = Services.prefs.getBoolPref(PREF_APP_UPDATE_ENABLED) &&
                              Services.prefs.getBoolPref(PREF_APP_UPDATE_AUTO);
       let checkHotfix = hotfixID && appUpdateEnabled;
 
       logger.debug("Background update check beginning");
 
@@ -1510,17 +1503,17 @@ var AddonManagerInternal = {
           if (addon.id == hotfixID) {
             continue;
           }
 
           // Check all add-ons for updates so that any compatibility updates will
           // be applied
           updates.push(new Promise((resolve, reject) => {
             addon.findUpdates({
-              onUpdateAvailable: function BUC_onUpdateAvailable(aAddon, aInstall) {
+              onUpdateAvailable: function(aAddon, aInstall) {
                 // Start installing updates when the add-on can be updated and
                 // background updates should be applied.
                 logger.debug("Found update for add-on ${id}", aAddon);
                 if (aAddon.permissions & AddonManager.PERM_CAN_UPGRADE &&
                     AddonManager.shouldAutoUpdate(aAddon)) {
                   // XXX we really should resolve when this install is done,
                   // not when update-available check completes, no?
                   logger.debug("Starting install of ${id}", aAddon);
@@ -1576,17 +1569,17 @@ var AddonManagerInternal = {
           if (Services.vc.compare(hotfixVersion, update.version) < 0) {
             logger.debug("Downloading hotfix version " + update.version);
             let aInstall = yield new Promise((resolve, reject) =>
               AddonManager.getInstallForURL(update.updateURL, resolve,
                 "application/x-xpinstall", update.updateHash, null,
                 null, update.version));
 
             aInstall.addListener({
-              onDownloadEnded: function BUC_onDownloadEnded(aInstall) {
+              onDownloadEnded: function(aInstall) {
                 if (aInstall.addon.id != hotfixID) {
                   logger.warn("The downloaded hotfix add-on did not have the " +
                               "expected ID and so will not be installed.");
                   aInstall.cancel();
                   return;
                 }
 
                 // If XPIProvider has reported the hotfix as properly signed then
@@ -1609,23 +1602,23 @@ var AddonManagerInternal = {
                 }
                 catch (e) {
                   logger.warn("The hotfix add-on was not signed by the expected " +
                        "certificate and so will not be installed.", e);
                   aInstall.cancel();
                 }
               },
 
-              onInstallEnded: function BUC_onInstallEnded(aInstall) {
+              onInstallEnded: function(aInstall) {
                 // Remember the last successfully installed version.
                 Services.prefs.setCharPref(PREF_EM_HOTFIX_LASTVERSION,
                                            aInstall.version);
               },
 
-              onInstallCancelled: function BUC_onInstallCancelled(aInstall) {
+              onInstallCancelled: function(aInstall) {
                 // Revert to the previous version if the installation was
                 // cancelled.
                 Services.prefs.setCharPref(PREF_EM_HOTFIX_LASTVERSION,
                                            hotfixVersion);
               }
             });
 
             aInstall.install();
@@ -1659,17 +1652,17 @@ var AddonManagerInternal = {
    *
    * @param  aType
    *         The type of change as a string. Providers can define their own
    *         types of changes or use the existing defined STARTUP_CHANGE_*
    *         constants
    * @param  aID
    *         The ID of the add-on
    */
-  addStartupChange: function AMI_addStartupChange(aType, aID) {
+  addStartupChange: function(aType, aID) {
     if (!aType || typeof aType != "string")
       throw Components.Exception("aType must be a non-empty string",
                                  Cr.NS_ERROR_INVALID_ARG);
 
     if (!aID || typeof aID != "string")
       throw Components.Exception("aID must be a non-empty string",
                                  Cr.NS_ERROR_INVALID_ARG);
 
@@ -1689,17 +1682,17 @@ var AddonManagerInternal = {
   /**
    * Removes a startup change for an add-on.
    *
    * @param  aType
    *         The type of change
    * @param  aID
    *         The ID of the add-on
    */
-  removeStartupChange: function AMI_removeStartupChange(aType, aID) {
+  removeStartupChange: function(aType, aID) {
     if (!aType || typeof aType != "string")
       throw Components.Exception("aType must be a non-empty string",
                                  Cr.NS_ERROR_INVALID_ARG);
 
     if (!aID || typeof aID != "string")
       throw Components.Exception("aID must be a non-empty string",
                                  Cr.NS_ERROR_INVALID_ARG);
 
@@ -1714,17 +1707,17 @@ var AddonManagerInternal = {
 
   /**
    * Calls all registered AddonManagerListeners with an event. Any parameters
    * after the method parameter are passed to the listener.
    *
    * @param  aMethod
    *         The method on the listeners to call
    */
-  callManagerListeners: function AMI_callManagerListeners(aMethod, ...aArgs) {
+  callManagerListeners: function(aMethod, ...aArgs) {
     if (!gStarted)
       throw Components.Exception("AddonManager is not initialized",
                                  Cr.NS_ERROR_NOT_INITIALIZED);
 
     if (!aMethod || typeof aMethod != "string")
       throw Components.Exception("aMethod must be a non-empty string",
                                  Cr.NS_ERROR_INVALID_ARG);
 
@@ -1745,17 +1738,17 @@ var AddonManagerInternal = {
    * the extraListeners parameter are passed to the listener.
    *
    * @param  aMethod
    *         The method on the listeners to call
    * @param  aExtraListeners
    *         An optional array of extra InstallListeners to also call
    * @return false if any of the listeners returned false, true otherwise
    */
-  callInstallListeners: function AMI_callInstallListeners(aMethod,
+  callInstallListeners: function(aMethod,
                                  aExtraListeners, ...aArgs) {
     if (!gStarted)
       throw Components.Exception("AddonManager is not initialized",
                                  Cr.NS_ERROR_NOT_INITIALIZED);
 
     if (!aMethod || typeof aMethod != "string")
       throw Components.Exception("aMethod must be a non-empty string",
                                  Cr.NS_ERROR_INVALID_ARG);
@@ -1787,17 +1780,17 @@ var AddonManagerInternal = {
 
   /**
    * Calls all registered AddonListeners with an event. Any parameters after
    * the method parameter are passed to the listener.
    *
    * @param  aMethod
    *         The method on the listeners to call
    */
-  callAddonListeners: function AMI_callAddonListeners(aMethod, ...aArgs) {
+  callAddonListeners: function(aMethod, ...aArgs) {
     if (!gStarted)
       throw Components.Exception("AddonManager is not initialized",
                                  Cr.NS_ERROR_NOT_INITIALIZED);
 
     if (!aMethod || typeof aMethod != "string")
       throw Components.Exception("aMethod must be a non-empty string",
                                  Cr.NS_ERROR_INVALID_ARG);
 
@@ -1821,17 +1814,17 @@ var AddonManagerInternal = {
    * @param  aID
    *         The ID of the enabled add-on
    * @param  aType
    *         The type of the enabled add-on
    * @param  aPendingRestart
    *         A boolean indicating if the change will only take place the next
    *         time the application is restarted
    */
-  notifyAddonChanged: function AMI_notifyAddonChanged(aID, aType, aPendingRestart) {
+  notifyAddonChanged: function(aID, aType, aPendingRestart) {
     if (!gStarted)
       throw Components.Exception("AddonManager is not initialized",
                                  Cr.NS_ERROR_NOT_INITIALIZED);
 
     if (aID && typeof aID != "string")
       throw Components.Exception("aID must be a string or null",
                                  Cr.NS_ERROR_INVALID_ARG);
 
@@ -1858,46 +1851,46 @@ var AddonManagerInternal = {
     }
   },
 
   /**
    * Notifies all providers they need to update the appDisabled property for
    * their add-ons in response to an application change such as a blocklist
    * update.
    */
-  updateAddonAppDisabledStates: function AMI_updateAddonAppDisabledStates() {
+  updateAddonAppDisabledStates: function() {
     if (!gStarted)
       throw Components.Exception("AddonManager is not initialized",
                                  Cr.NS_ERROR_NOT_INITIALIZED);
 
     this.callProviders("updateAddonAppDisabledStates");
   },
 
   /**
    * Notifies all providers that the repository has updated its data for
    * installed add-ons.
    *
    * @param  aCallback
    *         Function to call when operation is complete.
    */
-  updateAddonRepositoryData: function AMI_updateAddonRepositoryData(aCallback) {
+  updateAddonRepositoryData: function(aCallback) {
     if (!gStarted)
       throw Components.Exception("AddonManager is not initialized",
                                  Cr.NS_ERROR_NOT_INITIALIZED);
 
     if (typeof aCallback != "function")
       throw Components.Exception("aCallback must be a function",
                                  Cr.NS_ERROR_INVALID_ARG);
 
     new AsyncObjectCaller(this.providers, "updateAddonRepositoryData", {
-      nextObject: function updateAddonRepositoryData_nextObject(aCaller, aProvider) {
+      nextObject: function(aCaller, aProvider) {
         callProviderAsync(aProvider, "updateAddonRepositoryData",
                           aCaller.callNext.bind(aCaller));
       },
-      noMoreObjects: function updateAddonRepositoryData_noMoreObjects(aCaller) {
+      noMoreObjects: function(aCaller) {
         safeCall(aCallback);
         // only tests should care about this
         Services.obs.notifyObservers(null, "TEST:addon-repository-data-updated", null);
       }
     });
   },
 
   /**
@@ -1916,17 +1909,17 @@ var AddonManagerInternal = {
    * @param  aIcons
    *         Optional placeholder icons while the add-on is being downloaded
    * @param  aVersion
    *         An optional placeholder version while the add-on is being downloaded
    * @param  aLoadGroup
    *         An optional nsILoadGroup to associate any network requests with
    * @throws if the aUrl, aCallback or aMimetype arguments are not specified
    */
-  getInstallForURL: function AMI_getInstallForURL(aUrl, aCallback, aMimetype,
+  getInstallForURL: function(aUrl, aCallback, aMimetype,
                                                   aHash, aName, aIcons,
                                                   aVersion, aBrowser) {
     if (!gStarted)
       throw Components.Exception("AddonManager is not initialized",
                                  Cr.NS_ERROR_NOT_INITIALIZED);
 
     if (!aUrl || typeof aUrl != "string")
       throw Components.Exception("aURL must be a non-empty string",
@@ -1986,17 +1979,17 @@ var AddonManagerInternal = {
    * @param  aFile
    *         The nsIFile where the add-on is located
    * @param  aCallback
    *         A callback to pass the AddonInstall to
    * @param  aMimetype
    *         An optional mimetype hint for the add-on
    * @throws if the aFile or aCallback arguments are not specified
    */
-  getInstallForFile: function AMI_getInstallForFile(aFile, aCallback, aMimetype) {
+  getInstallForFile: function(aFile, aCallback, aMimetype) {
     if (!gStarted)
       throw Components.Exception("AddonManager is not initialized",
                                  Cr.NS_ERROR_NOT_INITIALIZED);
 
     if (!(aFile instanceof Ci.nsIFile))
       throw Components.Exception("aFile must be a nsIFile",
                                  Cr.NS_ERROR_INVALID_ARG);
 
@@ -2004,81 +1997,81 @@ var AddonManagerInternal = {
       throw Components.Exception("aCallback must be a function",
                                  Cr.NS_ERROR_INVALID_ARG);
 
     if (aMimetype && typeof aMimetype != "string")
       throw Components.Exception("aMimetype must be a string or null",
                                  Cr.NS_ERROR_INVALID_ARG);
 
     new AsyncObjectCaller(this.providers, "getInstallForFile", {
-      nextObject: function getInstallForFile_nextObject(aCaller, aProvider) {
+      nextObject: function(aCaller, aProvider) {
         callProviderAsync(aProvider, "getInstallForFile", aFile,
-                          function getInstallForFile_safeCall(aInstall) {
+                          function(aInstall) {
           if (aInstall)
             safeCall(aCallback, aInstall);
           else
             aCaller.callNext();
         });
       },
 
-      noMoreObjects: function getInstallForFile_noMoreObjects(aCaller) {
+      noMoreObjects: function(aCaller) {
         safeCall(aCallback, null);
       }
     });
   },
 
   /**
    * Asynchronously gets all current AddonInstalls optionally limiting to a list
    * of types.
    *
    * @param  aTypes
    *         An optional array of types to retrieve. Each type is a string name
    * @param  aCallback
    *         A callback which will be passed an array of AddonInstalls
    * @throws If the aCallback argument is not specified
    */
-  getInstallsByTypes: function AMI_getInstallsByTypes(aTypes, aCallback) {
+  getInstallsByTypes: function(aTypes, aCallback) {
     if (!gStarted)
       throw Components.Exception("AddonManager is not initialized",
                                  Cr.NS_ERROR_NOT_INITIALIZED);
 
     if (aTypes && !Array.isArray(aTypes))
       throw Components.Exception("aTypes must be an array or null",
                                  Cr.NS_ERROR_INVALID_ARG);
 
     if (typeof aCallback != "function")
       throw Components.Exception("aCallback must be a function",
                                  Cr.NS_ERROR_INVALID_ARG);
 
     let installs = [];
 
     new AsyncObjectCaller(this.providers, "getInstallsByTypes", {
-      nextObject: function getInstallsByTypes_nextObject(aCaller, aProvider) {
+      nextObject: function(aCaller, aProvider) {
         callProviderAsync(aProvider, "getInstallsByTypes", aTypes,
-                          function getInstallsByTypes_safeCall(aProviderInstalls) {
+                          function(aProviderInstalls) {
           if (aProviderInstalls) {
             installs = installs.concat(aProviderInstalls);
           }
           aCaller.callNext();
         });
       },
 
-      noMoreObjects: function getInstallsByTypes_noMoreObjects(aCaller) {
+      noMoreObjects: function(aCaller) {
         safeCall(aCallback, installs);
       }
     });
   },
 
   /**
    * Asynchronously gets all current AddonInstalls.
    *
    * @param  aCallback
    *         A callback which will be passed an array of AddonInstalls
    */
-  getAllInstalls: function AMI_getAllInstalls(aCallback) {
+  getAllInstalls: function(aCallback) {
     if (!gStarted)
       throw Components.Exception("AddonManager is not initialized",
                                  Cr.NS_ERROR_NOT_INITIALIZED);
 
     this.getInstallsByTypes(null, aCallback);
   },
 
   /**
@@ -2088,17 +2081,17 @@ var AddonManagerInternal = {
    * add-on, such as Javascript compartments, XUL windows, XBL bindings, etc.
    * but do not include URIs from meta data, such as the add-on homepage.
    *
    * @param  aURI
    *         nsIURI to map to an addon id
    * @return string containing the Addon ID or null
    * @see    amIAddonManager.mapURIToAddonID
    */
-  mapURIToAddonID: function AMI_mapURIToAddonID(aURI) {
+  mapURIToAddonID: function(aURI) {
     if (!(aURI instanceof Ci.nsIURI)) {
       throw Components.Exception("aURI is not a nsIURI",
                                  Cr.NS_ERROR_INVALID_ARG);
     }
 
     // Try all providers
     let providers = [...this.providers];
     for (let provider of providers) {
@@ -2113,17 +2106,17 @@ var AddonManagerInternal = {
 
   /**
    * Checks whether installation is enabled for a particular mimetype.
    *
    * @param  aMimetype
    *         The mimetype to check
    * @return true if installation is enabled for the mimetype
    */
-  isInstallEnabled: function AMI_isInstallEnabled(aMimetype) {
+  isInstallEnabled: function(aMimetype) {
     if (!gStarted)
       throw Components.Exception("AddonManager is not initialized",
                                  Cr.NS_ERROR_NOT_INITIALIZED);
 
     if (!aMimetype || typeof aMimetype != "string")
       throw Components.Exception("aMimetype must be a non-empty string",
                                  Cr.NS_ERROR_INVALID_ARG);
 
@@ -2141,17 +2134,17 @@ var AddonManagerInternal = {
    * given mimetype.
    *
    * @param  aMimetype
    *         The mimetype of the add-on
    * @param  aInstallingPrincipal
    *         The nsIPrincipal that initiated the install
    * @return true if the source is allowed to install this mimetype
    */
-  isInstallAllowed: function AMI_isInstallAllowed(aMimetype, aInstallingPrincipal) {
+  isInstallAllowed: function(aMimetype, aInstallingPrincipal) {
     if (!gStarted)
       throw Components.Exception("AddonManager is not initialized",
                                  Cr.NS_ERROR_NOT_INITIALIZED);
 
     if (!aMimetype || typeof aMimetype != "string")
       throw Components.Exception("aMimetype must be a non-empty string",
                                  Cr.NS_ERROR_INVALID_ARG);
 
@@ -2176,20 +2169,18 @@ var AddonManagerInternal = {
    *         The mimetype of add-ons being installed
    * @param  aBrowser
    *         The optional browser element that started the installs
    * @param  aInstallingPrincipal
    *         The nsIPrincipal that initiated the install
    * @param  aInstalls
    *         The array of AddonInstalls to be installed
    */
-  installAddonsFromWebpage: function AMI_installAddonsFromWebpage(aMimetype,
-                                                                  aBrowser,
-                                                                  aInstallingPrincipal,
-                                                                  aInstalls) {
+  installAddonsFromWebpage: function(aMimetype, aBrowser,
+                                     aInstallingPrincipal, aInstalls) {
     if (!gStarted)
       throw Components.Exception("AddonManager is not initialized",
                                  Cr.NS_ERROR_NOT_INITIALIZED);
 
     if (!aMimetype || typeof aMimetype != "string")
       throw Components.Exception("aMimetype must be a non-empty string",
                                  Cr.NS_ERROR_INVALID_ARG);
 
@@ -2202,19 +2193,18 @@ var AddonManagerInternal = {
                                  Cr.NS_ERROR_INVALID_ARG);
 
     if (!Array.isArray(aInstalls))
       throw Components.Exception("aInstalls must be an array",
                                  Cr.NS_ERROR_INVALID_ARG);
 
     if (!("@mozilla.org/addons/web-install-listener;1" in Cc)) {
       logger.warn("No web installer available, cancelling all installs");
-      aInstalls.forEach(function(aInstall) {
-        aInstall.cancel();
-      });
+      for (let install of aInstalls)
+        install.cancel();
       return;
     }
 
     // When a chrome in-content UI has loaded a <browser> inside to host a
     // website we want to do our security checks on the inner-browser but
     // notify front-end that install events came from the outer-browser (the
     // main tab's browser). Check this by seeing if the browser we've been
     // passed is in a content type docshell and if so get the outer-browser.
@@ -2252,62 +2242,59 @@ var AddonManagerInternal = {
       // The installs may start now depending on the web install listener,
       // listen for the browser navigating to a new origin and cancel the
       // installs in that case.
       new BrowserListener(aBrowser, aInstallingPrincipal, aInstalls);
 
       if (!this.isInstallAllowed(aMimetype, aInstallingPrincipal)) {
         if (weblistener.onWebInstallBlocked(topBrowser, aInstallingPrincipal.URI,
                                             aInstalls, aInstalls.length)) {
-          aInstalls.forEach(function(aInstall) {
-            aInstall.install();
-          });
+          for (let install of aInstalls)
+            install.install();
         }
       }
       else if (weblistener.onWebInstallRequested(topBrowser, aInstallingPrincipal.URI,
                                                  aInstalls, aInstalls.length)) {
-        aInstalls.forEach(function(aInstall) {
-          aInstall.install();
-        });
+        for (let install of aInstalls)
+          install.install();
       }
     }
     catch (e) {
       // In the event that the weblistener throws during instantiation or when
       // calling onWebInstallBlocked or onWebInstallRequested all of the
       // installs should get cancelled.
       logger.warn("Failure calling web installer", e);
-      aInstalls.forEach(function(aInstall) {
-        aInstall.cancel();
-      });
+      for (let install of aInstalls)
+        install.cancel();
     }
   },
 
   /**
    * Adds a new InstallListener if the listener is not already registered.
    *
    * @param  aListener
    *         The InstallListener to add
    */
-  addInstallListener: function AMI_addInstallListener(aListener) {
+  addInstallListener: function(aListener) {
     if (!aListener || typeof aListener != "object")
       throw Components.Exception("aListener must be a InstallListener object",
                                  Cr.NS_ERROR_INVALID_ARG);
 
-    if (!this.installListeners.some(function addInstallListener_matchListener(i) {
+    if (!this.installListeners.some(function(i) {
       return i == aListener; }))
       this.installListeners.push(aListener);
   },
 
   /**
    * Removes an InstallListener if the listener is registered.
    *
    * @param  aListener
    *         The InstallListener to remove
    */
-  removeInstallListener: function AMI_removeInstallListener(aListener) {
+  removeInstallListener: function(aListener) {
     if (!aListener || typeof aListener != "object")
       throw Components.Exception("aListener must be a InstallListener object",
                                  Cr.NS_ERROR_INVALID_ARG);
 
     let pos = 0;
     while (pos < this.installListeners.length) {
       if (this.installListeners[pos] == aListener)
         this.installListeners.splice(pos, 1);
@@ -2318,17 +2305,17 @@ var AddonManagerInternal = {
 
   /**
    * Starts installation of a temporary add-on from a local directory.
    * @param  aDirectory
    *         The directory of the add-on to be temporarily installed
    * @return a Promise that rejects if the add-on is not restartless
    *         or an add-on with the same ID is already temporarily installed
    */
-  installTemporaryAddon: function AMI_installTemporaryAddon(aFile) {
+  installTemporaryAddon: function(aFile) {
     if (!gStarted)
       throw Components.Exception("AddonManager is not initialized",
                                  Cr.NS_ERROR_NOT_INITIALIZED);
 
     if (!(aFile instanceof Ci.nsIFile))
       throw Components.Exception("aFile must be a nsIFile",
                                  Cr.NS_ERROR_INVALID_ARG);
 
@@ -2352,17 +2339,17 @@ var AddonManagerInternal = {
    *         list of icon size and icon URL, or an object having an iconURL
    *         and icon64URL property.
    * @param  aSize
    *         Ideal icon size in pixels
    * @param  aWindow
    *         Optional window object for determining the correct scale.
    * @return {String} The absolute URL of the icon or null if the addon doesn't have icons
    */
-  getPreferredIconURL: function AMI_getPreferredIconURL(aAddon, aSize, aWindow = undefined) {
+  getPreferredIconURL: function(aAddon, aSize, aWindow = undefined) {
     if (aWindow && aWindow.devicePixelRatio) {
       aSize *= aWindow.devicePixelRatio;
     }
 
     let icons = aAddon.icons;
 
     // certain addon-types only have iconURLs
     if (!icons) {
@@ -2416,17 +2403,17 @@ var AddonManagerInternal = {
    *
    * @param  aID
    *         The ID of the add-on to retrieve
    * @return {Promise}
    * @resolves The found Addon or null if no such add-on exists.
    * @rejects  Never
    * @throws if the aID argument is not specified
    */
-  getAddonByID: function AMI_getAddonByID(aID) {
+  getAddonByID: function(aID) {
     if (!gStarted)
       throw Components.Exception("AddonManager is not initialized",
                                  Cr.NS_ERROR_NOT_INITIALIZED);
 
     if (!aID || typeof aID != "string")
       throw Components.Exception("aID must be a non-empty string",
                                  Cr.NS_ERROR_INVALID_ARG);
 
@@ -2440,58 +2427,58 @@ var AddonManagerInternal = {
    * Asynchronously get an add-on with a specific Sync GUID.
    *
    * @param  aGUID
    *         String GUID of add-on to retrieve
    * @param  aCallback
    *         The callback to pass the retrieved add-on to.
    * @throws if the aGUID or aCallback arguments are not specified
    */
-  getAddonBySyncGUID: function AMI_getAddonBySyncGUID(aGUID, aCallback) {
+  getAddonBySyncGUID: function(aGUID, aCallback) {
     if (!gStarted)
       throw Components.Exception("AddonManager is not initialized",
                                  Cr.NS_ERROR_NOT_INITIALIZED);
 
     if (!aGUID || typeof aGUID != "string")
       throw Components.Exception("aGUID must be a non-empty string",
                                  Cr.NS_ERROR_INVALID_ARG);
 
     if (typeof aCallback != "function")
       throw Components.Exception("aCallback must be a function",
                                  Cr.NS_ERROR_INVALID_ARG);
 
     new AsyncObjectCaller(this.providers, "getAddonBySyncGUID", {
-      nextObject: function getAddonBySyncGUID_nextObject(aCaller, aProvider) {
+      nextObject: function(aCaller, aProvider) {
         callProviderAsync(aProvider, "getAddonBySyncGUID", aGUID,
-                          function getAddonBySyncGUID_safeCall(aAddon) {
+                          function(aAddon) {
           if (aAddon) {
             safeCall(aCallback, aAddon);
           } else {
             aCaller.callNext();
           }
         });
       },
 
-      noMoreObjects: function getAddonBySyncGUID_noMoreObjects(aCaller) {
+      noMoreObjects: function(aCaller) {
         safeCall(aCallback, null);
       }
     });
   },
 
   /**
    * Asynchronously gets an array of add-ons.
    *
    * @param  aIDs
    *         The array of IDs to retrieve
    * @return {Promise}
    * @resolves The array of found add-ons.
    * @rejects  Never
    * @throws if the aIDs argument is not specified
    */
-  getAddonsByIDs: function AMI_getAddonsByIDs(aIDs) {
+  getAddonsByIDs: function(aIDs) {
     if (!gStarted)
       throw Components.Exception("AddonManager is not initialized",
                                  Cr.NS_ERROR_NOT_INITIALIZED);
 
     if (!Array.isArray(aIDs))
       throw Components.Exception("aIDs must be an array",
                                  Cr.NS_ERROR_INVALID_ARG);
 
@@ -2503,55 +2490,55 @@ var AddonManagerInternal = {
    * Asynchronously gets add-ons of specific types.
    *
    * @param  aTypes
    *         An optional array of types to retrieve. Each type is a string name
    * @param  aCallback
    *         The callback to pass an array of Addons to.
    * @throws if the aCallback argument is not specified
    */
-  getAddonsByTypes: function AMI_getAddonsByTypes(aTypes, aCallback) {
+  getAddonsByTypes: function(aTypes, aCallback) {
     if (!gStarted)
       throw Components.Exception("AddonManager is not initialized",
                                  Cr.NS_ERROR_NOT_INITIALIZED);
 
     if (aTypes && !Array.isArray(aTypes))
       throw Components.Exception("aTypes must be an array or null",
                                  Cr.NS_ERROR_INVALID_ARG);
 
     if (typeof aCallback != "function")
       throw Components.Exception("aCallback must be a function",
                                  Cr.NS_ERROR_INVALID_ARG);
 
     let addons = [];
 
     new AsyncObjectCaller(this.providers, "getAddonsByTypes", {
-      nextObject: function getAddonsByTypes_nextObject(aCaller, aProvider) {
+      nextObject: function(aCaller, aProvider) {
         callProviderAsync(aProvider, "getAddonsByTypes", aTypes,
-                          function getAddonsByTypes_concatAddons(aProviderAddons) {
+                          function(aProviderAddons) {
           if (aProviderAddons) {
             addons = addons.concat(aProviderAddons);
           }
           aCaller.callNext();
         });
       },
 
-      noMoreObjects: function getAddonsByTypes_noMoreObjects(aCaller) {
+      noMoreObjects: function(aCaller) {
         safeCall(aCallback, addons);
       }
     });
   },
 
   /**
    * Asynchronously gets all installed add-ons.
    *
    * @param  aCallback
    *         A callback which will be passed an array of Addons
    */
-  getAllAddons: function AMI_getAllAddons(aCallback) {
+  getAllAddons: function(aCallback) {
     if (!gStarted)
       throw Components.Exception("AddonManager is not initialized",
                                  Cr.NS_ERROR_NOT_INITIALIZED);
 
     if (typeof aCallback != "function")
       throw Components.Exception("aCallback must be a function",
                                  Cr.NS_ERROR_INVALID_ARG);
 
@@ -2563,18 +2550,17 @@ var AddonManagerInternal = {
    * restart to complete.
    *
    * @param  aTypes
    *         An optional array of types to retrieve. Each type is a string name
    * @param  aCallback
    *         The callback to pass the array of Addons to
    * @throws if the aCallback argument is not specified
    */
-  getAddonsWithOperationsByTypes:
-  function AMI_getAddonsWithOperationsByTypes(aTypes, aCallback) {
+  getAddonsWithOperationsByTypes: function(aTypes, aCallback) {
     if (!gStarted)
       throw Components.Exception("AddonManager is not initialized",
                                  Cr.NS_ERROR_NOT_INITIALIZED);
 
     if (aTypes && !Array.isArray(aTypes))
       throw Components.Exception("aTypes must be an array or null",
                                  Cr.NS_ERROR_INVALID_ARG);
 
@@ -2592,45 +2578,44 @@ var AddonManagerInternal = {
                                    (aProviderAddons) {
           if (aProviderAddons) {
             addons = addons.concat(aProviderAddons);
           }
           aCaller.callNext();
         });
       },
 
-      noMoreObjects: function getAddonsWithOperationsByTypes_noMoreObjects(caller) {
+      noMoreObjects: function(caller) {
         safeCall(aCallback, addons);
       }
     });
   },
 
   /**
    * Adds a new AddonManagerListener if the listener is not already registered.
    *
    * @param  aListener
    *         The listener to add
    */
-  addManagerListener: function AMI_addManagerListener(aListener) {
+  addManagerListener: function(aListener) {
     if (!aListener || typeof aListener != "object")
       throw Components.Exception("aListener must be an AddonManagerListener object",
                                  Cr.NS_ERROR_INVALID_ARG);
 
-    if (!this.managerListeners.some(function addManagerListener_matchListener(i) {
-      return i == aListener; }))
+    if (!this.managerListeners.some(i => i == aListener))
       this.managerListeners.push(aListener);
   },
 
   /**
    * Removes an AddonManagerListener if the listener is registered.
    *
    * @param  aListener
    *         The listener to remove
    */
-  removeManagerListener: function AMI_removeManagerListener(aListener) {
+  removeManagerListener: function(aListener) {
     if (!aListener || typeof aListener != "object")
       throw Components.Exception("aListener must be an AddonManagerListener object",
                                  Cr.NS_ERROR_INVALID_ARG);
 
     let pos = 0;
     while (pos < this.managerListeners.length) {
       if (this.managerListeners[pos] == aListener)
         this.managerListeners.splice(pos, 1);
@@ -2640,33 +2625,32 @@ var AddonManagerInternal = {
   },
 
   /**
    * Adds a new AddonListener if the listener is not already registered.
    *
    * @param  aListener
    *         The AddonListener to add
    */
-  addAddonListener: function AMI_addAddonListener(aListener) {
+  addAddonListener: function(aListener) {
     if (!aListener || typeof aListener != "object")
       throw Components.Exception("aListener must be an AddonListener object",
                                  Cr.NS_ERROR_INVALID_ARG);
 
-    if (!this.addonListeners.some(function addAddonListener_matchListener(i) {
-      return i == aListener; }))
+    if (!this.addonListeners.some(i => i == aListener))
       this.addonListeners.push(aListener);
   },
 
   /**
    * Removes an AddonListener if the listener is registered.
    *
    * @param  aListener
    *         The AddonListener to remove
    */
-  removeAddonListener: function AMI_removeAddonListener(aListener) {
+  removeAddonListener: function(aListener) {
     if (!aListener || typeof aListener != "object")
       throw Components.Exception("aListener must be an AddonListener object",
                                  Cr.NS_ERROR_INVALID_ARG);
 
     let pos = 0;
     while (pos < this.addonListeners.length) {
       if (this.addonListeners[pos] == aListener)
         this.addonListeners.splice(pos, 1);
@@ -2676,33 +2660,32 @@ var AddonManagerInternal = {
   },
 
   /**
    * Adds a new TypeListener if the listener is not already registered.
    *
    * @param  aListener
    *         The TypeListener to add
    */
-  addTypeListener: function AMI_addTypeListener(aListener) {
+  addTypeListener: function(aListener) {
     if (!aListener || typeof aListener != "object")
       throw Components.Exception("aListener must be a TypeListener object",
                                  Cr.NS_ERROR_INVALID_ARG);
 
-    if (!this.typeListeners.some(function addTypeListener_matchListener(i) {
-      return i == aListener; }))
+    if (!this.typeListeners.some(i => i == aListener))
       this.typeListeners.push(aListener);
   },
 
   /**
    * Removes an TypeListener if the listener is registered.
    *
    * @param  aListener
    *         The TypeListener to remove
    */
-  removeTypeListener: function AMI_removeTypeListener(aListener) {
+  removeTypeListener: function(aListener) {
     if (!aListener || typeof aListener != "object")
       throw Components.Exception("aListener must be a TypeListener object",
                                  Cr.NS_ERROR_INVALID_ARG);
 
     let pos = 0;
     while (pos < this.typeListeners.length) {
       if (this.typeListeners[pos] == aListener)
         this.typeListeners.splice(pos, 1);
@@ -2789,33 +2772,33 @@ var AddonManagerInternal = {
 
 /**
  * Should not be used outside of core Mozilla code. This is a private API for
  * the startup and platform integration code to use. Refer to the methods on
  * AddonManagerInternal for documentation however note that these methods are
  * subject to change at any time.
  */
 this.AddonManagerPrivate = {
-  startup: function AMP_startup() {
+  startup: function() {
     AddonManagerInternal.startup();
   },
 
-  registerProvider: function AMP_registerProvider(aProvider, aTypes) {
+  registerProvider: function(aProvider, aTypes) {
     AddonManagerInternal.registerProvider(aProvider, aTypes);
   },
 
-  unregisterProvider: function AMP_unregisterProvider(aProvider) {
+  unregisterProvider: function(aProvider) {
     AddonManagerInternal.unregisterProvider(aProvider);
   },
 
-  markProviderSafe: function AMP_markProviderSafe(aProvider) {
+  markProviderSafe: function(aProvider) {
     AddonManagerInternal.markProviderSafe(aProvider);
   },
 
-  backgroundUpdateCheck: function AMP_backgroundUpdateCheck() {
+  backgroundUpdateCheck: function() {
     return AddonManagerInternal.backgroundUpdateCheck();
   },
 
   backgroundUpdateTimerHandler() {
     // Don't call through to the real update check if no checks are enabled.
     let checkHotfix = AddonManagerInternal.hotfixID &&
                       Services.prefs.getBoolPref(PREF_APP_UPDATE_ENABLED) &&
                       Services.prefs.getBoolPref(PREF_APP_UPDATE_AUTO);
@@ -2823,63 +2806,63 @@ this.AddonManagerPrivate = {
     if (!AddonManagerInternal.updateEnabled && !checkHotfix) {
       logger.info("Skipping background update check");
       return;
     }
     // Don't return the promise here, since the caller doesn't care.
     AddonManagerInternal.backgroundUpdateCheck();
   },
 
-  addStartupChange: function AMP_addStartupChange(aType, aID) {
+  addStartupChange: function(aType, aID) {
     AddonManagerInternal.addStartupChange(aType, aID);
   },
 
-  removeStartupChange: function AMP_removeStartupChange(aType, aID) {
+  removeStartupChange: function(aType, aID) {
     AddonManagerInternal.removeStartupChange(aType, aID);
   },
 
-  notifyAddonChanged: function AMP_notifyAddonChanged(aID, aType, aPendingRestart) {
+  notifyAddonChanged: function(aID, aType, aPendingRestart) {
     AddonManagerInternal.notifyAddonChanged(aID, aType, aPendingRestart);
   },
 
-  updateAddonAppDisabledStates: function AMP_updateAddonAppDisabledStates() {
+  updateAddonAppDisabledStates: function() {
     AddonManagerInternal.updateAddonAppDisabledStates();
   },
 
-  updateAddonRepositoryData: function AMP_updateAddonRepositoryData(aCallback) {
+  updateAddonRepositoryData: function(aCallback) {
     AddonManagerInternal.updateAddonRepositoryData(aCallback);
   },
 
-  callInstallListeners: function AMP_callInstallListeners(...aArgs) {
+  callInstallListeners: function(...aArgs) {
     return AddonManagerInternal.callInstallListeners.apply(AddonManagerInternal,
                                                            aArgs);
   },
 
-  callAddonListeners: function AMP_callAddonListeners(...aArgs) {
+  callAddonListeners: function(...aArgs) {
     AddonManagerInternal.callAddonListeners.apply(AddonManagerInternal, aArgs);
   },
 
   AddonAuthor: AddonAuthor,
 
   AddonScreenshot: AddonScreenshot,
 
   AddonCompatibilityOverride: AddonCompatibilityOverride,
 
   AddonType: AddonType,
 
-  recordTimestamp: function AMP_recordTimestamp(name, value) {
+  recordTimestamp: function(name, value) {
     AddonManagerInternal.recordTimestamp(name, value);
   },
 
   _simpleMeasures: {},
-  recordSimpleMeasure: function AMP_recordSimpleMeasure(name, value) {
+  recordSimpleMeasure: function(name, value) {
     this._simpleMeasures[name] = value;
   },
 
-  recordException: function AMP_recordException(aModule, aContext, aException) {
+  recordException: function(aModule, aContext, aException) {
     let report = {
       module: aModule,
       context: aContext
     };
 
     if (typeof aException == "number") {
       report.message = Components.Exception("", aException).name;
     }
@@ -2889,25 +2872,25 @@ this.AddonManagerPrivate = {
         report.file = aException.fileName;
         report.line = aException.lineNumber;
       }
     }
 
     this._simpleMeasures.exception = report;
   },
 
-  getSimpleMeasures: function AMP_getSimpleMeasures() {
+  getSimpleMeasures: function() {
     return this._simpleMeasures;
   },
 
-  getTelemetryDetails: function AMP_getTelemetryDetails() {
+  getTelemetryDetails: function() {
     return AddonManagerInternal.telemetryDetails;
   },
 
-  setTelemetryDetails: function AMP_setTelemetryDetails(aProvider, aDetails) {
+  setTelemetryDetails: function(aProvider, aDetails) {
     AddonManagerInternal.telemetryDetails[aProvider] = aDetails;
   },
 
   // Start a timer, record a simple measure of the time interval when
   // timer.done() is called
   simpleTimer: function(aName) {
     let startTime = Cu.now();
     return {
@@ -2916,17 +2899,17 @@ this.AddonManagerPrivate = {
   },
 
   /**
    * Helper to call update listeners when no update is available.
    *
    * This can be used as an implementation for Addon.findUpdates() when
    * no update mechanism is available.
    */
-  callNoUpdateListeners: function (addon, listener, reason, appVersion, platformVersion) {
+  callNoUpdateListeners: function(addon, listener, reason, appVersion, platformVersion) {
     if ("onNoCompatibilityUpdateAvailable" in listener) {
       safeCall(listener.onNoCompatibilityUpdateAvailable.bind(listener), addon);
     }
     if ("onNoUpdateAvailable" in listener) {
       safeCall(listener.onNoUpdateAvailable.bind(listener), addon);
     }
     if ("onUpdateFinished" in listener) {
       safeCall(listener.onUpdateFinished.bind(listener), addon);
@@ -3133,163 +3116,160 @@ this.AddonManager = {
   SIGNEDSTATE_SYSTEM: 3,
 
   // Constants for the Addon.userDisabled property
   // Indicates that the userDisabled state of this add-on is currently
   // ask-to-activate. That is, it can be conditionally enabled on a
   // case-by-case basis.
   STATE_ASK_TO_ACTIVATE: "askToActivate",
 
-#ifdef MOZ_EM_DEBUG
   get __AddonManagerInternal__() {
-    return AddonManagerInternal;
+    return AppConstants.DEBUG ? AddonManagerInternal : undefined;
   },
-#endif
 
   get isReady() {
     return gStartupComplete && !gShutdownInProgress;
   },
 
-  getInstallForURL: function AM_getInstallForURL(aUrl, aCallback, aMimetype,
+  getInstallForURL: function(aUrl, aCallback, aMimetype,
                                                  aHash, aName, aIcons,
                                                  aVersion, aBrowser) {
     AddonManagerInternal.getInstallForURL(aUrl, aCallback, aMimetype, aHash,
                                           aName, aIcons, aVersion, aBrowser);
   },
 
-  getInstallForFile: function AM_getInstallForFile(aFile, aCallback, aMimetype) {
+  getInstallForFile: function(aFile, aCallback, aMimetype) {
     AddonManagerInternal.getInstallForFile(aFile, aCallback, aMimetype);
   },
 
   /**
    * Gets an array of add-on IDs that changed during the most recent startup.
    *
    * @param  aType
    *         The type of startup change to get
    * @return An array of add-on IDs
    */
-  getStartupChanges: function AM_getStartupChanges(aType) {
+  getStartupChanges: function(aType) {
     if (!(aType in AddonManagerInternal.startupChanges))
       return [];
     return AddonManagerInternal.startupChanges[aType].slice(0);
   },
 
-  getAddonByID: function AM_getAddonByID(aID, aCallback) {
+  getAddonByID: function(aID, aCallback) {
     if (typeof aCallback != "function")
       throw Components.Exception("aCallback must be a function",
                                  Cr.NS_ERROR_INVALID_ARG);
 
     AddonManagerInternal.getAddonByID(aID)
                         .then(makeSafe(aCallback))
                         .catch(logger.error);
   },
 
-  getAddonBySyncGUID: function AM_getAddonBySyncGUID(aGUID, aCallback) {
+  getAddonBySyncGUID: function(aGUID, aCallback) {
     AddonManagerInternal.getAddonBySyncGUID(aGUID, aCallback);
   },
 
-  getAddonsByIDs: function AM_getAddonsByIDs(aIDs, aCallback) {
+  getAddonsByIDs: function(aIDs, aCallback) {
     if (typeof aCallback != "function")
       throw Components.Exception("aCallback must be a function",
                                  Cr.NS_ERROR_INVALID_ARG);
 
     AddonManagerInternal.getAddonsByIDs(aIDs)
                         .then(makeSafe(aCallback))
                         .catch(logger.error);
   },
 
-  getAddonsWithOperationsByTypes:
-  function AM_getAddonsWithOperationsByTypes(aTypes, aCallback) {
+  getAddonsWithOperationsByTypes: function(aTypes, aCallback) {
     AddonManagerInternal.getAddonsWithOperationsByTypes(aTypes, aCallback);
   },
 
-  getAddonsByTypes: function AM_getAddonsByTypes(aTypes, aCallback) {
+  getAddonsByTypes: function(aTypes, aCallback) {
     AddonManagerInternal.getAddonsByTypes(aTypes, aCallback);
   },
 
-  getAllAddons: function AM_getAllAddons(aCallback) {
+  getAllAddons: function(aCallback) {
     AddonManagerInternal.getAllAddons(aCallback);
   },
 
-  getInstallsByTypes: function AM_getInstallsByTypes(aTypes, aCallback) {
+  getInstallsByTypes: function(aTypes, aCallback) {
     AddonManagerInternal.getInstallsByTypes(aTypes, aCallback);
   },
 
-  getAllInstalls: function AM_getAllInstalls(aCallback) {
+  getAllInstalls: function(aCallback) {
     AddonManagerInternal.getAllInstalls(aCallback);
   },
 
-  mapURIToAddonID: function AM_mapURIToAddonID(aURI) {
+  mapURIToAddonID: function(aURI) {
     return AddonManagerInternal.mapURIToAddonID(aURI);
   },
 
-  isInstallEnabled: function AM_isInstallEnabled(aType) {
+  isInstallEnabled: function(aType) {
     return AddonManagerInternal.isInstallEnabled(aType);
   },
 
-  isInstallAllowed: function AM_isInstallAllowed(aType, aInstallingPrincipal) {
+  isInstallAllowed: function(aType, aInstallingPrincipal) {
     return AddonManagerInternal.isInstallAllowed(aType, ensurePrincipal(aInstallingPrincipal));
   },
 
-  installAddonsFromWebpage: function AM_installAddonsFromWebpage(aType, aBrowser,
+  installAddonsFromWebpage: function(aType, aBrowser,
                                                                  aInstallingPrincipal,
                                                                  aInstalls) {
     AddonManagerInternal.installAddonsFromWebpage(aType, aBrowser,
                                                   ensurePrincipal(aInstallingPrincipal),
                                                   aInstalls);
   },
 
-  installTemporaryAddon: function AM_installTemporaryAddon(aDirectory) {
+  installTemporaryAddon: function(aDirectory) {
     return AddonManagerInternal.installTemporaryAddon(aDirectory);
   },
 
-  addManagerListener: function AM_addManagerListener(aListener) {
+  addManagerListener: function(aListener) {
     AddonManagerInternal.addManagerListener(aListener);
   },
 
-  removeManagerListener: function AM_removeManagerListener(aListener) {
+  removeManagerListener: function(aListener) {
     AddonManagerInternal.removeManagerListener(aListener);
   },
 
-  addInstallListener: function AM_addInstallListener(aListener) {
+  addInstallListener: function(aListener) {
     AddonManagerInternal.addInstallListener(aListener);
   },
 
-  removeInstallListener: function AM_removeInstallListener(aListener) {
+  removeInstallListener: function(aListener) {
     AddonManagerInternal.removeInstallListener(aListener);
   },
 
-  addAddonListener: function AM_addAddonListener(aListener) {
+  addAddonListener: function(aListener) {
     AddonManagerInternal.addAddonListener(aListener);
   },
 
-  removeAddonListener: function AM_removeAddonListener(aListener) {
+  removeAddonListener: function(aListener) {
     AddonManagerInternal.removeAddonListener(aListener);
   },
 
-  addTypeListener: function AM_addTypeListener(aListener) {
+  addTypeListener: function(aListener) {
     AddonManagerInternal.addTypeListener(aListener);
   },
 
-  removeTypeListener: function AM_removeTypeListener(aListener) {
+  removeTypeListener: function(aListener) {
     AddonManagerInternal.removeTypeListener(aListener);
   },
 
   get addonTypes() {
     return AddonManagerInternal.addonTypes;
   },
 
   /**
    * Determines whether an Addon should auto-update or not.
    *
    * @param  aAddon
    *         The Addon representing the add-on
    * @return true if the addon should auto-update, false otherwise.
    */
-  shouldAutoUpdate: function AM_shouldAutoUpdate(aAddon) {
+  shouldAutoUpdate: function(aAddon) {
     if (!aAddon || typeof aAddon != "object")
       throw Components.Exception("aAddon must be specified",
                                  Cr.NS_ERROR_INVALID_ARG);
 
     if (!("applyBackgroundUpdates" in aAddon))
       return false;
     if (aAddon.applyBackgroundUpdates == AddonManager.AUTOUPDATE_ENABLE)
       return true;
@@ -3341,21 +3321,21 @@ this.AddonManager = {
   set autoUpdateDefault(aValue) {
     AddonManagerInternal.autoUpdateDefault = aValue;
   },
 
   get hotfixID() {
     return AddonManagerInternal.hotfixID;
   },
 
-  escapeAddonURI: function AM_escapeAddonURI(aAddon, aUri, aAppVersion) {
+  escapeAddonURI: function(aAddon, aUri, aAppVersion) {
     return AddonManagerInternal.escapeAddonURI(aAddon, aUri, aAppVersion);
   },
 
-  getPreferredIconURL: function AM_getPreferredIconURL(aAddon, aSize, aWindow = undefined) {
+  getPreferredIconURL: function(aAddon, aSize, aWindow = undefined) {
     return AddonManagerInternal.getPreferredIconURL(aAddon, aSize, aWindow);
   },
 
   get shutdown() {
     return gShutdownBarrier.client;
   },
 };
 
--- a/toolkit/mozapps/extensions/ChromeManifestParser.jsm
+++ b/toolkit/mozapps/extensions/ChromeManifestParser.jsm
@@ -40,17 +40,17 @@ this.ChromeManifestParser = {
    * secondary manifests it references.
    *
    * @param  aURI
    *         A nsIURI pointing to a chrome manifest.
    *         Typically a file: or jar: URI.
    * @return Array of objects describing each manifest instruction, in the form:
    *         { type: instruction-type, baseURI: string-uri, args: [arguments] }
    **/
-  parseSync: function CMP_parseSync(aURI) {
+  parseSync: function(aURI) {
     function parseLine(aLine) {
       let line = aLine.trim();
       if (line.length == 0 || line.charAt(0) == '#')
         return;
       let tokens = line.split(/\s+/);
       let type = tokens.shift();
       if (type == "manifest") {
         let uri = NetUtil.newURI(tokens.shift(), null, aURI);
@@ -76,17 +76,17 @@ this.ChromeManifestParser = {
     let baseURI = NetUtil.newURI(".", null, aURI).spec;
 
     let data = [];
     let lines = contents.split("\n");
     lines.forEach(parseLine.bind(this));
     return data;
   },
   
-  _readFromJar: function CMP_readFromJar(aURI) {
+  _readFromJar: function(aURI) {
     let data = "";
     let entries = [];
     let readers = [];
     
     try {
       // Deconstrict URI, which can be nested jar: URIs. 
       let uri = aURI.clone();
       while (uri instanceof Ci.nsIJARURI) {
@@ -119,17 +119,17 @@ this.ChromeManifestParser = {
         readers[i].close();
         flushJarCache(readers[i].file);
       }
     }
     
     return data;
   },
   
-  _readFromFile: function CMP_readFromFile(aURI) {
+  _readFromFile: function(aURI) {
     let file = aURI.QueryInterface(Ci.nsIFileURL).file;
     if (!file.exists() || !file.isFile())
       return "";
     
     let data = "";
     let fis = Cc["@mozilla.org/network/file-input-stream;1"].
               createInstance(Ci.nsIFileInputStream);
     try {
@@ -146,14 +146,12 @@ this.ChromeManifestParser = {
   * chrome manifest.
   *
   * @param  aManifest
   *         Manifest data, as returned by ChromeManifestParser.parseSync().
   * @param  aType
   *         Instruction type to filter by.
   * @return True if any matching instructions were found in the manifest.
   */
-  hasType: function CMP_hasType(aManifest, aType) {
-    return aManifest.some(function hasType_matchEntryType(aEntry) {
-      return aEntry.type == aType;
-    });
+  hasType: function(aManifest, aType) {
+    return aManifest.some(entry => entry.type == aType);
   }
 };
--- a/toolkit/mozapps/extensions/DeferredSave.jsm
+++ b/toolkit/mozapps/extensions/DeferredSave.jsm
@@ -46,23 +46,23 @@ const PREF_LOGGING_ENABLED = "extensions
 const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed";
 
 /**
 * Preference listener which listens for a change in the
 * "extensions.logging.enabled" preference and changes the logging level of the
 * parent 'addons' level logger accordingly.
 */
 var PrefObserver = {
- init: function PrefObserver_init() {
+ init: function() {
    Services.prefs.addObserver(PREF_LOGGING_ENABLED, this, false);
    Services.obs.addObserver(this, "xpcom-shutdown", false);
    this.observe(null, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, PREF_LOGGING_ENABLED);
  },
 
- observe: function PrefObserver_observe(aSubject, aTopic, aData) {
+ observe: function(aSubject, aTopic, aData) {
    if (aTopic == "xpcom-shutdown") {
      Services.prefs.removeObserver(PREF_LOGGING_ENABLED, this);
      Services.obs.removeObserver(this, "xpcom-shutdown");
    }
    else if (aTopic == NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) {
      let debugLogEnabled = false;
      try {
        debugLogEnabled = Services.prefs.getBoolPref(PREF_LOGGING_ENABLED);
@@ -98,17 +98,17 @@ PrefObserver.init();
  *        bytes it contains are written to the file as is.
  *        If aDataProvider returns a String the data are UTF-8 encoded
  *        and then written to the file.
  * @param [optional] aDelay
  *        The delay in milliseconds between the first saveChanges() call
  *        that marks the data as needing to be saved, and when the DeferredSave
  *        begins writing the data to disk. Default 50 milliseconds.
  */
-this.DeferredSave = function (aPath, aDataProvider, aDelay) {
+this.DeferredSave = function(aPath, aDataProvider, aDelay) {
   // Create a new logger (child of 'DeferredSave' logger)
   // for use by this particular instance of DeferredSave object
   let leafName = OS.Path.basename(aPath);
   let logger_id = DEFERREDSAVE_PARENT_LOGGER_ID + "." + leafName;
   this.logger = Log.repository.getLogger(logger_id);
 
   // @type {Deferred|null}, null when no data needs to be written
   // @resolves with the result of OS.File.writeAtomic when all writes complete
--- a/toolkit/mozapps/extensions/LightweightThemeManager.jsm
+++ b/toolkit/mozapps/extensions/LightweightThemeManager.jsm
@@ -37,47 +37,49 @@ const PERSIST_BYPASS_CACHE = false;
 const PERSIST_FILES = {
   headerURL: "lightweighttheme-header",
   footerURL: "lightweighttheme-footer"
 };
 
 XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeImageOptimizer",
   "resource://gre/modules/addons/LightweightThemeImageOptimizer.jsm");
 
-this.__defineGetter__("_prefs", function prefsGetter() {
-  delete this._prefs;
-  return this._prefs = Services.prefs.getBranch("lightweightThemes.");
+XPCOMUtils.defineLazyGetter(this, "_prefs", () => {
+  return Services.prefs.getBranch("lightweightThemes.");
 });
 
-this.__defineGetter__("_maxUsedThemes", function maxUsedThemesGetter() {
-  delete this._maxUsedThemes;
-  try {
-    this._maxUsedThemes = _prefs.getIntPref("maxUsedThemes");
-  }
-  catch (e) {
-    this._maxUsedThemes = DEFAULT_MAX_USED_THEMES_COUNT;
-  }
-  return this._maxUsedThemes;
-});
+Object.defineProperty(this, "_maxUsedThemes", {
+  get: function() {
+    delete this._maxUsedThemes;
+    try {
+      this._maxUsedThemes = _prefs.getIntPref("maxUsedThemes");
+    }
+    catch (e) {
+      this._maxUsedThemes = DEFAULT_MAX_USED_THEMES_COUNT;
+    }
+    return this._maxUsedThemes;
+  },
 
-this.__defineSetter__("_maxUsedThemes", function maxUsedThemesSetter(aVal) {
-  delete this._maxUsedThemes;
-  return this._maxUsedThemes = aVal;
+  set: function(val) {
+    delete this._maxUsedThemes;
+    return this._maxUsedThemes = val;
+  },
+  configurable: true,
 });
 
 // Holds the ID of the theme being enabled or disabled while sending out the
 // events so cached AddonWrapper instances can return correct values for
 // permissions and pendingOperations
 var _themeIDBeingEnabled = null;
 var _themeIDBeingDisabled = null;
 
 // Convert from the old storage format (in which the order of usedThemes
 // was combined with isThemeSelected to determine which theme was selected)
 // to the new one (where a selectedThemeID determines which theme is selected).
-(function migrateToNewStorageFormat() {
+(function() {
   let wasThemeSelected = false;
   try {
     wasThemeSelected = _prefs.getBoolPref("isThemeSelected");
   } catch(e) { }
 
   if (wasThemeSelected) {
     _prefs.clearUserPref("isThemeSelected");
     let themes = [];
@@ -140,30 +142,30 @@ this.LightweightThemeManager = {
 
     return data;
   },
 
   set currentTheme (aData) {
     return _setCurrentTheme(aData, false);
   },
 
-  setLocalTheme: function LightweightThemeManager_setLocalTheme(aData) {
+  setLocalTheme: function(aData) {
     _setCurrentTheme(aData, true);
   },
 
-  getUsedTheme: function LightweightThemeManager_getUsedTheme(aId) {
+  getUsedTheme: function(aId) {
     var usedThemes = this.usedThemes;
     for (let usedTheme of usedThemes) {
       if (usedTheme.id == aId)
         return usedTheme;
     }
     return null;
   },
 
-  forgetUsedTheme: function LightweightThemeManager_forgetUsedTheme(aId) {
+  forgetUsedTheme: function(aId) {
     let theme = this.getUsedTheme(aId);
     if (!theme || LightweightThemeManager._builtInThemes.has(theme.id))
       return;
 
     let wrapper = new AddonWrapper(theme);
     AddonManagerPrivate.callAddonListeners("onUninstalling", wrapper, false);
 
     var currentTheme = this.currentTheme;
@@ -171,41 +173,41 @@ this.LightweightThemeManager = {
       this.themeChanged(null);
       AddonManagerPrivate.notifyAddonChanged(null, ADDON_TYPE, false);
     }
 
     _updateUsedThemes(_usedThemesExceptId(aId));
     AddonManagerPrivate.callAddonListeners("onUninstalled", wrapper);
   },
 
-  addBuiltInTheme: function LightweightThemeManager_addBuiltInTheme(theme) {
+  addBuiltInTheme: function(theme) {
     if (!theme || !theme.id || this.usedThemes.some(t => t.id == theme.id)) {
       throw new Error("Trying to add invalid builtIn theme");
     }
 
     this._builtInThemes.set(theme.id, theme);
   },
 
-  forgetBuiltInTheme: function LightweightThemeManager_forgetBuiltInTheme(id) {
+  forgetBuiltInTheme: function(id) {
     if (!this._builtInThemes.has(id)) {
       let currentTheme = this.currentTheme;
       if (currentTheme && currentTheme.id == id) {
         this.currentTheme = null;
       }
     }
     return this._builtInThemes.delete(id);
   },
 
-  clearBuiltInThemes: function LightweightThemeManager_clearBuiltInThemes() {
+  clearBuiltInThemes: function() {
     for (let id of this._builtInThemes.keys()) {
       this.forgetBuiltInTheme(id);
     }
   },
 
-  previewTheme: function LightweightThemeManager_previewTheme(aData) {
+  previewTheme: function(aData) {
     let cancel = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool);
     cancel.data = false;
     Services.obs.notifyObservers(cancel, "lightweight-theme-preview-requested",
                                  JSON.stringify(aData));
     if (cancel.data)
       return;
 
     if (_previewTimer)
@@ -214,33 +216,33 @@ this.LightweightThemeManager = {
       _previewTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
     _previewTimer.initWithCallback(_previewTimerCallback,
                                    MAX_PREVIEW_SECONDS * 1000,
                                    _previewTimer.TYPE_ONE_SHOT);
 
     _notifyWindows(aData);
   },
 
-  resetPreview: function LightweightThemeManager_resetPreview() {
+  resetPreview: function() {
     if (_previewTimer) {
       _previewTimer.cancel();
       _previewTimer = null;
       _notifyWindows(this.currentThemeForDisplay);
     }
   },
 
-  parseTheme: function LightweightThemeManager_parseTheme(aString, aBaseURI) {
+  parseTheme: function(aString, aBaseURI) {
     try {
       return _sanitizeTheme(JSON.parse(aString), aBaseURI, false);
     } catch (e) {
       return null;
     }
   },
 
-  updateCurrentTheme: function LightweightThemeManager_updateCurrentTheme() {
+  updateCurrentTheme: function() {
     try {
       if (!_prefs.getBoolPref("update.enabled"))
         return;
     } catch (e) {
       return;
     }
 
     var theme = this.currentTheme;
@@ -253,54 +255,53 @@ this.LightweightThemeManager = {
     req.mozBackgroundRequest = true;
     req.overrideMimeType("text/plain");
     req.open("GET", theme.updateURL, true);
     // Prevent the request from reading from the cache.
     req.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
     // Prevent the request from writing to the cache.
     req.channel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
 
-    var self = this;
-    req.addEventListener("load", function loadEventListener() {
+    req.addEventListener("load", () => {
       if (req.status != 200)
         return;
 
-      let newData = self.parseTheme(req.responseText, theme.updateURL);
+      let newData = this.parseTheme(req.responseText, theme.updateURL);
       if (!newData ||
           newData.id != theme.id ||
           _version(newData) == _version(theme))
         return;
 
-      var currentTheme = self.currentTheme;
+      var currentTheme = this.currentTheme;
       if (currentTheme && currentTheme.id == theme.id)
-        self.currentTheme = newData;
+        this.currentTheme = newData;
     }, false);
 
     req.send(null);
   },
 
   /**
    * Switches to a new lightweight theme.
    *
    * @param  aData
    *         The lightweight theme to switch to
    */
-  themeChanged: function LightweightThemeManager_themeChanged(aData) {
+  themeChanged: function(aData) {
     if (_previewTimer) {
       _previewTimer.cancel();
       _previewTimer = null;
     }
 
     if (aData) {
       let usedThemes = _usedThemesExceptId(aData.id);
       usedThemes.unshift(aData);
       _updateUsedThemes(usedThemes);
       if (PERSIST_ENABLED) {
         LightweightThemeImageOptimizer.purge();
-        _persistImages(aData, function themeChanged_persistImages() {
+        _persistImages(aData, function() {
           _notifyWindows(this.currentThemeForDisplay);
         }.bind(this));
       }
     }
 
     if (aData)
       _prefs.setCharPref("selectedThemeID", aData.id);
     else
@@ -309,49 +310,49 @@ this.LightweightThemeManager = {
     _notifyWindows(aData);
     Services.obs.notifyObservers(null, "lightweight-theme-changed", null);
   },
 
   /**
    * Starts the Addons provider and enables the new lightweight theme if
    * necessary.
    */
-  startup: function LightweightThemeManager_startup() {
+  startup: function() {
     if (Services.prefs.prefHasUserValue(PREF_LWTHEME_TO_SELECT)) {
       let id = Services.prefs.getCharPref(PREF_LWTHEME_TO_SELECT);
       if (id)
         this.themeChanged(this.getUsedTheme(id));
       else
         this.themeChanged(null);
       Services.prefs.clearUserPref(PREF_LWTHEME_TO_SELECT);
     }
 
     _prefs.addObserver("", _prefObserver, false);
   },
 
   /**
    * Shuts down the provider.
    */
-  shutdown: function LightweightThemeManager_shutdown() {
+  shutdown: function() {
     _prefs.removeObserver("", _prefObserver);
   },
 
   /**
    * Called when a new add-on has been enabled when only one add-on of that type
    * can be enabled.
    *
    * @param  aId
    *         The ID of the newly enabled add-on
    * @param  aType
    *         The type of the newly enabled add-on
    * @param  aPendingRestart
    *         true if the newly enabled add-on will only become enabled after a
    *         restart
    */
-  addonChanged: function LightweightThemeManager_addonChanged(aId, aType, aPendingRestart) {
+  addonChanged: function(aId, aType, aPendingRestart) {
     if (aType != ADDON_TYPE)
       return;
 
     let id = _getInternalID(aId);
     let current = this.currentTheme;
 
     try {
       let next = Services.prefs.getCharPref(PREF_LWTHEME_TO_SELECT);
@@ -414,17 +415,17 @@ this.LightweightThemeManager = {
   /**
    * Called to get an Addon with a particular ID.
    *
    * @param  aId
    *         The ID of the add-on to retrieve
    * @param  aCallback
    *         A callback to pass the Addon to
    */
-  getAddonByID: function LightweightThemeManager_getAddonByID(aId, aCallback) {
+  getAddonByID: function(aId, aCallback) {
     let id = _getInternalID(aId);
     if (!id) {
       aCallback(null);
       return;
      }
 
     let theme = this.getUsedTheme(id);
     if (!theme) {
@@ -438,158 +439,143 @@ this.LightweightThemeManager = {
   /**
    * Called to get Addons of a particular type.
    *
    * @param  aTypes
    *         An array of types to fetch. Can be null to get all types.
    * @param  aCallback
    *         A callback to pass an array of Addons to
    */
-  getAddonsByTypes: function LightweightThemeManager_getAddonsByTypes(aTypes, aCallback) {
+  getAddonsByTypes: function(aTypes, aCallback) {
     if (aTypes && aTypes.indexOf(ADDON_TYPE) == -1) {
       aCallback([]);
       return;
     }
 
     aCallback(this.usedThemes.map(a => new AddonWrapper(a)));
   },
 };
 
+const wrapperMap = new WeakMap();
+let themeFor = wrapper => wrapperMap.get(wrapper);
+
 /**
  * The AddonWrapper wraps lightweight theme to provide the data visible to
  * consumers of the AddonManager API.
  */
 function AddonWrapper(aTheme) {
-  this.__defineGetter__("id", function AddonWrapper_idGetter() {
-    return aTheme.id + ID_SUFFIX;
-  });
-  this.__defineGetter__("type", function AddonWrapper_typeGetter() {
+  wrapperMap.set(this, aTheme);
+}
+
+AddonWrapper.prototype = {
+  get id() {
+    return themeFor(this).id + ID_SUFFIX;
+  },
+
+  get type() {
     return ADDON_TYPE;
-  });
-  this.__defineGetter__("isActive", function AddonWrapper_isActiveGetter() {
+  },
+
+  get isActive() {
     let current = LightweightThemeManager.currentTheme;
     if (current)
-      return aTheme.id == current.id;
+      return themeFor(this).id == current.id;
     return false;
-  });
+  },
 
-  this.__defineGetter__("name", function AddonWrapper_nameGetter() {
-    return aTheme.name;
-  });
-  this.__defineGetter__("version", function AddonWrapper_versionGetter() {
-    return "version" in aTheme ? aTheme.version : "";
-  });
-
-  ["description", "homepageURL", "iconURL"].forEach(function(prop) {
-    this.__defineGetter__(prop, function AddonWrapper_optionalPropGetter() {
-      return prop in aTheme ? aTheme[prop] : null;
-    });
-  }, this);
+  get name() {
+    return themeFor(this).name;
+  },
 
-  ["installDate", "updateDate"].forEach(function(prop) {
-    this.__defineGetter__(prop, function AddonWrapper_datePropGetter() {
-      return prop in aTheme ? new Date(aTheme[prop]) : null;
-    });
-  }, this);
+  get version() {
+    let theme = themeFor(this);
+    return "version" in theme ? theme.version : "";
+  },
 
-  this.__defineGetter__("creator", function AddonWrapper_creatorGetter() {
-    return "author" in aTheme ? new AddonManagerPrivate.AddonAuthor(aTheme.author) : null;
-  });
+  get creator() {
+    let theme = themeFor(this);
+    return "author" in theme ? new AddonManagerPrivate.AddonAuthor(theme.author) : null;
+  },
 
-  this.__defineGetter__("screenshots", function AddonWrapper_screenshotsGetter() {
-    let url = aTheme.previewURL;
+  get screenshots() {
+    let url = themeFor(this).previewURL;
     return [new AddonManagerPrivate.AddonScreenshot(url)];
-  });
+  },
 
-  this.__defineGetter__("pendingOperations",
-                       function AddonWrapper_pendingOperationsGetter() {
+  get pendingOperations() {
     let pending = AddonManager.PENDING_NONE;
     if (this.isActive == this.userDisabled)
       pending |= this.isActive ? AddonManager.PENDING_DISABLE : AddonManager.PENDING_ENABLE;
     return pending;
-  });
+  },
 
-  this.__defineGetter__("operationsRequiringRestart", 
-               function AddonWrapper_operationsRequiringRestartGetter() {
+  get operationsRequiringRestart() {
     // If a non-default theme is in use then a restart will be required to
     // enable lightweight themes unless dynamic theme switching is enabled
     if (Services.prefs.prefHasUserValue(PREF_GENERAL_SKINS_SELECTEDSKIN)) {
       try {
         if (Services.prefs.getBoolPref(PREF_EM_DSS_ENABLED))
           return AddonManager.OP_NEEDS_RESTART_NONE;
       }
       catch (e) {
       }
       return AddonManager.OP_NEEDS_RESTART_ENABLE;
     }
 
     return AddonManager.OP_NEEDS_RESTART_NONE;
-  });
+  },
 
-  this.__defineGetter__("size", function AddonWrapper_sizeGetter() {
+  get size() {
     // The size changes depending on whether the theme is in use or not, this is
     // probably not worth exposing.
     return null;
-  });
+  },
 
-  this.__defineGetter__("permissions", function AddonWrapper_permissionsGetter() {
+  get permissions() {
     let permissions = 0;
 
     // Do not allow uninstall of builtIn themes.
-    if (!LightweightThemeManager._builtInThemes.has(aTheme.id))
+    if (!LightweightThemeManager._builtInThemes.has(themeFor(this).id))
       permissions = AddonManager.PERM_CAN_UNINSTALL;
     if (this.userDisabled)
       permissions |= AddonManager.PERM_CAN_ENABLE;
     else
       permissions |= AddonManager.PERM_CAN_DISABLE;
     return permissions;
-  });
+  },
 
-  this.__defineGetter__("userDisabled", function AddonWrapper_userDisabledGetter() {
-    if (_themeIDBeingEnabled == aTheme.id)
+  get userDisabled() {
+    let id = themeFor(this).id;
+    if (_themeIDBeingEnabled == id)
       return false;
-    if (_themeIDBeingDisabled == aTheme.id)
+    if (_themeIDBeingDisabled == id)
       return true;
 
     try {
       let toSelect = Services.prefs.getCharPref(PREF_LWTHEME_TO_SELECT);
-      return aTheme.id != toSelect;
+      return id != toSelect;
     }
     catch (e) {
       let current = LightweightThemeManager.currentTheme;
-      return !current || current.id != aTheme.id;
+      return !current || current.id != id;
     }
-  });
+  },
 
-  this.__defineSetter__("userDisabled", function AddonWrapper_userDisabledSetter(val) {
+  set userDisabled(val) {
     if (val == this.userDisabled)
       return val;
 
     if (val)
       LightweightThemeManager.currentTheme = null;
     else
-      LightweightThemeManager.currentTheme = aTheme;
+      LightweightThemeManager.currentTheme = themeFor(this);
 
     return val;
-  });
-
-  this.uninstall = function AddonWrapper_uninstall() {
-    LightweightThemeManager.forgetUsedTheme(aTheme.id);
-  };
+  },
 
-  this.cancelUninstall = function AddonWrapper_cancelUninstall() {
-    throw new Error("Theme is not marked to be uninstalled");
-  };
-
-  this.findUpdates = function AddonWrapper_findUpdates(listener, reason, appVersion, platformVersion) {
-    AddonManagerPrivate.callNoUpdateListeners(this, listener, reason, appVersion, platformVersion);
-  };
-}
-
-AddonWrapper.prototype = {
   // Lightweight themes are never disabled by the application
   get appDisabled() {
     return false;
   },
 
   // Lightweight themes are always compatible
   get isCompatible() {
     return true;
@@ -602,32 +588,64 @@ AddonWrapper.prototype = {
   get scope() {
     return AddonManager.SCOPE_PROFILE;
   },
 
   get foreignInstall() {
     return false;
   },
 
+  uninstall: function() {
+    LightweightThemeManager.forgetUsedTheme(themeFor(this).id);
+  },
+
+  cancelUninstall: function() {
+    throw new Error("Theme is not marked to be uninstalled");
+  },
+
+  findUpdates: function(listener, reason, appVersion, platformVersion) {
+    AddonManagerPrivate.callNoUpdateListeners(this, listener, reason, appVersion, platformVersion);
+  },
+
   // Lightweight themes are always compatible
-  isCompatibleWith: function AddonWrapper_isCompatibleWith(appVersion, platformVersion) {
+  isCompatibleWith: function(appVersion, platformVersion) {
     return true;
   },
 
   // Lightweight themes are always securely updated
   get providesUpdatesSecurely() {
     return true;
   },
 
   // Lightweight themes are never blocklisted
   get blocklistState() {
     return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
   }
 };
 
+["description", "homepageURL", "iconURL"].forEach(function(prop) {
+  Object.defineProperty(AddonWrapper.prototype, prop, {
+    get: function() {
+      let theme = themeFor(this);
+      return prop in theme ? theme[prop] : null;
+    },
+    enumarable: true,
+  });
+});
+
+["installDate", "updateDate"].forEach(function(prop) {
+  Object.defineProperty(AddonWrapper.prototype, prop, {
+    get: function() {
+      let theme = themeFor(this);
+      return prop in theme ? new Date(theme[prop]) : null;
+    },
+    enumarable: true,
+  });
+});
+
 /**
  * Converts the ID used by the public AddonManager API to an lightweight theme
  * ID.
  *
  * @param   id
  *          The ID to be converted
  *
  * @return  the lightweight theme ID or null if the ID was not for a lightweight
@@ -737,18 +755,17 @@ function _sanitizeTheme(aData, aBaseURI,
       continue;
     result[optionalProperty] = val;
   }
 
   return result;
 }
 
 function _usedThemesExceptId(aId) {
-  return LightweightThemeManager.usedThemes.filter(
-    function usedThemesExceptId_filterID(t) {
+  return LightweightThemeManager.usedThemes.filter(function(t) {
       return "id" in t && t.id != aId;
     });
 }
 
 function _version(aThemeData) {
   return aThemeData.version || "";
 }
 
@@ -778,17 +795,17 @@ function _updateUsedThemes(aList) {
 
 function _notifyWindows(aThemeData) {
   Services.obs.notifyObservers(null, "lightweight-theme-styling-update",
                                JSON.stringify(aThemeData));
 }
 
 var _previewTimer;
 var _previewTimerCallback = {
-  notify: function _previewTimerCallback_notify() {
+  notify: function() {
     LightweightThemeManager.resetPreview();
   }
 };
 
 /**
  * Called when any of the lightweightThemes preferences are changed.
  */
 function _prefObserver(aSubject, aTopic, aData) {
@@ -855,21 +872,21 @@ function _persistImage(sourceURL, localF
   persist.progressListener = new _persistProgressListener(successCallback);
 
   persist.saveURI(sourceURI, null,
                   null, Ci.nsIHttpChannel.REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE,
                   null, null, targetURI, null);
 }
 
 function _persistProgressListener(successCallback) {
-  this.onLocationChange = function persistProgressListener_onLocationChange() {};
-  this.onProgressChange = function persistProgressListener_onProgressChange() {};
-  this.onStatusChange   = function persistProgressListener_onStatusChange() {};
-  this.onSecurityChange = function persistProgressListener_onSecurityChange() {};
-  this.onStateChange    = function persistProgressListener_onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) {
+  this.onLocationChange = function() {};
+  this.onProgressChange = function() {};
+  this.onStatusChange   = function() {};
+  this.onSecurityChange = function() {};
+  this.onStateChange    = function(aWebProgress, aRequest, aStateFlags, aStatus) {
     if (aRequest &&
         aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK &&
         aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
       try {
         if (aRequest.QueryInterface(Ci.nsIHttpChannel).requestSucceeded) {
           // success
           successCallback();
           return;
--- a/toolkit/mozapps/extensions/addonManager.js
+++ b/toolkit/mozapps/extensions/addonManager.js
@@ -48,129 +48,125 @@ function amManager() {
                  .getService(Ci.nsIMessageListenerManager);
   gParentMM.addMessageListener(MSG_INSTALL_ENABLED, this);
 
   // Needed so receiveMessage can be called directly by JS callers
   this.wrappedJSObject = this;
 }
 
 amManager.prototype = {
-  observe: function AMC_observe(aSubject, aTopic, aData) {
+  observe: function(aSubject, aTopic, aData) {
     if (aTopic == "addons-startup")
       AddonManagerPrivate.startup();
   },
 
   /**
    * @see amIAddonManager.idl
    */
-  mapURIToAddonID: function AMC_mapURIToAddonID(uri, id) {
+  mapURIToAddonID: function(uri, id) {
     id.value = AddonManager.mapURIToAddonID(uri);
     return !!id.value;
   },
 
   /**
    * @see amIWebInstaller.idl
    */
-  isInstallEnabled: function AMC_isInstallEnabled(aMimetype, aReferer) {
+  isInstallEnabled: function(aMimetype, aReferer) {
     return AddonManager.isInstallEnabled(aMimetype);
   },
 
   /**
    * @see amIWebInstaller.idl
    */
-  installAddonsFromWebpage: function AMC_installAddonsFromWebpage(aMimetype,
-                                                                  aBrowser,
-                                                                  aInstallingPrincipal,
-                                                                  aUris, aHashes,
-                                                                  aNames, aIcons,
-                                                                  aCallback) {
+  installAddonsFromWebpage: function(aMimetype, aBrowser, aInstallingPrincipal,
+                                     aUris, aHashes, aNames, aIcons, aCallback) {
     if (aUris.length == 0)
       return false;
 
     let retval = true;
     if (!AddonManager.isInstallAllowed(aMimetype, aInstallingPrincipal)) {
       aCallback = null;
       retval = false;
     }
 
     let installs = [];
     function buildNextInstall() {
       if (aUris.length == 0) {
         AddonManager.installAddonsFromWebpage(aMimetype, aBrowser, aInstallingPrincipal, installs);
         return;
       }
       let uri = aUris.shift();
-      AddonManager.getInstallForURL(uri, function buildNextInstall_getInstallForURL(aInstall) {
+      AddonManager.getInstallForURL(uri, function(aInstall) {
         function callCallback(aUri, aStatus) {
           try {
             aCallback.onInstallEnded(aUri, aStatus);
           }
           catch (e) {
             Components.utils.reportError(e);
           }
         }
 
         if (aInstall) {
           installs.push(aInstall);
           if (aCallback) {
             aInstall.addListener({
-              onDownloadCancelled: function buildNextInstall_onDownloadCancelled(aInstall) {
+              onDownloadCancelled: function(aInstall) {
                 callCallback(uri, USER_CANCELLED);
               },
 
-              onDownloadFailed: function buildNextInstall_onDownloadFailed(aInstall) {
+              onDownloadFailed: function(aInstall) {
                 if (aInstall.error == AddonManager.ERROR_CORRUPT_FILE)
                   callCallback(uri, CANT_READ_ARCHIVE);
                 else
                   callCallback(uri, DOWNLOAD_ERROR);
               },
 
-              onInstallFailed: function buildNextInstall_onInstallFailed(aInstall) {
+              onInstallFailed: function(aInstall) {
                 callCallback(uri, EXECUTION_ERROR);
               },
 
-              onInstallEnded: function buildNextInstall_onInstallEnded(aInstall, aStatus) {
+              onInstallEnded: function(aInstall, aStatus) {
                 callCallback(uri, SUCCESS);
               }
             });
           }
         }
         else if (aCallback) {
           aCallback.onInstallEnded(uri, UNSUPPORTED_TYPE);
         }
         buildNextInstall();
       }, aMimetype, aHashes.shift(), aNames.shift(), aIcons.shift(), null, aBrowser);
     }
     buildNextInstall();
 
     return retval;
   },
 
-  notify: function AMC_notify(aTimer) {
+  notify: function(aTimer) {
     AddonManagerPrivate.backgroundUpdateTimerHandler();
   },
 
   /**
    * messageManager callback function.
    *
    * Listens to requests from child processes for InstallTrigger
    * activity, and sends back callbacks.
    */
-  receiveMessage: function AMC_receiveMessage(aMessage) {
+  receiveMessage: function(aMessage) {
     let payload = aMessage.data;
 
     switch (aMessage.name) {
       case MSG_INSTALL_ENABLED:
         return AddonManager.isInstallEnabled(payload.mimetype);
 
       case MSG_INSTALL_ADDONS: {
         let callback = null;
         if (payload.callbackID != -1) {
           callback = {
-            onInstallEnded: function ITP_callback(url, status) {
+            onInstallEnded: function(url, status) {
               gParentMM.broadcastAsyncMessage(MSG_INSTALL_CALLBACK, {
                 callbackID: payload.callbackID,
                 url: url,
                 status: status
               });
             },
           };
         }
@@ -179,17 +175,17 @@ amManager.prototype = {
           aMessage.target, payload.triggeringPrincipal, payload.uris,
           payload.hashes, payload.names, payload.icons, callback);
       }
     }
   },
 
   classID: Components.ID("{4399533d-08d1-458c-a87a-235f74451cfa}"),
   _xpcom_factory: {
-    createInstance: function AMC_createInstance(aOuter, aIid) {
+    createInstance: function(aOuter, aIid) {
       if (aOuter != null)
         throw Components.Exception("Component does not support aggregation",
                                    Cr.NS_ERROR_NO_AGGREGATION);
 
       if (!gSingleton)
         gSingleton = new amManager();
       return gSingleton.QueryInterface(aIid);
     }
--- a/toolkit/mozapps/extensions/amContentHandler.js
+++ b/toolkit/mozapps/extensions/amContentHandler.js
@@ -23,17 +23,17 @@ amContentHandler.prototype = {
    *
    * @param  aMimetype
    *         The mimetype of the file
    * @param  aContext
    *         The context passed to nsIChannel.asyncOpen
    * @param  aRequest
    *         The nsIRequest dealing with the content
    */
-  handleContent: function XCH_handleContent(aMimetype, aContext, aRequest) {
+  handleContent: function(aMimetype, aContext, aRequest) {
     if (aMimetype != XPI_CONTENT_TYPE)
       throw Cr.NS_ERROR_WONT_HANDLE_CONTENT;
 
     if (!(aRequest instanceof Ci.nsIChannel))
       throw Cr.NS_ERROR_WONT_HANDLE_CONTENT;
 
     let uri = aRequest.URI;
 
@@ -84,17 +84,17 @@ amContentHandler.prototype = {
                                .getInterface(Ci.nsIContentFrameMessageManager);
 
     messageManager.sendAsyncMessage(MSG_INSTALL_ADDONS, installs);
   },
 
   classID: Components.ID("{7beb3ba8-6ec3-41b4-b67c-da89b8518922}"),
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentHandler]),
 
-  log : function XCH_log(aMsg) {
+  log : function(aMsg) {
     let msg = "amContentHandler.js: " + (aMsg.join ? aMsg.join("") : aMsg);
     Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService).
       logStringMessage(msg);
     dump(msg + "\n");
   }
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([amContentHandler]);
--- a/toolkit/mozapps/extensions/amInstallTrigger.js
+++ b/toolkit/mozapps/extensions/amInstallTrigger.js
@@ -198,17 +198,17 @@ InstallTrigger.prototype = {
     args[filename] = { "URL": url };
     return this.install(args);
   },
 
   installChrome: function(type, url, skin) {
     return this.startSoftwareUpdate(url);
   },
 
-  _resolveURL: function (url) {
+  _resolveURL: function(url) {
     return Services.io.newURI(url, null, this._url);
   },
 
   _checkLoadURIFromScript: function(uri) {
     let secman = Services.scriptSecurityManager;
     try {
       secman.checkLoadURIWithPrincipal(this._principal,
                                        uri,
--- a/toolkit/mozapps/extensions/amWebInstallListener.js
+++ b/toolkit/mozapps/extensions/amWebInstallListener.js
@@ -65,37 +65,37 @@ function notifyObservers(aTopic, aBrowse
 function Installer(aBrowser, aUrl, aInstalls) {
   this.browser = aBrowser;
   this.url = aUrl;
   this.downloads = aInstalls;
   this.installed = [];
 
   notifyObservers("addon-install-started", aBrowser, aUrl, aInstalls);
 
-  aInstalls.forEach(function(aInstall) {
-    aInstall.addListener(this);
+  for (let install of aInstalls) {
+    install.addListener(this);
 
     // Start downloading if it hasn't already begun
-    if (READY_STATES.indexOf(aInstall.state) != -1)
-      aInstall.install();
-  }, this);
+    if (READY_STATES.indexOf(install.state) != -1)
+      install.install();
+  }
 
   this.checkAllDownloaded();
 }
 
 Installer.prototype = {
   browser: null,
   downloads: null,
   installed: null,
   isDownloading: true,
 
   /**
    * Checks if all downloads are now complete and if so prompts to install.
    */
-  checkAllDownloaded: function Installer_checkAllDownloaded() {
+  checkAllDownloaded: function() {
     // Prevent re-entrancy caused by the confirmation dialog cancelling unwanted
     // installs.
     if (!this.isDownloading)
       return;
 
     var failed = [];
     var installs = [];
 
@@ -112,24 +112,24 @@ Installer.prototype = {
       case AddonManager.STATE_DOWNLOADED:
         // App disabled items are not compatible and so fail to install
         if (install.addon.appDisabled)
           failed.push(install);
         else
           installs.push(install);
 
         if (install.linkedInstalls) {
-          install.linkedInstalls.forEach(function(aInstall) {
-            aInstall.addListener(this);
+          for (let linkedInstall of install.linkedInstalls) {
+            linkedInstall.addListener(this);
             // Corrupt or incompatible items fail to install
-            if (aInstall.state == AddonManager.STATE_DOWNLOAD_FAILED || aInstall.addon.appDisabled)
-              failed.push(aInstall);
+            if (linkedInstall.state == AddonManager.STATE_DOWNLOAD_FAILED || linkedInstall.addon.appDisabled)
+              failed.push(linkedInstall);
             else
-              installs.push(aInstall);
-          }, this);
+              installs.push(linkedInstall);
+          }
         }
         break;
       case AddonManager.STATE_CANCELLED:
         // Just ignore cancelled downloads
         break;
       default:
         logger.warn("Download of " + install.sourceURI.spec + " in unexpected state " +
                     install.state);
@@ -137,22 +137,22 @@ Installer.prototype = {
     }
 
     this.isDownloading = false;
     this.downloads = installs;
 
     if (failed.length > 0) {
       // Stop listening and cancel any installs that are failed because of
       // compatibility reasons.
-      failed.forEach(function(aInstall) {
-        if (aInstall.state == AddonManager.STATE_DOWNLOADED) {
-          aInstall.removeListener(this);
-          aInstall.cancel();
+      for (let install of failed) {
+        if (install.state == AddonManager.STATE_DOWNLOADED) {
+          install.removeListener(this);
+          install.cancel();
         }
-      }, this);
+      }
       notifyObservers("addon-install-failed", this.browser, this.url, failed);
     }
 
     // If none of the downloads were successful then exit early
     if (this.downloads.length == 0)
       return;
 
     // Check for a custom installation prompt that may be provided by the
@@ -186,31 +186,31 @@ Installer.prototype = {
       if (this.browser) {
         parentWindow = this.browser.ownerDocument.defaultView;
         PromptUtils.fireDialogEvent(parentWindow, "DOMWillOpenModalDialog", this.browser);
       }
       Services.ww.openWindow(parentWindow, URI_XPINSTALL_DIALOG,
                              null, "chrome,modal,centerscreen", args);
     } catch (e) {
       logger.warn("Exception showing install confirmation dialog", e);
-      this.downloads.forEach(function(aInstall) {
-        aInstall.removeListener(this);
+      for (let install of this.downloads) {
+        install.removeListener(this);
         // Cancel the installs, as currently there is no way to make them fail
         // from here.
-        aInstall.cancel();
-      }, this);
+        install.cancel();
+      }
       notifyObservers("addon-install-cancelled", this.browser, this.url,
                       this.downloads);
     }
   },
 
   /**
    * Checks if all installs are now complete and if so notifies observers.
    */
-  checkAllInstalled: function Installer_checkAllInstalled() {
+  checkAllInstalled: function() {
     var failed = [];
 
     for (let install of this.downloads) {
       switch(install.state) {
       case AddonManager.STATE_DOWNLOADED:
       case AddonManager.STATE_INSTALLING:
         // Exit early if any add-ons haven't started installing yet or are
         // still installing
@@ -226,42 +226,42 @@ Installer.prototype = {
     if (failed.length > 0)
       notifyObservers("addon-install-failed", this.browser, this.url, failed);
 
     if (this.installed.length > 0)
       notifyObservers("addon-install-complete", this.browser, this.url, this.installed);
     this.installed = null;
   },
 
-  onDownloadCancelled: function Installer_onDownloadCancelled(aInstall) {
+  onDownloadCancelled: function(aInstall) {
     aInstall.removeListener(this);
     this.checkAllDownloaded();
   },
 
-  onDownloadFailed: function Installer_onDownloadFailed(aInstall) {
+  onDownloadFailed: function(aInstall) {
     aInstall.removeListener(this);
     this.checkAllDownloaded();
   },
 
-  onDownloadEnded: function Installer_onDownloadEnded(aInstall) {
+  onDownloadEnded: function(aInstall) {
     this.checkAllDownloaded();
     return false;
   },
 
-  onInstallCancelled: function Installer_onInstallCancelled(aInstall) {
+  onInstallCancelled: function(aInstall) {
     aInstall.removeListener(this);
     this.checkAllInstalled();
   },
 
-  onInstallFailed: function Installer_onInstallFailed(aInstall) {
+  onInstallFailed: function(aInstall) {
     aInstall.removeListener(this);
     this.checkAllInstalled();
   },
 
-  onInstallEnded: function Installer_onInstallEnded(aInstall) {
+  onInstallEnded: function(aInstall) {
     aInstall.removeListener(this);
     this.installed.push(aInstall);
 
     // If installing a theme that is disabled and can be enabled then enable it
     if (aInstall.addon.type == "theme" &&
         aInstall.addon.userDisabled == true &&
         aInstall.addon.appDisabled == false) {
       aInstall.addon.userDisabled = false;
@@ -273,70 +273,70 @@ Installer.prototype = {
 
 function extWebInstallListener() {
 }
 
 extWebInstallListener.prototype = {
   /**
    * @see amIWebInstallListener.idl
    */
-  onWebInstallDisabled: function extWebInstallListener_onWebInstallDisabled(aBrowser, aUri, aInstalls) {
+  onWebInstallDisabled: function(aBrowser, aUri, aInstalls) {
     let info = {
       browser: aBrowser,
       originatingURI: aUri,
       installs: aInstalls,
 
       QueryInterface: XPCOMUtils.generateQI([Ci.amIWebInstallInfo])
     };
     Services.obs.notifyObservers(info, "addon-install-disabled", null);
   },
 
   /**
    * @see amIWebInstallListener.idl
    */
-  onWebInstallOriginBlocked: function extWebInstallListener_onWebInstallOriginBlocked(aBrowser, aUri, aInstalls) {
+  onWebInstallOriginBlocked: function(aBrowser, aUri, aInstalls) {
     let info = {
       browser: aBrowser,
       originatingURI: aUri,
       installs: aInstalls,
 
-      install: function onWebInstallBlocked_install() {
+      install: function() {
       },
 
       QueryInterface: XPCOMUtils.generateQI([Ci.amIWebInstallInfo])
     };
     Services.obs.notifyObservers(info, "addon-install-origin-blocked", null);
 
     return false;
   },
 
   /**
    * @see amIWebInstallListener.idl
    */
-  onWebInstallBlocked: function extWebInstallListener_onWebInstallBlocked(aBrowser, aUri, aInstalls) {
+  onWebInstallBlocked: function(aBrowser, aUri, aInstalls) {
     let info = {
       browser: aBrowser,
       originatingURI: aUri,
       installs: aInstalls,
 
-      install: function onWebInstallBlocked_install() {
+      install: function() {
         new Installer(this.browser, this.originatingURI, this.installs);
       },
 
       QueryInterface: XPCOMUtils.generateQI([Ci.amIWebInstallInfo])
     };
     Services.obs.notifyObservers(info, "addon-install-blocked", null);
 
     return false;
   },
 
   /**
    * @see amIWebInstallListener.idl
    */
-  onWebInstallRequested: function extWebInstallListener_onWebInstallRequested(aBrowser, aUri, aInstalls) {
+  onWebInstallRequested: function(aBrowser, aUri, aInstalls) {
     new Installer(aBrowser, aUri, aInstalls);
 
     // We start the installs ourself
     return false;
   },
 
   classDescription: "XPI Install Handler",
   contractID: "@mozilla.org/addons/web-install-listener;1",
--- a/toolkit/mozapps/extensions/content/blocklist.js
+++ b/toolkit/mozapps/extensions/content/blocklist.js
@@ -21,17 +21,17 @@ function init() {
               createBundle("chrome://mozapps/locale/update/updates.properties");
   let cancelButton = document.documentElement.getButton("cancel");
   cancelButton.setAttribute("label", bundle.GetStringFromName("restartLaterButton"));
   cancelButton.setAttribute("accesskey",
                             bundle.GetStringFromName("restartLaterButton.accesskey"));
 
   var richlist = document.getElementById("addonList");
   var list = gArgs.list;
-  list.sort(function listSort(a, b) { return String.localeCompare(a.name, b.name); });
+  list.sort(function(a, b) { return String.localeCompare(a.name, b.name); });
   for (let listItem of list) {
     let item = document.createElement("richlistitem");
     item.setAttribute("name", listItem.name);
     item.setAttribute("version", listItem.version);
     item.setAttribute("icon", listItem.icon);
     if (listItem.blocked) {
       item.setAttribute("class", "hardBlockedAddon");
       hasHardBlocks = true;
--- a/toolkit/mozapps/extensions/content/extensions.js
+++ b/toolkit/mozapps/extensions/content/extensions.js
@@ -10,20 +10,26 @@ var Cu = Components.utils;
 var Cr = Components.results;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/DownloadUtils.jsm");
 Cu.import("resource://gre/modules/AddonManager.jsm");
 Cu.import("resource://gre/modules/addons/AddonRepository.jsm");
 
+const CONSTANTS = {};
+Cu.import("resource://gre/modules/addons/AddonConstants.jsm", CONSTANTS);
+const SIGNING_REQUIRED = CONSTANTS.REQUIRE_SIGNING ?
+                         true :
+                         Services.prefs.getBoolPref("xpinstall.signatures.required");
+
 XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
                                   "resource://gre/modules/PluralForm.jsm");
 
-XPCOMUtils.defineLazyGetter(this, "BrowserToolboxProcess", function () {
+XPCOMUtils.defineLazyGetter(this, "BrowserToolboxProcess", function() {
   return Cu.import("resource://devtools/client/framework/ToolboxProcess.jsm", {}).
          BrowserToolboxProcess;
 });
 XPCOMUtils.defineLazyModuleGetter(this, "Experiments",
   "resource:///modules/experiments/Experiments.jsm");
 
 const PREF_DISCOVERURL = "extensions.webservice.discoverURL";
 const PREF_DISCOVER_ENABLED = "extensions.getAddons.showPane";
@@ -53,39 +59,39 @@ const XMLURI_PARSE_ERROR = "http://www.m
 
 var gViewDefault = "addons://discover/";
 
 var gStrings = {};
 XPCOMUtils.defineLazyServiceGetter(gStrings, "bundleSvc",
                                    "@mozilla.org/intl/stringbundle;1",
                                    "nsIStringBundleService");
 
-XPCOMUtils.defineLazyGetter(gStrings, "brand", function brandLazyGetter() {
+XPCOMUtils.defineLazyGetter(gStrings, "brand", function() {
   return this.bundleSvc.createBundle("chrome://branding/locale/brand.properties");
 });
-XPCOMUtils.defineLazyGetter(gStrings, "ext", function extLazyGetter() {
+XPCOMUtils.defineLazyGetter(gStrings, "ext", function() {
   return this.bundleSvc.createBundle("chrome://mozapps/locale/extensions/extensions.properties");
 });
-XPCOMUtils.defineLazyGetter(gStrings, "dl", function dlLazyGetter() {
+XPCOMUtils.defineLazyGetter(gStrings, "dl", function() {
   return this.bundleSvc.createBundle("chrome://mozapps/locale/downloads/downloads.properties");
 });
 
-XPCOMUtils.defineLazyGetter(gStrings, "brandShortName", function brandShortNameLazyGetter() {
+XPCOMUtils.defineLazyGetter(gStrings, "brandShortName", function() {
   return this.brand.GetStringFromName("brandShortName");
 });
-XPCOMUtils.defineLazyGetter(gStrings, "appVersion", function appVersionLazyGetter() {
+XPCOMUtils.defineLazyGetter(gStrings, "appVersion", function() {
   return Services.appinfo.version;
 });
 
 document.addEventListener("load", initialize, true);
 window.addEventListener("unload", shutdown, false);
 
 var gPendingInitializations = 1;
-this.__defineGetter__("gIsInitializing", function gIsInitializingGetter() {
-  return gPendingInitializations > 0;
+Object.defineProperty(this, "gIsInitializing", {
+  get: () => gPendingInitializations > 0
 });
 
 function initialize(event) {
   // XXXbz this listener gets _all_ load events for all nodes in the
   // document... but relies on not being called "too early".
   if (event.target instanceof XMLStylesheetProcessingInstruction) {
     return;
   }
@@ -300,37 +306,37 @@ var HTML5History = {
   },
 
   get canGoForward() {
     return window.QueryInterface(Ci.nsIInterfaceRequestor)
                  .getInterface(Ci.nsIWebNavigation)
                  .canGoForward;
   },
 
-  back: function HTML5History_back() {
+  back: function() {
     window.history.back();
     gViewController.updateCommand("cmd_back");
     gViewController.updateCommand("cmd_forward");
   },
 
-  forward: function HTML5History_forward() {
+  forward: function() {
     window.history.forward();
     gViewController.updateCommand("cmd_back");
     gViewController.updateCommand("cmd_forward");
   },
 
-  pushState: function HTML5History_pushState(aState) {
+  pushState: function(aState) {
     window.history.pushState(aState, document.title);
   },
 
-  replaceState: function HTML5History_replaceState(aState) {
+  replaceState: function(aState) {
     window.history.replaceState(aState, document.title);
   },
 
-  popState: function HTML5History_popState() {
+  popState: function() {
     function onStatePopped(aEvent) {
       window.removeEventListener("popstate", onStatePopped, true);
       // TODO To ensure we can't go forward again we put an additional entry
       // for the current state into the history. Ideally we would just strip
       // the history but there doesn't seem to be a way to do that. Bug 590661
       window.history.pushState(aEvent.state, document.title);
     }
     window.addEventListener("popstate", onStatePopped, true);
@@ -354,47 +360,47 @@ var FakeHistory = {
   get canGoBack() {
     return this.pos > 0;
   },
 
   get canGoForward() {
     return (this.pos + 1) < this.states.length;
   },
 
-  back: function FakeHistory_back() {
+  back: function() {
     if (this.pos == 0)
       throw Components.Exception("Cannot go back from this point");
 
     this.pos--;
     gViewController.updateState(this.states[this.pos]);
     gViewController.updateCommand("cmd_back");
     gViewController.updateCommand("cmd_forward");
   },
 
-  forward: function FakeHistory_forward() {
+  forward: function() {
     if ((this.pos + 1) >= this.states.length)
       throw Components.Exception("Cannot go forward from this point");
 
     this.pos++;
     gViewController.updateState(this.states[this.pos]);
     gViewController.updateCommand("cmd_back");
     gViewController.updateCommand("cmd_forward");
   },
 
-  pushState: function FakeHistory_pushState(aState) {
+  pushState: function(aState) {
     this.pos++;
     this.states.splice(this.pos, this.states.length);
     this.states.push(aState);
   },
 
-  replaceState: function FakeHistory_replaceState(aState) {
+  replaceState: function(aState) {
     this.states[this.pos] = aState;
   },
 
-  popState: function FakeHistory_popState() {
+  popState: function() {
     if (this.pos == 0)
       throw Components.Exception("Cannot popState from this view");
 
     this.states.splice(this.pos, this.states.length);
     this.pos--;
 
     gViewController.updateState(this.states[this.pos]);
     gViewController.updateCommand("cmd_back");
@@ -412,53 +418,48 @@ if (window.QueryInterface(Ci.nsIInterfac
 else {
   gHistory = FakeHistory;
 }
 
 var gEventManager = {
   _listeners: {},
   _installListeners: [],
 
-  initialize: function gEM_initialize() {
-    var self = this;
+  initialize: function() {
     const ADDON_EVENTS = ["onEnabling", "onEnabled", "onDisabling",
                           "onDisabled", "onUninstalling", "onUninstalled",
                           "onInstalled", "onOperationCancelled",
                           "onUpdateAvailable", "onUpdateFinished",
                           "onCompatibilityUpdateAvailable",
                           "onPropertyChanged"];
     for (let evt of ADDON_EVENTS) {
       let event = evt;
-      self[event] = function initialize_delegateAddonEvent(...aArgs) {
-        self.delegateAddonEvent(event, aArgs);
-      };
+      this[event] = (...aArgs) => this.delegateAddonEvent(event, aArgs);
     }
 
     const INSTALL_EVENTS = ["onNewInstall", "onDownloadStarted",
                             "onDownloadEnded", "onDownloadFailed",
                             "onDownloadProgress", "onDownloadCancelled",
                             "onInstallStarted", "onInstallEnded",
                             "onInstallFailed", "onInstallCancelled",
                             "onExternalInstall"];
     for (let evt of INSTALL_EVENTS) {
       let event = evt;
-      self[event] = function initialize_delegateInstallEvent(...aArgs) {
-        self.delegateInstallEvent(event, aArgs);
-      };
+      this[event] = (...aArgs) => this.delegateInstallEvent(event, aArgs);
     }
 
     AddonManager.addManagerListener(this);
     AddonManager.addInstallListener(this);
     AddonManager.addAddonListener(this);
 
     this.refreshGlobalWarning();
     this.refreshAutoUpdateDefault();
 
     var contextMenu = document.getElementById("addonitem-popup");
-    contextMenu.addEventListener("popupshowing", function contextMenu_onPopupshowing() {
+    contextMenu.addEventListener("popupshowing", function() {
       var addon = gViewController.currentViewObj.getSelectedAddon();
       contextMenu.setAttribute("addontype", addon.type);
 
       var menuSep = document.getElementById("addonitem-menuseparator");
       var countMenuItemsBeforeSep = 0;
       for (let child of contextMenu.children) {
         if (child == menuSep) {
           break;
@@ -495,53 +496,53 @@ var gEventManager = {
         if (shouldShowVersionNumber(addonItem.mInstall))
           tiptext += " " + addonItem.mInstall.version;
       }
 
       addonTooltip.label = tiptext;
     }, false);
   },
 
-  shutdown: function gEM_shutdown() {
+  shutdown: function() {
     AddonManager.removeManagerListener(this);
     AddonManager.removeInstallListener(this);
     AddonManager.removeAddonListener(this);
   },
 
-  registerAddonListener: function gEM_registerAddonListener(aListener, aAddonId) {
+  registerAddonListener: function(aListener, aAddonId) {
     if (!(aAddonId in this._listeners))
       this._listeners[aAddonId] = [];
     else if (this._listeners[aAddonId].indexOf(aListener) != -1)
       return;
     this._listeners[aAddonId].push(aListener);
   },
 
-  unregisterAddonListener: function gEM_unregisterAddonListener(aListener, aAddonId) {
+  unregisterAddonListener: function(aListener, aAddonId) {
     if (!(aAddonId in this._listeners))
       return;
     var index = this._listeners[aAddonId].indexOf(aListener);
     if (index == -1)
       return;
     this._listeners[aAddonId].splice(index, 1);
   },
 
-  registerInstallListener: function gEM_registerInstallListener(aListener) {
+  registerInstallListener: function(aListener) {
     if (this._installListeners.indexOf(aListener) != -1)
       return;
     this._installListeners.push(aListener);
   },
 
-  unregisterInstallListener: function gEM_unregisterInstallListener(aListener) {
+  unregisterInstallListener: function(aListener) {
     var i = this._installListeners.indexOf(aListener);
     if (i == -1)
       return;
     this._installListeners.splice(i, 1);
   },
 
-  delegateAddonEvent: function gEM_delegateAddonEvent(aEvent, aParams) {
+  delegateAddonEvent: function(aEvent, aParams) {
     var addon = aParams.shift();
     if (!(addon.id in this._listeners))
       return;
 
     var listeners = this._listeners[addon.id];
     for (let listener of listeners) {
       if (!(aEvent in listener))
         continue;
@@ -549,17 +550,17 @@ var gEventManager = {
         listener[aEvent].apply(listener, aParams);
       } catch(e) {
         // this shouldn't be fatal
         Cu.reportError(e);
       }
     }
   },
 
-  delegateInstallEvent: function gEM_delegateInstallEvent(aEvent, aParams) {
+  delegateInstallEvent: function(aEvent, aParams) {
     var existingAddon = aEvent == "onExternalInstall" ? aParams[1] : aParams[0].existingAddon;
     // If the install is an update then send the event to all listeners
     // registered for the existing add-on
     if (existingAddon)
       this.delegateAddonEvent(aEvent, [existingAddon].concat(aParams));
 
     for (let listener of this._installListeners) {
       if (!(aEvent in listener))
@@ -568,17 +569,17 @@ var gEventManager = {
         listener[aEvent].apply(listener, aParams);
       } catch(e) {
         // this shouldn't be fatal
         Cu.reportError(e);
       }
     }
   },
 
-  refreshGlobalWarning: function gEM_refreshGlobalWarning() {
+  refreshGlobalWarning: function() {
     var page = document.getElementById("addons-page");
 
     if (Services.appinfo.inSafeMode) {
       page.setAttribute("warning", "safemode");
       return;
     }
 
     if (AddonManager.checkUpdateSecurityDefault &&
@@ -590,77 +591,76 @@ var gEventManager = {
     if (!AddonManager.checkCompatibility) {
       page.setAttribute("warning", "checkcompatibility");
       return;
     }
 
     page.removeAttribute("warning");
   },
 
-  refreshAutoUpdateDefault: function gEM_refreshAutoUpdateDefault() {
+  refreshAutoUpdateDefault: function() {
     var updateEnabled = AddonManager.updateEnabled;
     var autoUpdateDefault = AddonManager.autoUpdateDefault;
 
     // The checkbox needs to reflect that both prefs need to be true
     // for updates to be checked for and applied automatically
     document.getElementById("utils-autoUpdateDefault")
             .setAttribute("checked", updateEnabled && autoUpdateDefault);
 
     document.getElementById("utils-resetAddonUpdatesToAutomatic").hidden = !autoUpdateDefault;
     document.getElementById("utils-resetAddonUpdatesToManual").hidden = autoUpdateDefault;
   },
 
-  onCompatibilityModeChanged: function gEM_onCompatibilityModeChanged() {
+  onCompatibilityModeChanged: function() {
     this.refreshGlobalWarning();
   },
 
-  onCheckUpdateSecurityChanged: function gEM_onCheckUpdateSecurityChanged() {
+  onCheckUpdateSecurityChanged: function() {
     this.refreshGlobalWarning();
   },
 
-  onUpdateModeChanged: function gEM_onUpdateModeChanged() {
+  onUpdateModeChanged: function() {
     this.refreshAutoUpdateDefault();
   }
 };
 
 
 var gViewController = {
   viewPort: null,
   currentViewId: "",
   currentViewObj: null,
   currentViewRequest: 0,
   viewObjects: {},
   viewChangeCallback: null,
   initialViewSelected: false,
   lastHistoryIndex: -1,
 
-  initialize: function gVC_initialize() {
+  initialize: function() {
     this.viewPort = document.getElementById("view-port");
 
     this.viewObjects["search"] = gSearchView;
     this.viewObjects["discover"] = gDiscoverView;
     this.viewObjects["list"] = gListView;
     this.viewObjects["detail"] = gDetailView;
     this.viewObjects["updates"] = gUpdatesView;
 
     for (let type in this.viewObjects) {
       let view = this.viewObjects[type];
       view.initialize();
     }
 
     window.controllers.appendController(this);
 
-    window.addEventListener("popstate",
-                            function window_onStatePopped(e) {
+    window.addEventListener("popstate", function(e) {
                               gViewController.updateState(e.state);
                             },
                             false);
   },
 
-  shutdown: function gVC_shutdown() {
+  shutdown: function() {
     if (this.currentViewObj)
       this.currentViewObj.hide();
     this.currentViewRequest = 0;
 
     for (let type in this.viewObjects) {
       let view = this.viewObjects[type];
       if ("shutdown" in view) {
         try {
@@ -670,17 +670,17 @@ var gViewController = {
           Cu.reportError(e);
         }
       }
     }
 
     window.controllers.removeController(this);
   },
 
-  updateState: function gVC_updateState(state) {
+  updateState: function(state) {
     try {
       this.loadViewInternal(state.view, state.previousView, state);
       this.lastHistoryIndex = gHistory.index;
     }
     catch (e) {
       // The attempt to load the view failed, try moving further along history
       if (this.lastHistoryIndex > gHistory.index) {
         if (gHistory.canGoBack)
@@ -691,27 +691,27 @@ var gViewController = {
         if (gHistory.canGoForward)
           gHistory.forward();
         else
           gViewController.replaceView(gViewDefault);
       }
     }
   },
 
-  parseViewId: function gVC_parseViewId(aViewId) {
+  parseViewId: function(aViewId) {
     var matchRegex = /^addons:\/\/([^\/]+)\/(.*)$/;
     var [,viewType, viewParam] = aViewId.match(matchRegex) || [];
     return {type: viewType, param: decodeURIComponent(viewParam)};
   },
 
   get isLoading() {
     return !this.currentViewObj || this.currentViewObj.node.hasAttribute("loading");
   },
 
-  loadView: function gVC_loadView(aViewId) {
+  loadView: function(aViewId) {
     var isRefresh = false;
     if (aViewId == this.currentViewId) {
       if (this.isLoading)
         return;
       if (!("refresh" in this.currentViewObj))
         return;
       if (!this.currentViewObj.canRefresh())
         return;
@@ -726,41 +726,41 @@ var gViewController = {
       gHistory.pushState(state);
       this.lastHistoryIndex = gHistory.index;
     }
     this.loadViewInternal(aViewId, this.currentViewId, state);
   },
 
   // Replaces the existing view with a new one, rewriting the current history
   // entry to match.
-  replaceView: function gVC_replaceView(aViewId) {
+  replaceView: function(aViewId) {
     if (aViewId == this.currentViewId)
       return;
 
     var state = {
       view: aViewId,
       previousView: null
     };
     gHistory.replaceState(state);
     this.loadViewInternal(aViewId, null, state);
   },
 
-  loadInitialView: function gVC_loadInitialView(aViewId) {
+  loadInitialView: function(aViewId) {
     var state = {
       view: aViewId,
       previousView: null
     };
     gHistory.replaceState(state);
 
     this.loadViewInternal(aViewId, null, state);
     this.initialViewSelected = true;
     notifyInitialized();
   },
 
-  loadViewInternal: function gVC_loadViewInternal(aViewId, aPreviousView, aState) {
+  loadViewInternal: function(aViewId, aPreviousView, aState) {
     var view = this.parseViewId(aViewId);
 
     if (!view.type || !(view.type in this.viewObjects))
       throw Components.Exception("Invalid view: " + view.type);
 
     var viewObj = this.viewObjects[view.type];
     if (!viewObj.node)
       throw Components.Exception("Root node doesn't exist for '" + view.type + "' view");
@@ -788,199 +788,198 @@ var gViewController = {
 
     if (aViewId == aPreviousView)
       this.currentViewObj.refresh(view.param, ++this.currentViewRequest, aState);
     else
       this.currentViewObj.show(view.param, ++this.currentViewRequest, aState);
   },
 
   // Moves back in the document history and removes the current history entry
-  popState: function gVC_popState(aCallback) {
+  popState: function(aCallback) {
     this.viewChangeCallback = aCallback;
     gHistory.popState();
   },
 
-  notifyViewChanged: function gVC_notifyViewChanged() {
+  notifyViewChanged: function() {
     this.viewPort.selectedPanel.removeAttribute("loading");
 
     if (this.viewChangeCallback) {
       this.viewChangeCallback();
       this.viewChangeCallback = null;
     }
 
     var event = document.createEvent("Events");
     event.initEvent("ViewChanged", true, true);
     this.currentViewObj.node.dispatchEvent(event);
   },
 
   commands: {
     cmd_back: {
-      isEnabled: function cmd_back_isEnabled() {
+      isEnabled: function() {
         return gHistory.canGoBack;
       },
-      doCommand: function cmd_back_doCommand() {
+      doCommand: function() {
         gHistory.back();
       }
     },
 
     cmd_forward: {
-      isEnabled: function cmd_forward_isEnabled() {
+      isEnabled: function() {
         return gHistory.canGoForward;
       },
-      doCommand: function cmd_forward_doCommand() {
+      doCommand: function() {
         gHistory.forward();
       }
     },
 
     cmd_focusSearch: {
       isEnabled: () => true,
-      doCommand: function cmd_focusSearch_doCommand() {
+      doCommand: function() {
         gHeader.focusSearchBox();
       }
     },
 
     cmd_restartApp: {
-      isEnabled: function cmd_restartApp_isEnabled() {
+      isEnabled: function() {
         return true;
       },
-      doCommand: function cmd_restartApp_doCommand() {
+      doCommand: function() {
         let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].
                          createInstance(Ci.nsISupportsPRBool);
         Services.obs.notifyObservers(cancelQuit, "quit-application-requested",
                                      "restart");
         if (cancelQuit.data)
           return; // somebody canceled our quit request
 
         let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"].
                          getService(Ci.nsIAppStartup);
         appStartup.quit(Ci.nsIAppStartup.eAttemptQuit |  Ci.nsIAppStartup.eRestart);
       }
     },
 
     cmd_enableCheckCompatibility: {
-      isEnabled: function cmd_enableCheckCompatibility_isEnabled() {
+      isEnabled: function() {
         return true;
       },
-      doCommand: function cmd_enableCheckCompatibility_doCommand() {
+      doCommand: function() {
         AddonManager.checkCompatibility = true;
       }
     },
 
     cmd_enableUpdateSecurity: {
-      isEnabled: function cmd_enableUpdateSecurity_isEnabled() {
+      isEnabled: function() {
         return true;
       },
-      doCommand: function cmd_enableUpdateSecurity_doCommand() {
+      doCommand: function() {
         AddonManager.checkUpdateSecurity = true;
       }
     },
 
     cmd_pluginCheck: {
-      isEnabled: function cmd_pluginCheck_isEnabled() {
+      isEnabled: function() {
         return true;
       },
-      doCommand: function cmd_pluginCheck_doCommand() {
+      doCommand: function() {
         openURL(Services.urlFormatter.formatURLPref("plugins.update.url"));
       }
     },
 
     cmd_toggleAutoUpdateDefault: {
-      isEnabled: function cmd_toggleAutoUpdateDefault_isEnabled() {
+      isEnabled: function() {
         return true;
       },
-      doCommand: function cmd_toggleAutoUpdateDefault_doCommand() {
+      doCommand: function() {
         if (!AddonManager.updateEnabled || !AddonManager.autoUpdateDefault) {
           // One or both of the prefs is false, i.e. the checkbox is not checked.
           // Now toggle both to true. If the user wants us to auto-update
           // add-ons, we also need to auto-check for updates.
           AddonManager.updateEnabled = true;
           AddonManager.autoUpdateDefault = true;
         } else {
           // Both prefs are true, i.e. the checkbox is checked.
           // Toggle the auto pref to false, but don't touch the enabled check.
           AddonManager.autoUpdateDefault = false;
         }
       }
     },
 
     cmd_resetAddonAutoUpdate: {
-      isEnabled: function cmd_resetAddonAutoUpdate_isEnabled() {
+      isEnabled: function() {
         return true;
       },
-      doCommand: function cmd_resetAddonAutoUpdate_doCommand() {
-        AddonManager.getAllAddons(function cmd_resetAddonAutoUpdate_getAllAddons(aAddonList) {
+      doCommand: function() {
+        AddonManager.getAllAddons(function(aAddonList) {
           for (let addon of aAddonList) {
             if ("applyBackgroundUpdates" in addon)
               addon.applyBackgroundUpdates = AddonManager.AUTOUPDATE_DEFAULT;
           }
         });
       }
     },
 
     cmd_goToDiscoverPane: {
-      isEnabled: function cmd_goToDiscoverPane_isEnabled() {
+      isEnabled: function() {
         return gDiscoverView.enabled;
       },
-      doCommand: function cmd_goToDiscoverPane_doCommand() {
+      doCommand: function() {
         gViewController.loadView("addons://discover/");
       }
     },
 
     cmd_goToRecentUpdates: {
-      isEnabled: function cmd_goToRecentUpdates_isEnabled() {
+      isEnabled: function() {
         return true;
       },
-      doCommand: function cmd_goToRecentUpdates_doCommand() {
+      doCommand: function() {
         gViewController.loadView("addons://updates/recent");
       }
     },
 
     cmd_goToAvailableUpdates: {
-      isEnabled: function cmd_goToAvailableUpdates_isEnabled() {
+      isEnabled: function() {
         return true;
       },
-      doCommand: function cmd_goToAvailableUpdates_doCommand() {
+      doCommand: function() {
         gViewController.loadView("addons://updates/available");
       }
     },
 
     cmd_showItemDetails: {
-      isEnabled: function cmd_showItemDetails_isEnabled(aAddon) {
+      isEnabled: function(aAddon) {
         return !!aAddon && (gViewController.currentViewObj != gDetailView);
       },
-      doCommand: function cmd_showItemDetails_doCommand(aAddon, aScrollToPreferences) {
+      doCommand: function(aAddon, aScrollToPreferences) {
         gViewController.loadView("addons://detail/" +
                                  encodeURIComponent(aAddon.id) +
                                  (aScrollToPreferences ? "/preferences" : ""));
       }
     },
 
     cmd_findAllUpdates: {
       inProgress: false,
-      isEnabled: function cmd_findAllUpdates_isEnabled() {
+      isEnabled: function() {
         return !this.inProgress;
       },
-      doCommand: function cmd_findAllUpdates_doCommand() {
+      doCommand: function() {
         this.inProgress = true;
         gViewController.updateCommand("cmd_findAllUpdates");
         document.getElementById("updates-noneFound").hidden = true;
         document.getElementById("updates-progress").hidden = false;
         document.getElementById("updates-manualUpdatesFound-btn").hidden = true;
 
         var pendingChecks = 0;
         var numUpdated = 0;
         var numManualUpdates = 0;
         var restartNeeded = false;
-        var self = this;
-
-        function updateStatus() {
+
+        let updateStatus = () => {
           if (pendingChecks > 0)
             return;
 
-          self.inProgress = false;
+          this.inProgress = false;
           gViewController.updateCommand("cmd_findAllUpdates");
           document.getElementById("updates-progress").hidden = true;
           gUpdatesView.maybeRefresh();
 
           if (numManualUpdates > 0 && numUpdated == 0) {
             document.getElementById("updates-manualUpdatesFound-btn").hidden = false;
             return;
           }
@@ -994,125 +993,125 @@ var gViewController = {
             document.getElementById("updates-downloaded").hidden = false;
             document.getElementById("updates-restart-btn").hidden = false;
           } else {
             document.getElementById("updates-installed").hidden = false;
           }
         }
 
         var updateInstallListener = {
-          onDownloadFailed: function cmd_findAllUpdates_downloadFailed() {
+          onDownloadFailed: function() {
             pendingChecks--;
             updateStatus();
           },
-          onInstallFailed: function cmd_findAllUpdates_installFailed() {
+          onInstallFailed: function() {
             pendingChecks--;
             updateStatus();
           },
-          onInstallEnded: function cmd_findAllUpdates_installEnded(aInstall, aAddon) {
+          onInstallEnded: function(aInstall, aAddon) {
             pendingChecks--;
             numUpdated++;
             if (isPending(aInstall.existingAddon, "upgrade"))
               restartNeeded = true;
             updateStatus();
           }
         };
 
         var updateCheckListener = {
-          onUpdateAvailable: function cmd_findAllUpdates_updateAvailable(aAddon, aInstall) {
+          onUpdateAvailable: function(aAddon, aInstall) {
             gEventManager.delegateAddonEvent("onUpdateAvailable",
                                              [aAddon, aInstall]);
             if (AddonManager.shouldAutoUpdate(aAddon)) {
               aInstall.addListener(updateInstallListener);
               aInstall.install();
             } else {
               pendingChecks--;
               numManualUpdates++;
               updateStatus();
             }
           },
-          onNoUpdateAvailable: function cmd_findAllUpdates_noUpdateAvailable(aAddon) {
+          onNoUpdateAvailable: function(aAddon) {
             pendingChecks--;
             updateStatus();
           },
-          onUpdateFinished: function cmd_findAllUpdates_updateFinished(aAddon, aError) {
+          onUpdateFinished: function(aAddon, aError) {
             gEventManager.delegateAddonEvent("onUpdateFinished",
                                              [aAddon, aError]);
           }
         };
 
-        AddonManager.getAddonsByTypes(null, function cmd_findAllUpdates_getAddonsByTypes(aAddonList) {
+        AddonManager.getAddonsByTypes(null, function(aAddonList) {
           for (let addon of aAddonList) {
             if (addon.permissions & AddonManager.PERM_CAN_UPGRADE) {
               pendingChecks++;
               addon.findUpdates(updateCheckListener,
                                 AddonManager.UPDATE_WHEN_USER_REQUESTED);
             }
           }
 
           if (pendingChecks == 0)
             updateStatus();
         });
       }
     },
 
     cmd_findItemUpdates: {
-      isEnabled: function cmd_findItemUpdates_isEnabled(aAddon) {
+      isEnabled: function(aAddon) {
         if (!aAddon)
           return false;
         return hasPermission(aAddon, "upgrade");
       },
-      doCommand: function cmd_findItemUpdates_doCommand(aAddon) {
+      doCommand: function(aAddon) {
         var listener = {
-          onUpdateAvailable: function cmd_findItemUpdates_updateAvailable(aAddon, aInstall) {
+          onUpdateAvailable: function(aAddon, aInstall) {
             gEventManager.delegateAddonEvent("onUpdateAvailable",
                                              [aAddon, aInstall]);
             if (AddonManager.shouldAutoUpdate(aAddon))
               aInstall.install();
           },
-          onNoUpdateAvailable: function cmd_findItemUpdates_noUpdateAvailable(aAddon) {
+          onNoUpdateAvailable: function(aAddon) {
             gEventManager.delegateAddonEvent("onNoUpdateAvailable",
                                              [aAddon]);
           }
         };
         gEventManager.delegateAddonEvent("onCheckingUpdate", [aAddon]);
         aAddon.findUpdates(listener, AddonManager.UPDATE_WHEN_USER_REQUESTED);
       }
     },
 
     cmd_debugItem: {
-      doCommand: function cmd_debugItem_doCommand(aAddon) {
+      doCommand: function(aAddon) {
         BrowserToolboxProcess.init({ addonID: aAddon.id });
       },
 
-      isEnabled: function cmd_debugItem_isEnabled(aAddon) {
+      isEnabled: function(aAddon) {
         let debuggerEnabled = Services.prefs.
                               getBoolPref(PREF_ADDON_DEBUGGING_ENABLED);
         let remoteEnabled = Services.prefs.
                             getBoolPref(PREF_REMOTE_DEBUGGING_ENABLED);
         return aAddon && aAddon.isDebuggable && debuggerEnabled && remoteEnabled;
       }
     },
 
     cmd_showItemPreferences: {
-      isEnabled: function cmd_showItemPreferences_isEnabled(aAddon) {
+      isEnabled: function(aAddon) {
         if (!aAddon ||
             (!aAddon.isActive && !aAddon.isGMPlugin) ||
             !aAddon.optionsURL) {
           return false;
         }
         if (gViewController.currentViewObj == gDetailView &&
             aAddon.optionsType == AddonManager.OPTIONS_TYPE_INLINE) {
           return false;
         }
         if (aAddon.optionsType == AddonManager.OPTIONS_TYPE_INLINE_INFO)
           return false;
         return true;
       },
-      doCommand: function cmd_showItemPreferences_doCommand(aAddon) {
+      doCommand: function(aAddon) {
         if (aAddon.optionsType == AddonManager.OPTIONS_TYPE_INLINE) {
           gViewController.commands.cmd_showItemDetails.doCommand(aAddon, true);
           return;
         }
         var optionsURL = aAddon.optionsURL;
         if (aAddon.optionsType == AddonManager.OPTIONS_TYPE_TAB &&
             openOptionsInTab(optionsURL)) {
           return;
@@ -1135,140 +1134,140 @@ var gViewController = {
         } catch (e) {
           features += ",modal";
         }
         openDialog(optionsURL, "", features);
       }
     },
 
     cmd_showItemAbout: {
-      isEnabled: function cmd_showItemAbout_isEnabled(aAddon) {
+      isEnabled: function(aAddon) {
         // XXXunf This may be applicable to install items too. See bug 561260
         return !!aAddon;
       },
-      doCommand: function cmd_showItemAbout_doCommand(aAddon) {
+      doCommand: function(aAddon) {
         var aboutURL = aAddon.aboutURL;
         if (aboutURL)
           openDialog(aboutURL, "", "chrome,centerscreen,modal", aAddon);
         else
           openDialog("chrome://mozapps/content/extensions/about.xul",
                      "", "chrome,centerscreen,modal", aAddon);
       }
     },
 
     cmd_enableItem: {
-      isEnabled: function cmd_enableItem_isEnabled(aAddon) {
+      isEnabled: function(aAddon) {
         if (!aAddon)
           return false;
         let addonType = AddonManager.addonTypes[aAddon.type];
         return (!(addonType.flags & AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE) &&
                 hasPermission(aAddon, "enable"));
       },
-      doCommand: function cmd_enableItem_doCommand(aAddon) {
+      doCommand: function(aAddon) {
         aAddon.userDisabled = false;
       },
-      getTooltip: function cmd_enableItem_getTooltip(aAddon) {
+      getTooltip: function(aAddon) {
         if (!aAddon)
           return "";
         if (aAddon.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_ENABLE)
           return gStrings.ext.GetStringFromName("enableAddonRestartRequiredTooltip");
         return gStrings.ext.GetStringFromName("enableAddonTooltip");
       }
     },
 
     cmd_disableItem: {
-      isEnabled: function cmd_disableItem_isEnabled(aAddon) {
+      isEnabled: function(aAddon) {
         if (!aAddon)
           return false;
         let addonType = AddonManager.addonTypes[aAddon.type];
         return (!(addonType.flags & AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE) &&
                 hasPermission(aAddon, "disable"));
       },
-      doCommand: function cmd_disableItem_doCommand(aAddon) {
+      doCommand: function(aAddon) {
         aAddon.userDisabled = true;
       },
-      getTooltip: function cmd_disableItem_getTooltip(aAddon) {
+      getTooltip: function(aAddon) {
         if (!aAddon)
           return "";
         if (aAddon.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_DISABLE)
           return gStrings.ext.GetStringFromName("disableAddonRestartRequiredTooltip");
         return gStrings.ext.GetStringFromName("disableAddonTooltip");
       }
     },
 
     cmd_installItem: {
-      isEnabled: function cmd_installItem_isEnabled(aAddon) {
+      isEnabled: function(aAddon) {
         if (!aAddon)
           return false;
         return aAddon.install && aAddon.install.state == AddonManager.STATE_AVAILABLE;
       },
-      doCommand: function cmd_installItem_doCommand(aAddon) {
+      doCommand: function(aAddon) {
         function doInstall() {
           gViewController.currentViewObj.getListItemForID(aAddon.id)._installStatus.installRemote();
         }
 
         if (gViewController.currentViewObj == gDetailView)
           gViewController.popState(doInstall);
         else
           doInstall();
       }
     },
 
     cmd_purchaseItem: {
-      isEnabled: function cmd_purchaseItem_isEnabled(aAddon) {
+      isEnabled: function(aAddon) {
         if (!aAddon)
           return false;
         return !!aAddon.purchaseURL;
       },
-      doCommand: function cmd_purchaseItem_doCommand(aAddon) {
+      doCommand: function(aAddon) {
         openURL(aAddon.purchaseURL);
       }
     },
 
     cmd_uninstallItem: {
-      isEnabled: function cmd_uninstallItem_isEnabled(aAddon) {
+      isEnabled: function(aAddon) {
         if (!aAddon)
           return false;
         return hasPermission(aAddon, "uninstall");
       },
-      doCommand: function cmd_uninstallItem_doCommand(aAddon) {
+      doCommand: function(aAddon) {
         if (gViewController.currentViewObj != gDetailView) {
           aAddon.uninstall();
           return;
         }
 
-        gViewController.popState(function cmd_uninstallItem_popState() {
+        gViewController.popState(function() {
           gViewController.currentViewObj.getListItemForID(aAddon.id).uninstall();
         });
       },
-      getTooltip: function cmd_uninstallItem_getTooltip(aAddon) {
+      getTooltip: function(aAddon) {
         if (!aAddon)
           return "";
         if (aAddon.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_UNINSTALL)
           return gStrings.ext.GetStringFromName("uninstallAddonRestartRequiredTooltip");
         return gStrings.ext.GetStringFromName("uninstallAddonTooltip");
       }
     },
 
     cmd_cancelUninstallItem: {
-      isEnabled: function cmd_cancelUninstallItem_isEnabled(aAddon) {
+      isEnabled: function(aAddon) {
         if (!aAddon)
           return false;
         return isPending(aAddon, "uninstall");
       },
-      doCommand: function cmd_cancelUninstallItem_doCommand(aAddon) {
+      doCommand: function(aAddon) {
         aAddon.cancelUninstall();
       }
     },
 
     cmd_installFromFile: {
-      isEnabled: function cmd_installFromFile_isEnabled() {
+      isEnabled: function() {
         return true;
       },
-      doCommand: function cmd_installFromFile_doCommand() {
+      doCommand: function() {
         const nsIFilePicker = Ci.nsIFilePicker;
         var fp = Cc["@mozilla.org/filepicker;1"]
                    .createInstance(nsIFilePicker);
         fp.init(window,
                 gStrings.ext.GetStringFromName("installFromFile.dialogTitle"),
                 nsIFilePicker.modeOpenMultiple);
         try {
           fp.appendFilter(gStrings.ext.GetStringFromName("installFromFile.filterName"),
@@ -1291,184 +1290,184 @@ var gViewController = {
               webInstaller.onWebInstallRequested(getBrowserElement(),
                                                  document.documentURIObject,
                                                  installs);
             }
             return;
           }
 
           var file = files.getNext();
-          AddonManager.getInstallForFile(file, function cmd_installFromFile_getInstallForFile(aInstall) {
+          AddonManager.getInstallForFile(file, function(aInstall) {
             installs.push(aInstall);
             buildNextInstall();
           });
         }
 
         buildNextInstall();
       }
     },
 
     cmd_cancelOperation: {
-      isEnabled: function cmd_cancelOperation_isEnabled(aAddon) {
+      isEnabled: function(aAddon) {
         if (!aAddon)
           return false;
         return aAddon.pendingOperations != AddonManager.PENDING_NONE;
       },
-      doCommand: function cmd_cancelOperation_doCommand(aAddon) {
+      doCommand: function(aAddon) {
         if (isPending(aAddon, "install")) {
           aAddon.install.cancel();
         } else if (isPending(aAddon, "upgrade")) {
           aAddon.pendingUpgrade.install.cancel();
         } else if (isPending(aAddon, "uninstall")) {
           aAddon.cancelUninstall();
         } else if (isPending(aAddon, "enable")) {
           aAddon.userDisabled = true;
         } else if (isPending(aAddon, "disable")) {
           aAddon.userDisabled = false;
         }
       }
     },
 
     cmd_contribute: {
-      isEnabled: function cmd_contribute_isEnabled(aAddon) {
+      isEnabled: function(aAddon) {
         if (!aAddon)
           return false;
         return ("contributionURL" in aAddon && aAddon.contributionURL);
       },
-      doCommand: function cmd_contribute_doCommand(aAddon) {
+      doCommand: function(aAddon) {
         openURL(aAddon.contributionURL);
       }
     },
 
     cmd_askToActivateItem: {
-      isEnabled: function cmd_askToActivateItem_isEnabled(aAddon) {
+      isEnabled: function(aAddon) {
         if (!aAddon)
           return false;
         let addonType = AddonManager.addonTypes[aAddon.type];
         return ((addonType.flags & AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE) &&
                 hasPermission(aAddon, "ask_to_activate"));
       },
-      doCommand: function cmd_askToActivateItem_doCommand(aAddon) {
+      doCommand: function(aAddon) {
         aAddon.userDisabled = AddonManager.STATE_ASK_TO_ACTIVATE;
       }
     },
 
     cmd_alwaysActivateItem: {
-      isEnabled: function cmd_alwaysActivateItem_isEnabled(aAddon) {
+      isEnabled: function(aAddon) {
         if (!aAddon)
           return false;
         let addonType = AddonManager.addonTypes[aAddon.type];
         return ((addonType.flags & AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE) &&
                 hasPermission(aAddon, "enable"));
       },
-      doCommand: function cmd_alwaysActivateItem_doCommand(aAddon) {
+      doCommand: function(aAddon) {
         aAddon.userDisabled = false;
       }
     },
 
     cmd_neverActivateItem: {
-      isEnabled: function cmd_neverActivateItem_isEnabled(aAddon) {
+      isEnabled: function(aAddon) {
         if (!aAddon)
           return false;
         let addonType = AddonManager.addonTypes[aAddon.type];
         return ((addonType.flags & AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE) &&
                 hasPermission(aAddon, "disable"));
       },
-      doCommand: function cmd_neverActivateItem_doCommand(aAddon) {
+      doCommand: function(aAddon) {
         aAddon.userDisabled = true;
       }
     },
 
     cmd_experimentsLearnMore: {
-      isEnabled: function cmd_experimentsLearnMore_isEnabled() {
+      isEnabled: function() {
         let mainWindow = getMainWindow();
         return mainWindow && "switchToTabHavingURI" in mainWindow;
       },
-      doCommand: function cmd_experimentsLearnMore_doCommand() {
+      doCommand: function() {
         let url = Services.prefs.getCharPref("toolkit.telemetry.infoURL");
         openOptionsInTab(url);
       },
     },
 
     cmd_experimentsOpenTelemetryPreferences: {
-      isEnabled: function cmd_experimentsOpenTelemetryPreferences_isEnabled() {
+      isEnabled: function() {
         return !!getMainWindowWithPreferencesPane();
       },
-      doCommand: function cmd_experimentsOpenTelemetryPreferences_doCommand() {
+      doCommand: function() {
         let mainWindow = getMainWindowWithPreferencesPane();
         mainWindow.openAdvancedPreferences("dataChoicesTab");
       },
     },
 
     cmd_showUnsignedExtensions: {
-      isEnabled: function cmd_showUnsignedExtensions_isEnabled() {
+      isEnabled: function() {
         return true;
       },
-      doCommand: function cmd_showUnsignedExtensions_doCommand() {
+      doCommand: function() {
         gViewController.loadView("addons://list/extension?unsigned=true");
       },
     },
 
     cmd_showAllExtensions: {
-      isEnabled: function cmd_showUnsignedExtensions_isEnabled() {
+      isEnabled: function() {
         return true;
       },
-      doCommand: function cmd_showUnsignedExtensions_doCommand() {
+      doCommand: function() {
         gViewController.loadView("addons://list/extension");
       },
     },
   },
 
-  supportsCommand: function gVC_supportsCommand(aCommand) {
+  supportsCommand: function(aCommand) {
     return (aCommand in this.commands);
   },
 
-  isCommandEnabled: function gVC_isCommandEnabled(aCommand) {
+  isCommandEnabled: function(aCommand) {
     if (!this.supportsCommand(aCommand))
       return false;
     var addon = this.currentViewObj.getSelectedAddon();
     return this.commands[aCommand].isEnabled(addon);
   },
 
-  updateCommands: function gVC_updateCommands() {
+  updateCommands: function() {
     // wait until the view is initialized
     if (!this.currentViewObj)
       return;
     var addon = this.currentViewObj.getSelectedAddon();
     for (let commandId in this.commands)
       this.updateCommand(commandId, addon);
   },
 
-  updateCommand: function gVC_updateCommand(aCommandId, aAddon) {
+  updateCommand: function(aCommandId, aAddon) {
     if (typeof aAddon == "undefined")
       aAddon = this.currentViewObj.getSelectedAddon();
     var cmd = this.commands[aCommandId];
     var cmdElt = document.getElementById(aCommandId);
     cmdElt.setAttribute("disabled", !cmd.isEnabled(aAddon));
     if ("getTooltip" in cmd) {
       let tooltip = cmd.getTooltip(aAddon);
       if (tooltip)
         cmdElt.setAttribute("tooltiptext", tooltip);
       else
         cmdElt.removeAttribute("tooltiptext");
     }
   },
 
-  doCommand: function gVC_doCommand(aCommand, aAddon) {
+  doCommand: function(aCommand, aAddon) {
     if (!this.supportsCommand(aCommand))
       return;
     var cmd = this.commands[aCommand];
     if (!aAddon)
       aAddon = this.currentViewObj.getSelectedAddon();
     if (!cmd.isEnabled(aAddon))
       return;
     cmd.doCommand(aAddon);
   },
 
-  onEvent: function gVC_onEvent() {}
+  onEvent: function() {}
 };
 
 function hasInlineOptions(aAddon) {
   return (aAddon.optionsType == AddonManager.OPTIONS_TYPE_INLINE ||
           aAddon.optionsType == AddonManager.OPTIONS_TYPE_INLINE_INFO);
 }
 
 function openOptionsInTab(optionsURL) {
@@ -1657,17 +1656,17 @@ function sortElements(aElements, aSortBy
       aSortFuncs[i] = uiStateCompare;
     else if (DATE_FIELDS.indexOf(sortBy) != -1)
       aSortFuncs[i] = dateCompare;
     else if (NUMERIC_FIELDS.indexOf(sortBy) != -1)
       aSortFuncs[i] = numberCompare;
   }
 
 
-  aElements.sort(function elementsSort(a, b) {
+  aElements.sort(function(a, b) {
     if (!aAscending)
       [a, b] = [b, a];
 
     for (let i = 0; i < aSortFuncs.length; i++) {
       var sortBy = aSortBy[i];
       var aValue = getValue(a, sortBy);
       var bValue = getValue(b, sortBy);
 
@@ -1702,25 +1701,25 @@ function sortList(aList, aSortBy, aAscen
   for (let element of elements)
     aList.appendChild(element);
 }
 
 function getAddonsAndInstalls(aType, aCallback) {
   let addons = null, installs = null;
   let types = (aType != null) ? [aType] : null;
 
-  AddonManager.getAddonsByTypes(types, function getAddonsAndInstalls_getAddonsByTypes(aAddonsList) {
+  AddonManager.getAddonsByTypes(types, function(aAddonsList) {
     addons = aAddonsList.filter(a => !a.hidden);
     if (installs != null)
       aCallback(addons, installs);
   });
 
-  AddonManager.getInstallsByTypes(types, function getAddonsAndInstalls_getInstallsByTypes(aInstallsList) {
+  AddonManager.getInstallsByTypes(types, function(aInstallsList) {
     // skip over upgrade installs and non-active installs
-    installs = aInstallsList.filter(function installsFilter(aInstall) {
+    installs = aInstallsList.filter(function(aInstall) {
       return !(aInstall.existingAddon ||
                aInstall.state == AddonManager.STATE_AVAILABLE);
     });
 
     if (addons != null)
       aCallback(addons, installs)
   });
 }
@@ -1740,17 +1739,17 @@ function doPendingUninstalls(aListBox) {
   for (let addon of items)
     addon.uninstall();
 }
 
 var gCategories = {
   node: null,
   _search: null,
 
-  initialize: function gCategories_initialize() {
+  initialize: function() {
     this.node = document.getElementById("categories");
     this._search = this.get("addons://search/");
 
     var types = AddonManager.addonTypes;
     for (var type in types)
       this.onTypeAdded(types[type]);
 
     AddonManager.addTypeListener(this);
@@ -1760,42 +1759,41 @@ var gCategories = {
     } catch (e) { }
 
     // If there was no last view or no existing category matched the last view
     // then the list will default to selecting the search category and we never
     // want to show that as the first view so switch to the default category
     if (!this.node.selectedItem || this.node.selectedItem == this._search)
       this.node.value = gViewDefault;
 
-    var self = this;
-    this.node.addEventListener("select", function node_onSelected() {
-      self.maybeHideSearch();
-      gViewController.loadView(self.node.selectedItem.value);
+    this.node.addEventListener("select", () => {
+      this.maybeHideSearch();
+      gViewController.loadView(this.node.selectedItem.value);
     }, false);
 
-    this.node.addEventListener("click", function node_onClicked(aEvent) {
-      var selectedItem = self.node.selectedItem;
+    this.node.addEventListener("click", (aEvent) => {
+      var selectedItem = this.node.selectedItem;
       if (aEvent.target.localName == "richlistitem" &&
           aEvent.target == selectedItem) {
         var viewId = selectedItem.value;
 
         if (gViewController.parseViewId(viewId).type == "search") {
           viewId += encodeURIComponent(gHeader.searchQuery);
         }
 
         gViewController.loadView(viewId);
       }
     }, false);
   },
 
-  shutdown: function gCategories_shutdown() {
+  shutdown: function() {
     AddonManager.removeTypeListener(this);
   },
 
-  _insertCategory: function gCategories_insertCategory(aId, aName, aView, aPriority, aStartHidden) {
+  _insertCategory: function(aId, aName, aView, aPriority, aStartHidden) {
     // If this category already exists then don't re-add it
     if (document.getElementById("category-" + aId))
       return;
 
     var category = document.createElement("richlistitem");
     category.setAttribute("id", "category-" + aId);
     category.setAttribute("value", aView);
     category.setAttribute("class", "category");
@@ -1819,29 +1817,29 @@ var gCategories = {
       // alphabetically then this is the insertion point
       if (String.localeCompare(aName, node.getAttribute("name")) < 0)
         break;
     }
 
     this.node.insertBefore(category, node);
   },
 
-  _removeCategory: function gCategories_removeCategory(aId) {
+  _removeCategory: function(aId) {
     var category = document.getElementById("category-" + aId);
     if (!category)
       return;
 
     // If this category is currently selected then switch to the default view
     if (this.node.selectedItem == category)
       gViewController.replaceView(gViewDefault);
 
     this.node.removeChild(category);
   },
 
-  onTypeAdded: function gCategories_onTypeAdded(aType) {
+  onTypeAdded: function(aType) {
     // Ignore types that we don't have a view object for
     if (!(aType.viewType in gViewController.viewObjects))
       return;
 
     var aViewId = "addons://" + aType.viewType + "/" + aType.id;
 
     var startHidden = false;
     if (aType.flags & AddonManager.TYPE_UI_HIDE_EMPTY) {
@@ -1849,77 +1847,76 @@ var gCategories = {
       try {
         startHidden = Services.prefs.getBoolPref(prefName);
       }
       catch (e) {
         // Default to hidden
         startHidden = true;
       }
 
-      var self = this;
       gPendingInitializations++;
-      getAddonsAndInstalls(aType.id, function onTypeAdded_getAddonsAndInstalls(aAddonsList, aInstallsList) {
+      getAddonsAndInstalls(aType.id, (aAddonsList, aInstallsList) => {
         var hidden = (aAddonsList.length == 0 && aInstallsList.length == 0);
-        var item = self.get(aViewId);
+        var item = this.get(aViewId);
 
         // Don't load view that is becoming hidden
         if (hidden && aViewId == gViewController.currentViewId)
           gViewController.loadView(gViewDefault);
 
         item.hidden = hidden;
         Services.prefs.setBoolPref(prefName, hidden);
 
         if (aAddonsList.length > 0 || aInstallsList.length > 0) {
           notifyInitialized();
           return;
         }
 
         gEventManager.registerInstallListener({
-          onDownloadStarted: function gCategories_onDownloadStarted(aInstall) {
+          onDownloadStarted: function(aInstall) {
             this._maybeShowCategory(aInstall);
           },
 
-          onInstallStarted: function gCategories_onInstallStarted(aInstall) {
+          onInstallStarted: function(aInstall) {
             this._maybeShowCategory(aInstall);
           },
 
-          onInstallEnded: function gCategories_onInstallEnded(aInstall, aAddon) {
+          onInstallEnded: function(aInstall, aAddon) {
             this._maybeShowCategory(aAddon);
           },
 
-          onExternalInstall: function gCategories_onExternalInstall(aAddon, aExistingAddon, aRequiresRestart) {
+          onExternalInstall: function(aAddon, aExistingAddon, aRequiresRestart) {
             this._maybeShowCategory(aAddon);
           },
 
-          _maybeShowCategory: function gCategories_maybeShowCategory(aAddon) {
+          _maybeShowCategory: aAddon => {
             if (aType.id == aAddon.type) {
-              self.get(aViewId).hidden = false;
+              this.get(aViewId).hidden = false;
               Services.prefs.setBoolPref(prefName, false);
               gEventManager.unregisterInstallListener(this);
             }
           }
         });
 
         notifyInitialized();
       });
     }
 
     this._insertCategory(aType.id, aType.name, aViewId, aType.uiPriority,
                          startHidden);
   },
 
-  onTypeRemoved: function gCategories_onTypeRemoved(aType) {
+  onTypeRemoved: function(aType) {
     this._removeCategory(aType.id);
   },
 
   get selected() {
     return this.node.selectedItem ? this.node.selectedItem.value : null;
   },
 
-  select: function gCategories_select(aId, aPreviousView) {
+  select: function(aId, aPreviousView) {
     var view = gViewController.parseViewId(aId);
     if (view.type == "detail" && aPreviousView) {
       aId = aPreviousView;
       view = gViewController.parseViewId(aPreviousView);
     }
     aId = aId.replace(/\?.*/, "");
 
     Services.prefs.setCharPref(PREF_UI_LASTCATEGORY, aId);
@@ -1943,70 +1940,70 @@ var gCategories = {
       this.node.selectedItem = item;
       this.node.suppressOnSelect = false;
       this.node.ensureElementIsVisible(item);
 
       this.maybeHideSearch();
     }
   },
 
-  get: function gCategories_get(aId) {
+  get: function(aId) {
     var items = document.getElementsByAttribute("value", aId);
     if (items.length)
       return items[0];
     return null;
   },
 
-  setBadge: function gCategories_setBadge(aId, aCount) {
+  setBadge: function(aId, aCount) {
     let item = this.get(aId);
     if (item)
       item.badgeCount = aCount;
   },
 
-  maybeHideSearch: function gCategories_maybeHideSearch() {
+  maybeHideSearch: function() {
     var view = gViewController.parseViewId(this.node.selectedItem.value);
     this._search.disabled = view.type != "search";
   }
 };
 
 
 var gHeader = {
   _search: null,
   _dest: "",
 
-  initialize: function gHeader_initialize() {
+  initialize: function() {
     this._search = document.getElementById("header-search");
 
-    this._search.addEventListener("command", function search_onCommand(aEvent) {
+    this._search.addEventListener("command", function(aEvent) {
       var query = aEvent.target.value;
       if (query.length == 0)
         return;
 
       gViewController.loadView("addons://search/" + encodeURIComponent(query));
     }, false);
 
     function updateNavButtonVisibility() {
       var shouldShow = gHeader.shouldShowNavButtons;
       document.getElementById("back-btn").hidden = !shouldShow;
       document.getElementById("forward-btn").hidden = !shouldShow;
     }
 
-    window.addEventListener("focus", function window_onFocus(aEvent) {
+    window.addEventListener("focus", function(aEvent) {
       if (aEvent.target == window)
         updateNavButtonVisibility();
     }, false);
 
     updateNavButtonVisibility();
   },
 
-  focusSearchBox: function gHeader_focusSearchBox() {
+  focusSearchBox: function() {
     this._search.focus();
   },
 
-  onKeyPress: function gHeader_onKeyPress(aEvent) {
+  onKeyPress: function(aEvent) {
     if (String.fromCharCode(aEvent.charCode) == "/") {
       this.focusSearchBox();
       return;
     }
   },
 
   get shouldShowNavButtons() {
     var docshellItem = window.QueryInterface(Ci.nsIInterfaceRequestor)
@@ -2056,17 +2053,17 @@ var gDiscoverView = {
   // after this then it must also load the discover homepage
   loaded: false,
   _browser: null,
   _loading: null,
   _error: null,
   homepageURL: null,
   _loadListeners: [],
 
-  initialize: function gDiscoverView_initialize() {
+  initialize: function() {
     this.enabled = isDiscoverEnabled();
     if (!this.enabled) {
       gCategories.get("addons://discover/").hidden = true;
       return;
     }
 
     this.node = document.getElementById("discover-view");
     this._loading = document.getElementById("discover-loading");
@@ -2078,43 +2075,41 @@ var gDiscoverView = {
       compatMode = "ignore";
     else if (AddonManager.strictCompatibility)
       compatMode = "strict";
 
     var url = Services.prefs.getCharPref(PREF_DISCOVERURL);
     url = url.replace("%COMPATIBILITY_MODE%", compatMode);
     url = Services.urlFormatter.formatURL(url);
 
-    var self = this;
-
-    function setURL(aURL) {
+    let setURL = (aURL) => {
       try {
-        self.homepageURL = Services.io.newURI(aURL, null, null);
+        this.homepageURL = Services.io.newURI(aURL, null, null);
       } catch (e) {
-        self.showError();
+        this.showError();
         notifyInitialized();
         return;
       }
 
-      self._browser.homePage = self.homepageURL.spec;
-      self._browser.addProgressListener(self);
-
-      if (self.loaded)
-        self._loadURL(self.homepageURL.spec, false, notifyInitialized);
+      this._browser.homePage = this.homepageURL.spec;
+      this._browser.addProgressListener(this);
+
+      if (this.loaded)
+        this._loadURL(this.homepageURL.spec, false, notifyInitialized);
       else
         notifyInitialized();
     }
 
     if (Services.prefs.getBoolPref(PREF_GETADDONS_CACHE_ENABLED) == false) {
       setURL(url);
       return;
     }
 
     gPendingInitializations++;
-    AddonManager.getAllAddons(function initialize_getAllAddons(aAddons) {
+    AddonManager.getAllAddons(function(aAddons) {
       var list = {};
       for (let addon of aAddons) {
         var prefName = PREF_GETADDONS_CACHE_ID_ENABLED.replace("%ID%",
                                                                addon.id);
         try {
           if (!Services.prefs.getBoolPref(prefName))
             continue;
         } catch (e) { }
@@ -2127,26 +2122,26 @@ var gDiscoverView = {
           isBlocklisted: addon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED
         }
       }
 
       setURL(url + "#" + JSON.stringify(list));
     });
   },
 
-  destroy: function gDiscoverView_destroy() {
+  destroy: function() {
     try {
       this._browser.removeProgressListener(this);
     }
     catch (e) {
       // Ignore the case when the listener wasn't already registered
     }
   },
 
-  show: function gDiscoverView_show(aParam, aRequest, aState, aIsRefresh) {
+  show: function(aParam, aRequest, aState, aIsRefresh) {
     gViewController.updateCommands();
 
     // If we're being told to load a specific URL then just do that
     if (aState && "url" in aState) {
       this.loaded = true;
       this._loadURL(aState.url);
     }
 
@@ -2167,51 +2162,51 @@ var gDiscoverView = {
       this._loadListeners.push(gViewController.notifyViewChanged.bind(gViewController));
       return;
     }
 
     this._loadURL(this.homepageURL.spec, aIsRefresh,
                   gViewController.notifyViewChanged.bind(gViewController));
   },
 
-  canRefresh: function gDiscoverView_canRefresh() {
+  canRefresh: function() {
     if (this._browser.currentURI &&
         this._browser.currentURI.spec == this._browser.homePage)
       return false;
     return true;
   },
 
-  refresh: function gDiscoverView_refresh(aParam, aRequest, aState) {
+  refresh: function(aParam, aRequest, aState) {
     this.show(aParam, aRequest, aState, true);
   },
 
-  hide: function gDiscoverView_hide() { },
-
-  showError: function gDiscoverView_showError() {
+  hide: function() { },
+
+  showError: function() {
     this.node.selectedPanel = this._error;
   },
 
-  _loadURL: function gDiscoverView_loadURL(aURL, aKeepHistory, aCallback) {
+  _loadURL: function(aURL, aKeepHistory, aCallback) {
     if (this._browser.currentURI.spec == aURL) {
       if (aCallback)
         aCallback();
       return;
     }
 
     if (aCallback)
       this._loadListeners.push(aCallback);
 
     var flags = 0;
     if (!aKeepHistory)
       flags |= Ci.nsIWebNavigation.LOAD_FLAGS_REPLACE_HISTORY;
 
     this._browser.loadURIWithFlags(aURL, flags);
   },
 
-  onLocationChange: function gDiscoverView_onLocationChange(aWebProgress, aRequest, aLocation, aFlags) {
+  onLocationChange: function(aWebProgress, aRequest, aLocation, aFlags) {
     // Ignore the about:blank load
     if (aLocation.spec == "about:blank")
       return;
 
     // When using the real session history the inner-frame will update the
     // session history automatically, if using the fake history though it must
     // be manually updated
     if (gHistory == FakeHistory) {
@@ -2239,31 +2234,31 @@ var gDiscoverView = {
         (!this.homepageURL.schemeIs("https") || aLocation.schemeIs("https")))
       return;
 
     // Canceling the request will send an error to onStateChange which will show
     // the error page
     aRequest.cancel(Components.results.NS_BINDING_ABORTED);
   },
 
-  onSecurityChange: function gDiscoverView_onSecurityChange(aWebProgress, aRequest, aState) {
+  onSecurityChange: function(aWebProgress, aRequest, aState) {
     // Don't care about security if the page is not https
     if (!this.homepageURL.schemeIs("https"))
       return;
 
     // If the request was secure then it is ok
     if (aState & Ci.nsIWebProgressListener.STATE_IS_SECURE)
       return;
 
     // Canceling the request will send an error to onStateChange which will show
     // the error page
     aRequest.cancel(Components.results.NS_BINDING_ABORTED);
   },
 
-  onStateChange: function gDiscoverView_onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) {
+  onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus) {
     let transferStart = Ci.nsIWebProgressListener.STATE_IS_DOCUMENT |
                         Ci.nsIWebProgressListener.STATE_IS_REQUEST |
                         Ci.nsIWebProgressListener.STATE_TRANSFERRING;
     // Once transferring begins show the content
     if (aStateFlags & transferStart)
       this.node.selectedPanel = this._browser;
 
     // Only care about the network events
@@ -2297,23 +2292,23 @@ var gDiscoverView = {
 
     var listeners = this._loadListeners;
     this._loadListeners = [];
 
     for (let listener of listeners)
       listener();
   },
 
-  onProgressChange: function gDiscoverView_onProgressChange() { },
-  onStatusChange: function gDiscoverView_onStatusChange() { },
+  onProgressChange: function() { },
+  onStatusChange: function() { },
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
                                          Ci.nsISupportsWeakReference]),
 
-  getSelectedAddon: function gDiscoverView_getSelectedAddon() {
+  getSelectedAddon: function() {
     return null;
   }
 };
 
 
 var gCachedAddons = {};
 
 var gSearchView = {
@@ -2323,17 +2318,17 @@ var gSearchView = {
   _loading: null,
   _listBox: null,
   _emptyNotice: null,
   _allResultsLink: null,
   _lastQuery: null,
   _lastRemoteTotal: 0,
   _pendingSearches: 0,
 
-  initialize: function gSearchView_initialize() {
+  initialize: function() {
     this.node = document.getElementById("search-view");
     this._filter = document.getElementById("search-filter-radiogroup");
     this._sorters = document.getElementById("search-sorters");
     this._sorters.handler = this;
     this._loading = document.getElementById("search-loading");
     this._listBox = document.getElementById("search-list");
     this._emptyNotice = document.getElementById("search-list-empty");
     this._allResultsLink = document.getElementById("search-allresults-link");
@@ -2347,26 +2342,26 @@ var gSearchView = {
         if (item)
           item.showInDetailView();
       }
     }, false);
 
     this._filter.addEventListener("command", () => this.updateView(), false);
   },
 
-  shutdown: function gSearchView_shutdown() {
+  shutdown: function() {
     if (AddonRepository.isSearching)
       AddonRepository.cancelSearch();
   },
 
   get isSearching() {
     return this._pendingSearches > 0;
   },
 
-  show: function gSearchView_show(aQuery, aRequest) {
+  show: function(aQuery, aRequest) {
     gEventManager.registerInstallListener(this);
 
     this.showEmptyNotice(false);
     this.showAllResultsLink(0);
     this.showLoading(true);
     this._sorters.showprice = false;
 
     gHeader.searchQuery = aQuery;
@@ -2379,61 +2374,60 @@ var gSearchView = {
     this._lastQuery = aQuery;
 
     if (AddonRepository.isSearching)
       AddonRepository.cancelSearch();
 
     while (this._listBox.firstChild.localName == "richlistitem")
       this._listBox.removeChild(this._listBox.firstChild);
 
-    var self = this;
     gCachedAddons = {};
     this._pendingSearches = 2;
     this._sorters.setSort("relevancescore", false);
 
     var elements = [];
 
-    function createSearchResults(aObjsList, aIsInstall, aIsRemote) {
+    let createSearchResults = (aObjsList, aIsInstall, aIsRemote) => {
       for (let index in aObjsList) {
         let obj = aObjsList[index];
         let score = aObjsList.length - index;
         if (!aIsRemote && aQuery.length > 0) {
-          score = self.getMatchScore(obj, aQuery);
+          score = this.getMatchScore(obj, aQuery);
           if (score == 0)
             continue;
         }
 
         let item = createItem(obj, aIsInstall, aIsRemote);
         item.setAttribute("relevancescore", score);
         if (aIsRemote) {
           gCachedAddons[obj.id] = obj;
           if (obj.purchaseURL)
-            self._sorters.showprice = true;
+            this._sorters.showprice = true;
         }
 
         elements.push(item);
       }
     }
 
-    function finishSearch(createdCount) {
+    let finishSearch = (createdCount) => {
       if (elements.length > 0) {
-        sortElements(elements, [self._sorters.sortBy], self._sorters.ascending);
+        sortElements(elements, [this._sorters.sortBy], this._sorters.ascending);
         for (let element of elements)
-          self._listBox.insertBefore(element, self._listBox.lastChild);
-        self.updateListAttributes();
+          this._listBox.insertBefore(element, this._listBox.lastChild);
+        this.updateListAttributes();
       }
 
-      self._pendingSearches--;
-      self.updateView();
-
-      if (!self.isSearching)
+      this._pendingSearches--;
+      this.updateView();
+
+      if (!this.isSearching)
         gViewController.notifyViewChanged();
     }
 
-    getAddonsAndInstalls(null, function show_getAddonsAndInstalls(aAddons, aInstalls) {
+    getAddonsAndInstalls(null, function(aAddons, aInstalls) {
       if (gViewController && aRequest != gViewController.currentViewRequest)
         return;
 
       createSearchResults(aAddons, false, false);
       createSearchResults(aInstalls, true, false);
       finishSearch();
     });
 
@@ -2443,47 +2437,47 @@ var gSearchView = {
     } catch(e) {}
 
     if (maxRemoteResults <= 0) {
       finishSearch(0);
       return;
     }
 
     AddonRepository.searchAddons(aQuery, maxRemoteResults, {
-      searchFailed: function show_SearchFailed() {
+      searchFailed: () => {
         if (gViewController && aRequest != gViewController.currentViewRequest)
           return;
 
-        self._lastRemoteTotal = 0;
+        this._lastRemoteTotal = 0;
 
         // XXXunf Better handling of AMO search failure. See bug 579502
         finishSearch(0); // Silently fail
       },
 
-      searchSucceeded: function show_SearchSucceeded(aAddonsList, aAddonCount, aTotalResults) {
+      searchSucceeded: (aAddonsList, aAddonCount, aTotalResults) => {
         if (gViewController && aRequest != gViewController.currentViewRequest)
           return;
 
         if (aTotalResults > maxRemoteResults)
-          self._lastRemoteTotal = aTotalResults;
+          this._lastRemoteTotal = aTotalResults;
         else
-          self._lastRemoteTotal = 0;
+          this._lastRemoteTotal = 0;
 
         var createdCount = createSearchResults(aAddonsList, false, true);
         finishSearch(createdCount);
       }
     });
   },
 
-  showLoading: function gSearchView_showLoading(aLoading) {
+  showLoading: function(aLoading) {
     this._loading.hidden = !aLoading;
     this._listBox.hidden = aLoading;
   },
 
-  updateView: function gSearchView_updateView() {
+  updateView: function() {
     var showLocal = this._filter.value == "local";
 
     if (!showLocal && !AddonManager.isInstallEnabled("application/x-xpinstall"))
       showLocal = true;
 
     this._listBox.setAttribute("local", showLocal);
     this._listBox.setAttribute("remote", !showLocal);
 
@@ -2501,31 +2495,31 @@ var gSearchView = {
 
       this.showEmptyNotice(isEmpty);
       this.showAllResultsLink(this._lastRemoteTotal);
     }
 
     gViewController.updateCommands();
   },
 
-  hide: function gSearchView_hide() {
+  hide: function() {
     gEventManager.unregisterInstallListener(this);
     doPendingUninstalls(this._listBox);
   },
 
-  getMatchScore: function gSearchView_getMatchScore(aObj, aQuery) {
+  getMatchScore: function(aObj, aQuery) {
     var score = 0;
     score += this.calculateMatchScore(aObj.name, aQuery,
                                       SEARCH_SCORE_MULTIPLIER_NAME);
     score += this.calculateMatchScore(aObj.description, aQuery,
                                       SEARCH_SCORE_MULTIPLIER_DESCRIPTION);
     return score;
   },
 
-  calculateMatchScore: function gSearchView_calculateMatchScore(aStr, aQuery, aMultiplier) {
+  calculateMatchScore: function(aStr, aQuery, aMultiplier) {
     var score = 0;
     if (!aStr || aQuery.length == 0)
       return score;
 
     aStr = aStr.trim().toLocaleLowerCase();
     var haystack = aStr.split(/\s+/);
     var needles = aQuery.split(/\s+/);
 
@@ -2547,38 +2541,38 @@ var gSearchView = {
     // give progressively higher score for longer queries, since longer queries
     // are more likely to be unique and therefore more relevant.
     if (needles.length > 1 && aStr.indexOf(aQuery) != -1)
       score += needles.length;
 
     return score * aMultiplier;
   },
 
-  showEmptyNotice: function gSearchView_showEmptyNotice(aShow) {
+  showEmptyNotice: function(aShow) {
     this._emptyNotice.hidden = !aShow;
     this._listBox.hidden = aShow;
   },
 
-  showAllResultsLink: function gSearchView_showAllResultsLink(aTotalResults) {
+  showAllResultsLink: function(aTotalResults) {
     if (aTotalResults == 0) {
       this._allResultsLink.hidden = true;
       return;
     }
 
     var linkStr = gStrings.ext.GetStringFromName("showAllSearchResults");
     linkStr = PluralForm.get(aTotalResults, linkStr);
     linkStr = linkStr.replace("#1", aTotalResults);
     this._allResultsLink.setAttribute("value", linkStr);
 
     this._allResultsLink.setAttribute("href",
                                       AddonRepository.getSearchURL(this._lastQuery));
     this._allResultsLink.hidden = false;
  },
 
-  updateListAttributes: function gSearchView_updateListAttributes() {
+  updateListAttributes: function() {
     var item = this._listBox.querySelector("richlistitem[remote='true'][first]");
     if (item)
       item.removeAttribute("first");
     item = this._listBox.querySelector("richlistitem[remote='true'][last]");
     if (item)
       item.removeAttribute("last");
     var items = this._listBox.querySelectorAll("richlistitem[remote='true']");
     if (items.length > 0) {
@@ -2595,51 +2589,51 @@ var gSearchView = {
     items = this._listBox.querySelectorAll("richlistitem:not([remote='true'])");
     if (items.length > 0) {
       items[0].setAttribute("first", true);
       items[items.length - 1].setAttribute("last", true);
     }
 
   },
 
-  onSortChanged: function gSearchView_onSortChanged(aSortBy, aAscending) {
+  onSortChanged: function(aSortBy, aAscending) {
     var footer = this._listBox.lastChild;
     this._listBox.removeChild(footer);
 
     sortList(this._listBox, aSortBy, aAscending);
     this.updateListAttributes();
 
     this._listBox.appendChild(footer);
   },
 
-  onDownloadCancelled: function gSearchView_onDownloadCancelled(aInstall) {
+  onDownloadCancelled: function(aInstall) {
     this.removeInstall(aInstall);
   },
 
-  onInstallCancelled: function gSearchView_onInstallCancelled(aInstall) {
+  onInstallCancelled: function(aInstall) {
     this.removeInstall(aInstall);
   },
 
-  removeInstall: function gSearchView_removeInstall(aInstall) {
+  removeInstall: function(aInstall) {
     for (let item of this._listBox.childNodes) {
       if (item.mInstall == aInstall) {
         this._listBox.removeChild(item);
         return;
       }
     }
   },
 
-  getSelectedAddon: function gSearchView_getSelectedAddon() {
+  getSelectedAddon: function() {
     var item = this._listBox.selectedItem;
     if (item)
       return item.mAddon;
     return null;
   },
 
-  getListItemForID: function gSearchView_getListItemForID(aId) {
+  getListItemForID: function(aId) {
     var listitem = this._listBox.firstChild;
     while (listitem) {
       if (listitem.getAttribute("status") == "installed" && listitem.mAddon.id == aId)
         return listitem;
       listitem = listitem.nextSibling;
     }
     return null;
   }
@@ -2647,25 +2641,24 @@ var gSearchView = {
 
 
 var gListView = {
   node: null,
   _listBox: null,
   _emptyNotice: null,
   _type: null,
 
-  initialize: function gListView_initialize() {
+  initialize: function() {
     this.node = document.getElementById("list-view");
     this._listBox = document.getElementById("addon-list");
     this._emptyNotice = document.getElementById("addon-list-empty");
 
-    var self = this;
-    this._listBox.addEventListener("keydown", function listbox_onKeydown(aEvent) {
+    this._listBox.addEventListener("keydown", (aEvent) => {
       if (aEvent.keyCode == aEvent.DOM_VK_RETURN) {
-        var item = self._listBox.selectedItem;
+        var item = this._listBox.selectedItem;
         if (item)
           item.showInDetailView();
       }
     }, false);
 
     document.getElementById("signing-learn-more").setAttribute("href",
       Services.urlFormatter.formatURLPref("app.support.baseURL") + "unsigned-addons");
 
@@ -2680,17 +2673,17 @@ var gListView = {
     try {
       document.getElementById("signing-dev-manual-link").setAttribute("href",
         Services.prefs.getCharPref("xpinstall.signatures.devInfoURL"));
     } catch (e) {
       document.getElementById("signing-dev-info").hidden = true;
     }
   },
 
-  show: function gListView_show(aType, aRequest) {
+  show: function(aType, aRequest) {
     let showOnlyDisabledUnsigned = false;
     if (aType.endsWith("?unsigned=true")) {
       aType = aType.replace(/\?.*/, "");
       showOnlyDisabledUnsigned = true;
     }
 
     if (!(aType in AddonManager.addonTypes))
       throw Components.Exception("Attempting to show unknown type " + aType, Cr.NS_ERROR_INVALID_ARG);
@@ -2728,22 +2721,22 @@ var gListView = {
       this.filterDisabledUnsigned(showOnlyDisabledUnsigned);
 
       gEventManager.registerInstallListener(this);
       gViewController.updateCommands();
       gViewController.notifyViewChanged();
     });
   },
 
-  hide: function gListView_hide() {
+  hide: function() {
     gEventManager.unregisterInstallListener(this);
     doPendingUninstalls(this._listBox);
   },
 
-  filterDisabledUnsigned: function gListView_filterDisabledUnsigned(aFilter = true) {
+  filterDisabledUnsigned: function(aFilter = true) {
     let foundDisabledUnsigned = false;
 
     if (SIGNING_REQUIRED) {
       for (let item of this._listBox.childNodes) {
         if (!isCorrectlySigned(item.mAddon))
           foundDisabledUnsigned = true;
         else
           item.hidden = aFilter;
@@ -2752,67 +2745,67 @@ var gListView = {
 
     document.getElementById("show-disabled-unsigned-extensions").hidden =
       aFilter || !foundDisabledUnsigned;
 
     document.getElementById("show-all-extensions").hidden = !aFilter;
     document.getElementById("disabled-unsigned-addons-info").hidden = !aFilter;
   },
 
-  showEmptyNotice: function gListView_showEmptyNotice(aShow) {
+  showEmptyNotice: function(aShow) {
     this._emptyNotice.hidden = !aShow;
     this._listBox.hidden = aShow;
   },
 
-  onSortChanged: function gListView_onSortChanged(aSortBy, aAscending) {
+  onSortChanged: function(aSortBy, aAscending) {
     sortList(this._listBox, aSortBy, aAscending);
   },
 
-  onExternalInstall: function gListView_onExternalInstall(aAddon, aExistingAddon, aRequiresRestart) {
+  onExternalInstall: function(aAddon, aExistingAddon, aRequiresRestart) {
     // The existing list item will take care of upgrade installs
     if (aExistingAddon)
       return;
 
     if (aAddon.hidden)
       return;
 
     this.addItem(aAddon);
   },
 
-  onDownloadStarted: function gListView_onDownloadStarted(aInstall) {
+  onDownloadStarted: function(aInstall) {
     this.addItem(aInstall, true);
   },
 
-  onInstallStarted: function gListView_onInstallStarted(aInstall) {
+  onInstallStarted: function(aInstall) {
     this.addItem(aInstall, true);
   },
 
-  onDownloadCancelled: function gListView_onDownloadCancelled(aInstall) {
+  onDownloadCancelled: function(aInstall) {
     this.removeItem(aInstall, true);
   },
 
-  onInstallCancelled: function gListView_onInstallCancelled(aInstall) {
+  onInstallCancelled: function(aInstall) {
     this.removeItem(aInstall, true);
   },
 
-  onInstallEnded: function gListView_onInstallEnded(aInstall) {
+  onInstallEnded: function(aInstall) {
     // Remove any install entries for upgrades, their status will appear against
     // the existing item
     if (aInstall.existingAddon)
       this.removeItem(aInstall, true);
 
     if (aInstall.addon.type == "experiment") {
       let item = this.getListItemForID(aInstall.addon.id);
       if (item) {
         item.endDate = getExperimentEndDate(aInstall.addon);
       }
     }
   },
 
-  addItem: function gListView_addItem(aObj, aIsInstall) {
+  addItem: function(aObj, aIsInstall) {
     if (aObj.type != this._type)
       return;
 
     if (aIsInstall && aObj.existingAddon)
       return;
 
     let prop = aIsInstall ? "mInstall" : "mAddon";
     for (let item of this._listBox.childNodes) {
@@ -2820,36 +2813,36 @@ var gListView = {
         return;
     }
 
     let item = createItem(aObj, aIsInstall);
     this._listBox.insertBefore(item, this._listBox.firstChild);
     this.showEmptyNotice(false);
   },
 
-  removeItem: function gListView_removeItem(aObj, aIsInstall) {
+  removeItem: function(aObj, aIsInstall) {
     let prop = aIsInstall ? "mInstall" : "mAddon";
 
     for (let item of this._listBox.childNodes) {
       if (item[prop] == aObj) {
         this._listBox.removeChild(item);
         this.showEmptyNotice(this._listBox.itemCount == 0);
         return;
       }
     }
   },
 
-  getSelectedAddon: function gListView_getSelectedAddon() {
+  getSelectedAddon: function() {
     var item = this._listBox.selectedItem;
     if (item)
       return item.mAddon;
     return null;
   },
 
-  getListItemForID: function gListView_getListItemForID(aId) {
+  getListItemForID: function(aId) {
     var listitem = this._listBox.firstChild;
     while (listitem) {
       if (listitem.getAttribute("status") == "installed" && listitem.mAddon.id == aId)
         return listitem;
       listitem = listitem.nextSibling;
     }
     return null;
   }
@@ -2857,36 +2850,35 @@ var gListView = {
 
 
 var gDetailView = {
   node: null,
   _addon: null,
   _loadingTimer: null,
   _autoUpdate: null,
 
-  initialize: function gDetailView_initialize() {
+  initialize: function() {
     this.node = document.getElementById("detail-view");
 
     this._autoUpdate = document.getElementById("detail-autoUpdate");
 
-    var self = this;
-    this._autoUpdate.addEventListener("command", function autoUpdate_onCommand() {
-      self._addon.applyBackgroundUpdates = self._autoUpdate.value;
+    this._autoUpdate.addEventListener("command", () => {
+      this._addon.applyBackgroundUpdates = this._autoUpdate.value;
     }, true);
   },
 
-  shutdown: function gDetailView_shutdown() {
+  shutdown: function() {
     AddonManager.removeManagerListener(this);
   },
 
-  onUpdateModeChanged: function gDetailView_onUpdateModeChanged() {
+  onUpdateModeChanged: function() {
     this.onPropertyChanged(["applyBackgroundUpdates"]);
   },
 
-  _updateView: function gDetailView_updateView(aAddon, aIsRemote, aScrollToPreferences) {
+  _updateView: function(aAddon, aIsRemote, aScrollToPreferences) {
     AddonManager.addManagerListener(this);
     this.clearLoading();
 
     this._addon = aAddon;
     gEventManager.registerAddonListener(this, aAddon.id);
     gEventManager.registerInstallListener(this);
 
     this.node.setAttribute("type", aAddon.type);
@@ -3087,70 +3079,69 @@ var gDetailView = {
         let timeString = gStrings.ext.GetStringFromName(timeKey);
         timeMessage = PluralForm.get(days, timeString)
                                 .replace("#1", days);
       }
 
       document.getElementById("detail-experiment-time").value = timeMessage;
     }
 
-    this.fillSettingsRows(aScrollToPreferences, (function updateView_fillSettingsRows() {
+    this.fillSettingsRows(aScrollToPreferences, (function() {
       this.updateState();
       gViewController.notifyViewChanged();
     }).bind(this));
   },
 
-  show: function gDetailView_show(aAddonId, aRequest) {
+  show: function(aAddonId, aRequest) {
     let index = aAddonId.indexOf("/preferences");
     let scrollToPreferences = false;
     if (index >= 0) {
       aAddonId = aAddonId.substring(0, index);
       scrollToPreferences = true;
     }
 
-    var self = this;
-    this._loadingTimer = setTimeout(function loadTimeOutTimer() {
-      self.node.setAttribute("loading-extended", true);
+    this._loadingTimer = setTimeout(() => {
+      this.node.setAttribute("loading-extended", true);
     }, LOADING_MSG_DELAY);
 
     var view = gViewController.currentViewId;
 
-    AddonManager.getAddonByID(aAddonId, function show_getAddonByID(aAddon) {
+    AddonManager.getAddonByID(aAddonId, (aAddon) => {
       if (gViewController && aRequest != gViewController.currentViewRequest)
         return;
 
       if (aAddon) {
-        self._updateView(aAddon, false, scrollToPreferences);
+        this._updateView(aAddon, false, scrollToPreferences);
         return;
       }
 
       // Look for an add-on pending install
-      AddonManager.getAllInstalls(function show_getAllInstalls(aInstalls) {
+      AddonManager.getAllInstalls(aInstalls => {
         for (let install of aInstalls) {
           if (install.state == AddonManager.STATE_INSTALLED &&
               install.addon.id == aAddonId) {
-            self._updateView(install.addon, false);
+            this._updateView(install.addon, false);
             return;
           }
         }
 
         if (aAddonId in gCachedAddons) {
-          self._updateView(gCachedAddons[aAddonId], true);
+          this._updateView(gCachedAddons[aAddonId], true);
           return;
         }
 
         // This might happen due to session restore restoring us back to an
         // add-on that doesn't exist but otherwise shouldn't normally happen.
         // Either way just revert to the default view.
         gViewController.replaceView(gViewDefault);
       });
     });
   },
 
-  hide: function gDetailView_hide() {
+  hide: function() {
     AddonManager.removeManagerListener(this);
     this.clearLoading();
     if (this._addon) {
       if (hasInlineOptions(this._addon)) {
         Services.obs.notifyObservers(document,
                                      AddonManager.OPTIONS_NOTIFICATION_HIDDEN,
                                      this._addon.id);
       }
@@ -3160,17 +3151,17 @@ var gDetailView = {
       this._addon = null;
 
       // Flush the preferences to disk so they survive any crash
       if (this.node.getElementsByTagName("setting").length)
         Services.prefs.savePrefFile(null);
     }
   },
 
-  updateState: function gDetailView_updateState() {
+  updateState: function() {
     gViewController.updateCommands();
 
     var pending = this._addon.pendingOperations;
     if (pending != AddonManager.PENDING_NONE) {
       this.node.removeAttribute("notification");
 
       var pending = null;
       const PENDING_OPERATIONS = ["enable", "disable", "install", "uninstall",
@@ -3298,33 +3289,33 @@ var gDetailView = {
       menulist.classList.add('no-auto-hide');
     } else {
       menulist.hidden = true;
     }
 
     this.node.setAttribute("active", this._addon.isActive);
   },
 
-  clearLoading: function gDetailView_clearLoading() {
+  clearLoading: function() {
     if (this._loadingTimer) {
       clearTimeout(this._loadingTimer);
       this._loadingTimer = null;
     }
 
     this.node.removeAttribute("loading-extended");
   },
 
-  emptySettingsRows: function gDetailView_emptySettingsRows() {
+  emptySettingsRows: function() {
     var lastRow = document.getElementById("detail-downloads");
     var rows = lastRow.parentNode;
     while (lastRow.nextSibling)
       rows.removeChild(rows.lastChild);
   },
 
-  fillSettingsRows: function gDetailView_fillSettingsRows(aScrollToPreferences, aCallback) {
+  fillSettingsRows: function(aScrollToPreferences, aCallback) {
     this.emptySettingsRows();
     if (!hasInlineOptions(this._addon)) {
       if (aCallback)
         aCallback();
       return;
     }
 
     // This function removes and returns the text content of aNode without
@@ -3344,17 +3335,17 @@ var gDetailView = {
     }
 
     var rows = document.getElementById("detail-downloads").parentNode;
 
     try {
       var xhr = new XMLHttpRequest();
       xhr.open("GET", this._addon.optionsURL, true);
       xhr.responseType = "xml";
-      xhr.onload = (function fillSettingsRows_onload() {
+      xhr.onload = (function() {
         var xml = xhr.responseXML;
         var settings = xml.querySelectorAll(":root > setting");
 
         var firstSetting = null;
         for (var setting of settings) {
 
           var desc = stripTextNodes(setting).trim();
           if (!setting.hasAttribute("desc"))
@@ -3399,357 +3390,354 @@ var gDetailView = {
                                        AddonManager.OPTIONS_NOTIFICATION_DISPLAYED,
                                        this._addon.id);
           if (aScrollToPreferences)
             gDetailView.scrollToPreferencesRows();
         }
         if (aCallback)
           aCallback();
       }).bind(this);
-      xhr.onerror = function fillSettingsRows_onerror(aEvent) {
+      xhr.onerror = function(aEvent) {
         Cu.reportError("Error " + aEvent.target.status +
                        " occurred while receiving " + this._addon.optionsURL);
         if (aCallback)
           aCallback();
       };
       xhr.send();
     } catch(e) {
       Cu.reportError(e);
       if (aCallback)
         aCallback();
     }
   },
 
-  scrollToPreferencesRows: function gDetailView_scrollToPreferencesRows() {
+  scrollToPreferencesRows: function() {
     // We find this row, rather than remembering it from above,
     // in case it has been changed by the observers.
     let firstRow = gDetailView.node.querySelector('setting[first-row="true"]');
     if (firstRow) {
       let top = firstRow.boxObject.y;
       top -= parseInt(window.getComputedStyle(firstRow, null).getPropertyValue("margin-top"));
 
       let detailViewBoxObject = gDetailView.node.boxObject;
       top -= detailViewBoxObject.y;
 
       detailViewBoxObject.scrollTo(0, top);
     }
   },
 
-  getSelectedAddon: function gDetailView_getSelectedAddon() {
+  getSelectedAddon: function() {
     return this._addon;
   },
 
-  onEnabling: function gDetailView_onEnabling() {
+  onEnabling: function() {
     this.updateState();
   },
 
-  onEnabled: function gDetailView_onEnabled() {
+  onEnabled: function() {
     this.updateState();
     this.fillSettingsRows();
   },
 
-  onDisabling: function gDetailView_onDisabling(aNeedsRestart) {
+  onDisabling: function(aNeedsRestart) {
     this.updateState();
     if (!aNeedsRestart && hasInlineOptions(this._addon)) {
       Services.obs.notifyObservers(document,
                                    AddonManager.OPTIONS_NOTIFICATION_HIDDEN,
                                    this._addon.id);
     }
   },
 
-  onDisabled: function gDetailView_onDisabled() {
+  onDisabled: function() {
     this.updateState();
     this.emptySettingsRows();
   },
 
-  onUninstalling: function gDetailView_onUninstalling() {
+  onUninstalling: function() {
     this.updateState();
   },
 
-  onUninstalled: function gDetailView_onUninstalled() {
+  onUninstalled: function() {
     gViewController.popState();
   },
 
-  onOperationCancelled: function gDetailView_onOperationCancelled() {
+  onOperationCancelled: function() {
     this.updateState();
   },
 
-  onPropertyChanged: function gDetailView_onPropertyChanged(aProperties) {
+  onPropertyChanged: function(aProperties) {
     if (aProperties.indexOf("applyBackgroundUpdates") != -1) {
       this._autoUpdate.value = this._addon.applyBackgroundUpdates;
       let hideFindUpdates = AddonManager.shouldAutoUpdate(this._addon);
       document.getElementById("detail-findUpdates-btn").hidden = hideFindUpdates;
     }
 
     if (aProperties.indexOf("appDisabled") != -1 ||
         aProperties.indexOf("signedState") != -1 ||
         aProperties.indexOf("userDisabled") != -1)
       this.updateState();
   },
 
-  onExternalInstall: function gDetailView_onExternalInstall(aAddon, aExistingAddon, aNeedsRestart) {
+  onExternalInstall: function(aAddon, aExistingAddon, aNeedsRestart) {
     // Only care about upgrades for the currently displayed add-on
     if (!aExistingAddon || aExistingAddon.id != this._addon.id)
       return;
 
     if (!aNeedsRestart)
       this._updateView(aAddon, false);
     else
       this.updateState();
   },
 
-  onInstallCancelled: function gDetailView_onInstallCancelled(aInstall) {
+  onInstallCancelled: function(aInstall) {
     if (aInstall.addon.id == this._addon.id)
       gViewController.popState();
   }
 };
 
 
 var gUpdatesView = {
   node: null,
   _listBox: null,
   _emptyNotice: null,
   _sorters: null,
   _updateSelected: null,
   _categoryItem: null,
 
-  initialize: function gUpdatesView_initialize() {
+  initialize: function() {
     this.node = document.getElementById("updates-view");
     this._listBox = document.getElementById("updates-list");
     this._emptyNotice = document.getElementById("updates-list-empty");
     this._sorters = document.getElementById("updates-sorters");
     this._sorters.handler = this;
 
     this._categoryItem = gCategories.get("addons://updates/available");
 
     this._updateSelected = document.getElementById("update-selected-btn");
-    this._updateSelected.addEventListener("command", function updateSelected_onCommand() {
+    this._updateSelected.addEventListener("command", function() {
       gUpdatesView.installSelected();
     }, false);
 
     this.updateAvailableCount(true);
 
     AddonManager.addAddonListener(this);
     AddonManager.addInstallListener(this);
   },
 
-  shutdown: function gUpdatesView_shutdown() {
+  shutdown: function() {
     AddonManager.removeAddonListener(this);
     AddonManager.removeInstallListener(this);
   },
 
-  show: function gUpdatesView_show(aType, aRequest) {
+  show: function(aType, aRequest) {
     document.getElementById("empty-availableUpdates-msg").hidden = aType != "available";
     document.getElementById("empty-recentUpdates-msg").hidden = aType != "recent";
     this.showEmptyNotice(false);
 
     while (this._listBox.itemCount > 0)
       this._listBox.removeItemAt(0);
 
     this.node.setAttribute("updatetype", aType);
     if (aType == "recent")
       this._showRecentUpdates(aRequest);
     else
       this._showAvailableUpdates(false, aRequest);
   },
 
-  hide: function gUpdatesView_hide() {
+  hide: function() {
     this._updateSelected.hidden = true;
     this._categoryItem.disabled = this._categoryItem.badgeCount == 0;
     doPendingUninstalls(this._listBox);
   },
 
-  _showRecentUpdates: function gUpdatesView_showRecentUpdates(aRequest) {
-    var self = this;
-    AddonManager.getAllAddons(function showRecentUpdates_getAllAddons(aAddonsList) {
+  _showRecentUpdates: function(aRequest) {
+    AddonManager.getAllAddons((aAddonsList) => {
       if (gViewController && aRequest != gViewController.currentViewRequest)
         return;
 
       var elements = [];
       let threshold = Date.now() - UPDATES_RECENT_TIMESPAN;
       for (let addon of aAddonsList) {
         if (addon.hidden || !addon.updateDate || addon.updateDate.getTime() < threshold)
           continue;
 
         elements.push(createItem(addon));
       }
 
-      self.showEmptyNotice(elements.length == 0);
+      this.showEmptyNotice(elements.length == 0);
       if (elements.length > 0) {
-        sortElements(elements, [self._sorters.sortBy], self._sorters.ascending);
+        sortElements(elements, [this._sorters.sortBy], this._sorters.ascending);
         for (let element of elements)
-          self._listBox.appendChild(element);
+          this._listBox.appendChild(element);
       }
 
       gViewController.notifyViewChanged();
     });
   },
 
-  _showAvailableUpdates: function gUpdatesView_showAvailableUpdates(aIsRefresh, aRequest) {
+  _showAvailableUpdates: function(aIsRefresh, aRequest) {
     /* Disable the Update Selected button so it can't get clicked
        before everything is initialized asynchronously.
        It will get re-enabled by maybeDisableUpdateSelected(). */
     this._updateSelected.disabled = true;
 
-    var self = this;
-    AddonManager.getAllInstalls(function showAvailableUpdates_getAllInstalls(aInstallsList) {
+    AddonManager.getAllInstalls((aInstallsList) => {
       if (!aIsRefresh && gViewController && aRequest &&
           aRequest != gViewController.currentViewRequest)
         return;
 
       if (aIsRefresh) {
-        self.showEmptyNotice(false);
-        self._updateSelected.hidden = true;
-
-        while (self._listBox.childNodes.length > 0)
-          self._listBox.removeChild(self._listBox.firstChild);
+        this.showEmptyNotice(false);
+        this._updateSelected.hidden = true;
+
+        while (this._listBox.childNodes.length > 0)
+          this._listBox.removeChild(this._listBox.firstChild);
       }
 
       var elements = [];
 
       for (let install of aInstallsList) {
-        if (!self.isManualUpdate(install))
+        if (!this.isManualUpdate(install))
           continue;
 
         let item = createItem(install.existingAddon);
         item.setAttribute("upgrade", true);
-        item.addEventListener("IncludeUpdateChanged", function item_onIncludeUpdateChanged() {
-          self.maybeDisableUpdateSelected();
+        item.addEventListener("IncludeUpdateChanged", () => {
+          this.maybeDisableUpdateSelected();
         }, false);
         elements.push(item);
       }
 
-      self.showEmptyNotice(elements.length == 0);
+      this.showEmptyNotice(elements.length == 0);
       if (elements.length > 0) {
-        self._updateSelected.hidden = false;
-        sortElements(elements, [self._sorters.sortBy], self._sorters.ascending);
+        this._updateSelected.hidden = false;
+        sortElements(elements, [this._sorters.sortBy], this._sorters.ascending);
         for (let element of elements)
-          self._listBox.appendChild(element);
+          this._listBox.appendChild(element);
       }
 
       // ensure badge count is in sync
-      self._categoryItem.badgeCount = self._listBox.itemCount;
+      this._categoryItem.badgeCount = this._listBox.itemCount;
 
       gViewController.notifyViewChanged();
     });
   },
 
-  showEmptyNotice: function gUpdatesView_showEmptyNotice(aShow) {
+  showEmptyNotice: function(aShow) {
     this._emptyNotice.hidden = !aShow;
     this._listBox.hidden = aShow;
   },
 
-  isManualUpdate: function gUpdatesView_isManualUpdate(aInstall, aOnlyAvailable) {
+  isManualUpdate: function(aInstall, aOnlyAvailable) {
     var isManual = aInstall.existingAddon &&
                    !AddonManager.shouldAutoUpdate(aInstall.existingAddon);
     if (isManual && aOnlyAvailable)
       return isInState(aInstall, "available");
     return isManual;
   },
 
-  maybeRefresh: function gUpdatesView_maybeRefresh() {
+  maybeRefresh: function() {
     if (gViewController.currentViewId == "addons://updates/available")
       this._showAvailableUpdates(true);
     this.updateAvailableCount();
   },
 
-  updateAvailableCount: function gUpdatesView_updateAvailableCount(aInitializing) {
+  updateAvailableCount: function(aInitializing) {
     if (aInitializing)
       gPendingInitializations++;
-    var self = this;
-    AddonManager.getAllInstalls(function updateAvailableCount_getAllInstalls(aInstallsList) {
-      var count = aInstallsList.filter(function installListFilter(aInstall) {
-        return self.isManualUpdate(aInstall, true);
+    AddonManager.getAllInstalls((aInstallsList) => {
+      var count = aInstallsList.filter(aInstall => {
+        return this.isManualUpdate(aInstall, true);
       }).length;
-      self._categoryItem.disabled = gViewController.currentViewId != "addons://updates/available" &&
+      this._categoryItem.disabled = gViewController.currentViewId != "addons://updates/available" &&
                                     count == 0;
-      self._categoryItem.badgeCount = count;
+      this._categoryItem.badgeCount = count;
       if (aInitializing)
         notifyInitialized();
     });
   },
 
-  maybeDisableUpdateSelected: function gUpdatesView_maybeDisableUpdateSelected() {
+  maybeDisableUpdateSelected: function() {
     for (let item of this._listBox.childNodes) {
       if (item.includeUpdate) {
         this._updateSelected.disabled = false;
         return;
       }
     }
     this._updateSelected.disabled = true;
   },
 
-  installSelected: function gUpdatesView_installSelected() {
+  installSelected: function() {
     for (let item of this._listBox.childNodes) {
       if (item.includeUpdate)
         item.upgrade();
     }
 
     this._updateSelected.disabled = true;
   },
 
-  getSelectedAddon: function gUpdatesView_getSelectedAddon() {
+  getSelectedAddon: function() {
     var item = this._listBox.selectedItem;
     if (item)
       return item.mAddon;
     return null;
   },
 
-  getListItemForID: function gUpdatesView_getListItemForID(aId) {
+  getListItemForID: function(aId) {
     var listitem = this._listBox.firstChild;
     while (listitem) {
       if (listitem.mAddon.id == aId)
         return listitem;
       listitem = listitem.nextSibling;
     }
     return null;
   },
 
-  onSortChanged: function gUpdatesView_onSortChanged(aSortBy, aAscending) {
+  onSortChanged: function(aSortBy, aAscending) {
     sortList(this._listBox, aSortBy, aAscending);
   },
 
-  onNewInstall: function gUpdatesView_onNewInstall(aInstall) {
+  onNewInstall: function(aInstall) {
     if (!this.isManualUpdate(aInstall))
       return;
     this.maybeRefresh();
   },
 
-  onInstallStarted: function gUpdatesView_onInstallStarted(aInstall) {
+  onInstallStarted: function(aInstall) {
     this.updateAvailableCount();
   },
 
-  onInstallCancelled: function gUpdatesView_onInstallCancelled(aInstall) {
+  onInstallCancelled: function(aInstall) {
     if (!this.isManualUpdate(aInstall))
       return;
     this.maybeRefresh();
   },
 
-  onPropertyChanged: function gUpdatesView_onPropertyChanged(aAddon, aProperties) {
+  onPropertyChanged: function(aAddon, aProperties) {
     if (aProperties.indexOf("applyBackgroundUpdates") != -1)
       this.updateAvailableCount();
   }
 };
 
 function debuggingPrefChanged() {
   gViewController.updateState();
   gViewController.updateCommands();
   gViewController.notifyViewChanged();
 }
 
 var gDragDrop = {
-  onDragOver: function gDragDrop_onDragOver(aEvent) {
+  onDragOver: function(aEvent) {
     var types = aEvent.dataTransfer.types;
     if (types.contains("text/uri-list") ||
         types.contains("text/x-moz-url") ||
         types.contains("application/x-moz-file"))
       aEvent.preventDefault();
   },
 
-  onDrop: function gDragDrop_onDrop(aEvent) {
+  onDrop: function(aEvent) {
     var dataTransfer = aEvent.dataTransfer;
     var urls = [];
 
     // Convert every dropped item into a url
     for (var i = 0; i < dataTransfer.mozItemCount; i++) {
       var url = dataTransfer.mozGetDataAt("text/uri-list", i);
       if (url) {
         urls.push(url);
@@ -3780,25 +3768,19 @@ var gDragDrop = {
                              getService(Ci.amIWebInstallListener);
           webInstaller.onWebInstallRequested(getBrowserElement(),
                                              document.documentURIObject,
                                              installs);
         }
         return;
       }
 
-      AddonManager.getInstallForURL(urls[pos++], function onDrop_getInstallForURL(aInstall) {
+      AddonManager.getInstallForURL(urls[pos++], function(aInstall) {
         installs.push(aInstall);
         buildNextInstall();
       }, "application/x-xpinstall");
     }
 
     buildNextInstall();
 
     aEvent.preventDefault();
   }
 };
-
-#ifdef MOZ_REQUIRE_SIGNING
-const SIGNING_REQUIRED = true;
-#else
-const SIGNING_REQUIRED = Services.prefs.getBoolPref("xpinstall.signatures.required");
-#endif
--- a/toolkit/mozapps/extensions/content/extensions.xml
+++ b/toolkit/mozapps/extensions/content/extensions.xml
@@ -1119,28 +1119,27 @@
             this._description.value = this.mAddon.description;
           else
             this._description.hidden = true;
 
           if (!("applyBackgroundUpdates" in this.mAddon) ||
               (this.mAddon.applyBackgroundUpdates == AddonManager.AUTOUPDATE_DISABLE ||
                (this.mAddon.applyBackgroundUpdates == AddonManager.AUTOUPDATE_DEFAULT &&
                 !AddonManager.autoUpdateDefault))) {
-            var self = this;
-            AddonManager.getAllInstalls(function(aInstallsList) {
+            AddonManager.getAllInstalls(aInstallsList => {
               // This can return after the binding has been destroyed,
               // so try to detect that and return early
-              if (!("onNewInstall" in self))
+              if (!("onNewInstall" in this))
                 return;
               for (let install of aInstallsList) {
                 if (install.existingAddon &&
-                    install.existingAddon.id == self.mAddon.id &&
+                    install.existingAddon.id == this.mAddon.id &&
                     install.state == AddonManager.STATE_AVAILABLE) {
-                  self.onNewInstall(install);
-                  self.onIncludeUpdateChanged();
+                  this.onNewInstall(install);
+                  this.onIncludeUpdateChanged();
                 }
               }
             });
           }
         ]]></body>
       </method>
 
       <method name="_showStatus">
@@ -1408,60 +1407,59 @@
             }
           }
         ]]></body>
       </method>
 
       <method name="_fetchReleaseNotes">
         <parameter name="aURI"/>
         <body><![CDATA[
-          var self = this;
           if (!aURI || this._relNotesLoaded) {
             sendToggleEvent();
             return;
           }
 
           var relNotesData = null, transformData = null;
 
           this._relNotesLoaded = true;
           this._relNotesLoading.hidden = false;
           this._relNotesError.hidden = true;
 
-          function sendToggleEvent() {
+          let sendToggleEvent = () => {
             var event = document.createEvent("Events");
             event.initEvent("RelNotesToggle", true, true);
-            self.dispatchEvent(event);
+            this.dispatchEvent(event);
           }
 
-          function showRelNotes() {
+          let showRelNotes = () => {
             if (!relNotesData || !transformData)
               return;
 
-            self._relNotesLoading.hidden = true;
+            this._relNotesLoading.hidden = true;
 
             var processor = Components.classes["@mozilla.org/document-transformer;1?type=xslt"]
                                       .createInstance(Components.interfaces.nsIXSLTProcessor);
             processor.flags |= Components.interfaces.nsIXSLTProcessorPrivate.DISABLE_ALL_LOADS;
 
             processor.importStylesheet(transformData);
             var fragment = processor.transformToFragment(relNotesData, document);
-            self._relNotes.appendChild(fragment);
-            if (self.hasAttribute("show-relnotes")) {
-              var container = self._relNotesContainer;
+            this._relNotes.appendChild(fragment);
+            if (this.hasAttribute("show-relnotes")) {
+              var container = this._relNotesContainer;
               container.style.height = container.scrollHeight + "px";
             }
             sendToggleEvent();
           }
 
-          function handleError() {
+          let handleError = () => {
             dataReq.abort();
             styleReq.abort();
-            self._relNotesLoading.hidden = true;
-            self._relNotesError.hidden = false;
-            self._relNotesLoaded = false; // allow loading to be re-tried
+            this._relNotesLoading.hidden = true;
+            this._relNotesError.hidden = false;
+            this._relNotesLoaded = false; // allow loading to be re-tried
             sendToggleEvent();
           }
 
           function handleResponse(aEvent) {
             var req = aEvent.target;
             var ct = req.getResponseHeader("content-type");
             if ((!ct || ct.indexOf("text/html") < 0) &&
                 req.responseXML &&
--- a/toolkit/mozapps/extensions/content/newaddon.js
+++ b/toolkit/mozapps/extensions/content/newaddon.js
@@ -8,17 +8,17 @@ var Cu = Components.utils;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/AddonManager.jsm");
 
 var gAddon = null;
 
 // If the user enables the add-on through some other UI close this window
 var EnableListener = {
-  onEnabling: function EnableListener_onEnabling(aAddon) {
+  onEnabling: function(aAddon) {
     if (aAddon.id == gAddon.id)
       window.close();
   }
 }
 AddonManager.addAddonListener(EnableListener);
 
 function initialize() {
   // About URIs don't implement nsIURL so we have to find the query string
@@ -33,17 +33,17 @@ function initialize() {
   let id = query.substring(3);
   if (!id) {
     window.location = "about:blank";
     return;
   }
 
   let bundle = Services.strings.createBundle("chrome://mozapps/locale/extensions/newaddon.properties");
 
-  AddonManager.getAddonByID(id, function initialize_getAddonByID(aAddon) {
+  AddonManager.getAddonByID(id, function(aAddon) {
     // If the add-on doesn't exist or it is already enabled or it cannot be
     // enabled then this UI is useless, just close it. This shouldn't normally
     // happen unless session restore restores the tab
     if (!aAddon || !aAddon.userDisabled ||
         !(aAddon.permissions & AddonManager.PERM_CAN_ENABLE)) {
       window.close();
       return;
     }
--- a/toolkit/mozapps/extensions/content/selectAddons.js
+++ b/toolkit/mozapps/extensions/content/selectAddons.js
@@ -57,27 +57,27 @@ var gAddons = {};
 
 var gChecking = {
   nodeID: "checking",
 
   _progress: null,
   _addonCount: 0,
   _completeCount: 0,
 
-  show: function gChecking_show() {
+  show: function() {
     showButtons(true, false, false, false);
     this._progress = document.getElementById("checking-progress");
 
     AddonManager.getAllAddons(aAddons => {
       if (aAddons.length == 0) {
         window.close();
         return;
       }
 
-      aAddons = aAddons.filter(function gChecking_filterAddons(aAddon) {
+      aAddons = aAddons.filter(function(aAddon) {
         if (aAddon.id == AddonManager.hotfixID) {
           return false;
         }
         if (aAddon.type == "plugin" || aAddon.type == "service")
           return false;
 
         if (aAddon.type == "theme") {
           // Don't show application shipped themes
@@ -108,32 +108,32 @@ var gChecking = {
           }
 
           addonItem.findUpdates(this, AddonManager.UPDATE_WHEN_NEW_APP_INSTALLED);
         }
       });
     });
   },
 
-  onUpdateAvailable: function gChecking_onUpdateAvailable(aAddon, aInstall) {
+  onUpdateAvailable: function(aAddon, aInstall) {
     // If the add-on can be upgraded then remember the new version
     if (aAddon.permissions & AddonManager.PERM_CAN_UPGRADE)
       gAddons[aAddon.id].install = aInstall;
   },
 
-  onUpdateFinished: function gChecking_onUpdateFinished(aAddon, aError) {
+  onUpdateFinished: function(aAddon, aError) {
     this._completeCount++;
     this._progress.value = this._completeCount;
 
     if (this._completeCount < this._addonCount)
       return;
 
     var addons = [gAddons[id] for (id in gAddons)];
 
-    addons.sort(function sortAddons(a, b) {
+    addons.sort(function(a, b) {
       let orderA = orderForScope(a.addon.scope);
       let orderB = orderForScope(b.addon.scope);
 
       if (orderA != orderB)
         return orderA - orderB;
 
       return String.localeCompare(a.addon.name, b.addon.name);
     });
@@ -162,48 +162,48 @@ var gChecking = {
 
     showView(gSelect);
   }
 };
 
 var gSelect = {
   nodeID: "select",
 
-  show: function gSelect_show() {
+  show: function() {
     this.updateButtons();
   },
 
-  updateButtons: function gSelect_updateButtons() {
+  updateButtons: function() {
     for (let row = document.getElementById("select-rows").firstChild;
          row; row = row.nextSibling) {
       if (row.localName == "separator")
         continue;
 
       if (row.action) {
         showButtons(false, false, true, false);
         return;
       }
     }
 
     showButtons(false, false, false, true);
   },
 
-  next: function gSelect_next() {
+  next: function() {
     showView(gConfirm);
   },
 
-  done: function gSelect_done() {
+  done: function() {
     window.close();
   }
 };
 
 var gConfirm = {
   nodeID: "confirm",
 
-  show: function gConfirm_show() {
+  show: function() {
     showButtons(false, true, false, true);
 
     let box = document.getElementById("confirm-scrollbox").firstChild;
     while (box) {
       box.hidden = true;
       while (box.lastChild != box.firstChild)
         box.removeChild(box.lastChild);
       box = box.nextSibling;
@@ -230,25 +230,25 @@ var gConfirm = {
         item.setAttribute("active", "true");
       list.appendChild(item);
 
       if (action == "update")
         showButtons(false, true, true, false);
     }
   },
 
-  back: function gConfirm_back() {
+  back: function() {
     showView(gSelect);
   },
 
-  next: function gConfirm_next() {
+  next: function() {
     showView(gUpdate);
   },
 
-  done: function gConfirm_done() {
+  done: function() {
     for (let row = document.getElementById("select-rows").firstChild;
          row; row = row.nextSibling) {
       if (row.localName != "separator")
         row.apply();
     }
 
     window.close();
   }
@@ -257,84 +257,84 @@ var gConfirm = {
 var gUpdate = {
   nodeID: "update",
 
   _progress: null,
   _waitingCount: 0,
   _completeCount: 0,
   _errorCount: 0,
 
-  show: function gUpdate_show() {
+  show: function() {
     showButtons(true, false, false, false);
 
     this._progress = document.getElementById("update-progress");
 
     for (let row = document.getElementById("select-rows").firstChild;
          row; row = row.nextSibling) {
       if (row.localName != "separator")
         row.apply();
     }
 
     this._progress.mode = "determined";
     this._progress.max = this._waitingCount;
     this._progress.value = this._completeCount;
   },
 
-  checkComplete: function gUpdate_checkComplete() {
+  checkComplete: function() {
     this._progress.value = this._completeCount;
     if (this._completeCount < this._waitingCount)
       return;
 
     if (this._errorCount > 0) {
       showView(gErrors);
       return;
     }
 
     window.close();
   },
 
-  onDownloadStarted: function gUpdate_onDownloadStarted(aInstall) {
+  onDownloadStarted: function(aInstall) {
     this._waitingCount++;
   },
 
-  onDownloadFailed: function gUpdate_onDownloadFailed(aInstall) {
+  onDownloadFailed: function(aInstall) {
     this._errorCount++;
     this._completeCount++;
     this.checkComplete();
   },
 
-  onInstallFailed: function gUpdate_onInstallFailed(aInstall) {
+  onInstallFailed: function(aInstall) {
     this._errorCount++;
     this._completeCount++;
     this.checkComplete();
   },
 
-  onInstallEnded: function gUpdate_onInstallEnded(aInstall) {
+  onInstallEnded: function(aInstall) {
     this._completeCount++;
     this.checkComplete();
   }
 };
 
 var gErrors = {
   nodeID: "errors",
 
-  show: function gErrors_show() {
+  show: function() {
     showButtons(false, false, false, true);
   },
 
-  done: function gErrors_done() {
+  done: function() {
     window.close();
   }
 };
 
-window.addEventListener("load", function loadEventListener() {
+window.addEventListener("load", function() {
                                          showView(gChecking); }, false);
 
 // When closing the window cancel any pending or in-progress installs
-window.addEventListener("unload", function unloadEventListener() {
+window.addEventListener("unload", function() {
   for (let id in gAddons) {
     let entry = gAddons[id];
     if (!entry.install)
       return;
 
     aEntry.install.removeListener(gUpdate);
 
     if (entry.install.state != AddonManager.STATE_INSTALLED &&
--- a/toolkit/mozapps/extensions/content/update.js
+++ b/toolkit/mozapps/extensions/content/update.js
@@ -45,17 +45,17 @@ var gUpdateWizard = {
   // metadata checks, and upgraded.
   disabled: 0,
   metadataEnabled: 0,
   metadataDisabled: 0,
   upgraded: 0,
   upgradeFailed: 0,
   upgradeDeclined: 0,
 
-  init: function gUpdateWizard_init()
+  init: function()
   {
     logger = Log.repository.getLogger("addons.update-dialog");
     // XXX could we pass the addons themselves rather than the IDs?
     this.affectedAddonIDs = new Set(window.arguments[0]);
 
     try {
       this.shouldSuggestAutoChecking =
         !Services.prefs.getBoolPref(PREF_UPDATE_EXTENSIONS_ENABLED);
@@ -77,56 +77,56 @@ var gUpdateWizard = {
   },
 
   onWizardFinish: function gUpdateWizard_onWizardFinish ()
   {
     if (this.shouldSuggestAutoChecking)
       Services.prefs.setBoolPref(PREF_UPDATE_EXTENSIONS_ENABLED, this.shouldAutoCheck);
   },
 
-  _setUpButton: function gUpdateWizard_setUpButton(aButtonID, aButtonKey, aDisabled)
+  _setUpButton: function(aButtonID, aButtonKey, aDisabled)
   {
     var strings = document.getElementById("updateStrings");
     var button = document.documentElement.getButton(aButtonID);
     if (aButtonKey) {
       button.label = strings.getString(aButtonKey);
       try {
         button.setAttribute("accesskey", strings.getString(aButtonKey + "Accesskey"));
       }
       catch (e) {
       }
     }
     button.disabled = aDisabled;
   },
 
-  setButtonLabels: function gUpdateWizard_setButtonLabels(aBackButton, aBackButtonIsDisabled,
+  setButtonLabels: function(aBackButton, aBackButtonIsDisabled,
                              aNextButton, aNextButtonIsDisabled,
                              aCancelButton, aCancelButtonIsDisabled)
   {
     this._setUpButton("back", aBackButton, aBackButtonIsDisabled);
     this._setUpButton("next", aNextButton, aNextButtonIsDisabled);
     this._setUpButton("cancel", aCancelButton, aCancelButtonIsDisabled);
   },
 
   /////////////////////////////////////////////////////////////////////////////
   // Update Errors
   errorItems: [],
 
-  checkForErrors: function gUpdateWizard_checkForErrors(aElementIDToShow)
+  checkForErrors: function(aElementIDToShow)
   {
     if (this.errorItems.length > 0)
       document.getElementById(aElementIDToShow).hidden = false;
   },
 
-  onWizardClose: function gUpdateWizard_onWizardClose(aEvent)
+  onWizardClose: function(aEvent)
   {
     return this.onWizardCancel();
   },
 
-  onWizardCancel: function gUpdateWizard_onWizardCancel()
+  onWizardCancel: function()
   {
     gUpdateWizard.shuttingDown = true;
     // Allow add-ons to continue downloading and installing
     // in the background, though some may require a later restart
     // Pages that are waiting for user input go into the background
     // on cancel
     if (gMismatchPage.waiting) {
       logger.info("Dialog closed in mismatch page");
@@ -144,46 +144,46 @@ var gUpdateWizard = {
     else {
       logger.info("Dialog closed while downloading and installing updates");
     }
     return true;
   }
 };
 
 var gOfflinePage = {
-  onPageAdvanced: function gOfflinePage_onPageAdvanced()
+  onPageAdvanced: function()
   {
     Services.io.offline = false;
     return true;
   },
 
-  toggleOffline: function gOfflinePage_toggleOffline()
+  toggleOffline: function()
   {
     var nextbtn = document.documentElement.getButton("next");
     nextbtn.disabled = !nextbtn.disabled;
   }
 }
 
 // Addon listener to count addons enabled/disabled by metadata checks
 var listener = {
-  onDisabled: function listener_onDisabled(aAddon) {
+  onDisabled: function(aAddon) {
     gUpdateWizard.affectedAddonIDs.add(aAddon.id);
     gUpdateWizard.metadataDisabled++;
   },
-  onEnabled: function listener_onEnabled(aAddon) {
+  onEnabled: function(aAddon) {
     gUpdateWizard.affectedAddonIDs.delete(aAddon.id);
     gUpdateWizard.metadataEnabled++;
   }
 };
 
 var gVersionInfoPage = {
   _completeCount: 0,
   _totalCount: 0,
   _versionInfoDone: false,
-  onPageShow: Task.async(function* gVersionInfoPage_onPageShow() {
+  onPageShow: Task.async(function*() {
     gUpdateWizard.setButtonLabels(null, true,
                                   "nextButtonText", true,
                                   "cancelButtonText", false);
 
     gUpdateWizard.disabled = gUpdateWizard.affectedAddonIDs.size;
 
     // Ensure compatibility overrides are up to date before checking for
     // individual addon updates.
@@ -217,17 +217,17 @@ var gVersionInfoPage = {
     gVersionInfoPage._totalCount = gUpdateWizard.addons.length;
 
     for (let addon of gUpdateWizard.addons) {