Merge mozilla-central to mozilla-inbound
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Tue, 01 Dec 2015 15:27:23 +0100
changeset 309092 9c017873382788da0e303f4b37dee54373305bfb
parent 309091 5e8e09fa2bbf5d0c8f22a3f8a79711ff17a67af5 (current diff)
parent 309025 974fe614d5299159dc16d98d97d76af653158d29 (diff)
child 309093 1ced6fa5afed1dac982e001cd169aa4d5a307fa7
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)
milestone45.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to mozilla-inbound
--- a/b2g/config/aries/sources.xml
+++ b/b2g/config/aries/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="538c96ab7f17adbbd15b82f750e7247c5685e831"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="59c8605876736b22acaaed25be00008e452149cb"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ac7e9ae8a24ab4a3f3da801ca53f95f39a32b89f"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="538c96ab7f17adbbd15b82f750e7247c5685e831"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="59c8605876736b22acaaed25be00008e452149cb"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ac7e9ae8a24ab4a3f3da801ca53f95f39a32b89f"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gecko and Gaia -->
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="538c96ab7f17adbbd15b82f750e7247c5685e831"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="59c8605876736b22acaaed25be00008e452149cb"/>
   <!-- Gonk-specific things and forks -->
   <project name="platform_bionic" path="bionic" remote="b2g" revision="e2b3733ba3fa5e3f404e983d2e4142b1f6b1b846"/>
   <project name="platform_build" path="build" remote="b2g" revision="1b0db93fb6b870b03467aff50d6419771ba0d88c">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
   <project name="android-development" path="development" remote="b2g" revision="2bdf22305b523af644e1891b4ddfd9229336d0ce"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="660169a3d7e034a892359e39135e8c2785a6ad6f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="538c96ab7f17adbbd15b82f750e7247c5685e831"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="59c8605876736b22acaaed25be00008e452149cb"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ac7e9ae8a24ab4a3f3da801ca53f95f39a32b89f"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="5de6856fad82857028f9f059f50680a9bea5b75c"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="538c96ab7f17adbbd15b82f750e7247c5685e831"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="59c8605876736b22acaaed25be00008e452149cb"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ac7e9ae8a24ab4a3f3da801ca53f95f39a32b89f"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="5de6856fad82857028f9f059f50680a9bea5b75c"/>
--- a/b2g/config/emulator-l/sources.xml
+++ b/b2g/config/emulator-l/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="c9d4fe680662ee44a4bdea42ae00366f5df399cf">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="538c96ab7f17adbbd15b82f750e7247c5685e831"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="59c8605876736b22acaaed25be00008e452149cb"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ac7e9ae8a24ab4a3f3da801ca53f95f39a32b89f"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="5de6856fad82857028f9f059f50680a9bea5b75c"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gecko and Gaia -->
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="538c96ab7f17adbbd15b82f750e7247c5685e831"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="59c8605876736b22acaaed25be00008e452149cb"/>
   <!-- Gonk-specific things and forks -->
   <project name="platform_bionic" path="bionic" remote="b2g" revision="e2b3733ba3fa5e3f404e983d2e4142b1f6b1b846"/>
   <project name="platform_build" path="build" remote="b2g" revision="1b0db93fb6b870b03467aff50d6419771ba0d88c">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
   <project name="android-development" path="development" remote="b2g" revision="2bdf22305b523af644e1891b4ddfd9229336d0ce"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="538c96ab7f17adbbd15b82f750e7247c5685e831"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="59c8605876736b22acaaed25be00008e452149cb"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ac7e9ae8a24ab4a3f3da801ca53f95f39a32b89f"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
-        "git_revision": "538c96ab7f17adbbd15b82f750e7247c5685e831", 
+        "git_revision": "59c8605876736b22acaaed25be00008e452149cb", 
         "remote": "https://git.mozilla.org/releases/gaia.git", 
         "branch": ""
     }, 
-    "revision": "183b45c6d96733ce09aee5eb7d7882b0d81f020d", 
+    "revision": "09d11f2ffa29c5f32712084fb8ac6023056f6c24", 
     "repo_path": "integration/gaia-central"
 }
--- a/b2g/config/nexus-4-kk/sources.xml
+++ b/b2g/config/nexus-4-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="538c96ab7f17adbbd15b82f750e7247c5685e831"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="59c8605876736b22acaaed25be00008e452149cb"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ac7e9ae8a24ab4a3f3da801ca53f95f39a32b89f"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -13,17 +13,17 @@
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="660169a3d7e034a892359e39135e8c2785a6ad6f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="538c96ab7f17adbbd15b82f750e7247c5685e831"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="59c8605876736b22acaaed25be00008e452149cb"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ac7e9ae8a24ab4a3f3da801ca53f95f39a32b89f"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="5de6856fad82857028f9f059f50680a9bea5b75c"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
--- a/b2g/config/nexus-5-l/sources.xml
+++ b/b2g/config/nexus-5-l/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="c9d4fe680662ee44a4bdea42ae00366f5df399cf">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="538c96ab7f17adbbd15b82f750e7247c5685e831"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="59c8605876736b22acaaed25be00008e452149cb"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ac7e9ae8a24ab4a3f3da801ca53f95f39a32b89f"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
--- 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
@@ -8979,21 +8979,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);