Merge m-c to inbound, a=merge
authorWes Kocher <wkocher@mozilla.com>
Mon, 30 Nov 2015 17:47:00 -0800
changeset 308952 dd0db75af15ffa5beb0f74cea95c748ae4bae87f
parent 308951 a28821163fff5d0db7a5015e0eeb891b30bb38b7 (current diff)
parent 308801 a44dde7aaa7d5b80b13dc946ccbea0801f772ef7 (diff)
child 308953 0cc1efabc37f8879530fe19aeed25b6cebaef5f2
push id5513
push userraliiev@mozilla.com
push dateMon, 25 Jan 2016 13:55:34 +0000
treeherdermozilla-beta@5ee97dd05b5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone45.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to inbound, a=merge
browser/extensions/loop/.eslintignore
mobile/android/chrome/content/browser.js
--- a/.eslintignore
+++ b/.eslintignore
@@ -53,28 +53,36 @@ webapprt/**
 widget/**
 xpcom/**
 xpfe/**
 xulrunner/**
 
 # browser/ exclusions
 browser/app/**
 browser/base/**
-browser/branding/**
-browser/components/**
-browser/config/**
-browser/docs/**
+browser/components/customizableui/**
+browser/components/downloads/**
+browser/components/feeds/**
+browser/components/migration/**
+browser/components/*.js
+browser/components/places/**
+browser/components/pocket/**
+browser/components/preferences/**
+browser/components/privatebrowsing/**
+browser/components/sessionstore/**
+browser/components/shell/**
+browser/components/tabview/**
+browser/components/translation/**
+browser/components/uitour/**
 browser/experiments/**
 browser/extensions/pdfjs/**
 browser/extensions/shumway/**
 browser/fuel/**
-browser/installer/**
 browser/locales/**
 browser/modules/**
-browser/themes/**
 
 # Loop specific exclusions
 
 # This file currently uses a non-standard (and not on a standards track)
 # if statement within catch.
 browser/extensions/loop/content/modules/MozLoopWorker.js
 # This file currently uses es7 features eslint issue:
 # https://github.com/eslint/espree/issues/125
--- a/.eslintrc
+++ b/.eslintrc
@@ -1,5 +1,9 @@
 {
+  // When adding items to this file please check for effects on sub-directories.
   "plugins": [
     "mozilla"
-  ]
+  ],
+  "env": {
+    "es6": true
+  },
 }
--- 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="702773bee0b70e479ccebe5e061f571e977bc376"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="538c96ab7f17adbbd15b82f750e7247c5685e831"/>
   <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="702773bee0b70e479ccebe5e061f571e977bc376"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="538c96ab7f17adbbd15b82f750e7247c5685e831"/>
   <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="702773bee0b70e479ccebe5e061f571e977bc376"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="538c96ab7f17adbbd15b82f750e7247c5685e831"/>
   <!-- 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="702773bee0b70e479ccebe5e061f571e977bc376"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="538c96ab7f17adbbd15b82f750e7247c5685e831"/>
   <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="702773bee0b70e479ccebe5e061f571e977bc376"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="538c96ab7f17adbbd15b82f750e7247c5685e831"/>
   <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="702773bee0b70e479ccebe5e061f571e977bc376"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="538c96ab7f17adbbd15b82f750e7247c5685e831"/>
   <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="702773bee0b70e479ccebe5e061f571e977bc376"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="538c96ab7f17adbbd15b82f750e7247c5685e831"/>
   <!-- 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="702773bee0b70e479ccebe5e061f571e977bc376"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="538c96ab7f17adbbd15b82f750e7247c5685e831"/>
   <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": "702773bee0b70e479ccebe5e061f571e977bc376", 
+        "git_revision": "538c96ab7f17adbbd15b82f750e7247c5685e831", 
         "remote": "https://git.mozilla.org/releases/gaia.git", 
         "branch": ""
     }, 
-    "revision": "d8d3b630339c16b3bf5292813143da11a8bbb0f0", 
+    "revision": "183b45c6d96733ce09aee5eb7d7882b0d81f020d", 
     "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="702773bee0b70e479ccebe5e061f571e977bc376"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="538c96ab7f17adbbd15b82f750e7247c5685e831"/>
   <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="702773bee0b70e479ccebe5e061f571e977bc376"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="538c96ab7f17adbbd15b82f750e7247c5685e831"/>
   <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="702773bee0b70e479ccebe5e061f571e977bc376"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="538c96ab7f17adbbd15b82f750e7247c5685e831"/>
   <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"/>
new file mode 100644
--- /dev/null
+++ b/browser/.eslintrc
@@ -0,0 +1,6 @@
+{
+  // When adding items to this file please check for effects on sub-directories.
+  "rules": {
+    "eol-last": 2,
+  }
+}
--- a/browser/base/content/browser-addons.js
+++ b/browser/base/content/browser-addons.js
@@ -1,12 +1,12 @@
-# -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
-# 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/.
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+ * 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/. */
 
 // Removes a doorhanger notification if all of the installs it was notifying
 // about have ended in some way.
 function removeNotificationOnEnd(notification, installs) {
   let count = installs.length;
 
   function maybeRemove(install) {
     install.removeListener(this);
--- a/browser/base/content/browser-ctrlTab.js
+++ b/browser/base/content/browser-ctrlTab.js
@@ -1,15 +1,11 @@
-/*
-#ifdef 0
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* 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/.
-#endif
- */
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /**
  * Tab previews utility, produces thumbnails
  */
 var tabPreviews = {
   init: function tabPreviews_init() {
     if (this._selectedTab)
       return;
--- a/browser/base/content/browser-customization.js
+++ b/browser/base/content/browser-customization.js
@@ -1,12 +1,12 @@
-# -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
-# 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/.
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+ * 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/. */
 
 /**
  * Customization handler prepares this browser window for entering and exiting
  * customization mode by handling customizationstarting and customizationending
  * events.
  */
 var CustomizationHandler = {
   handleEvent: function(aEvent) {
--- a/browser/base/content/browser-data-submission-info-bar.js
+++ b/browser/base/content/browser-data-submission-info-bar.js
@@ -1,11 +1,11 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+/* This 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/. */
 
 /**
  * Represents an info bar that shows a data submission notification.
  */
 var gDataNotificationInfoBar = {
   _OBSERVERS: [
     "datareporting:notify-data-policy:request",
     "datareporting:notify-data-policy:close",
--- a/browser/base/content/browser-devedition.js
+++ b/browser/base/content/browser-devedition.js
@@ -1,11 +1,11 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+/* This 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/. */
 
 /**
  * Listeners for the DevEdition theme.  This adds an extra stylesheet
  * to browser.xul if a pref is set and no other themes are applied.
  */
 var DevEdition = {
   _devtoolsThemePrefName: "devtools.theme",
   styleSheetLocation: "chrome://browser/skin/devedition.css",
--- a/browser/base/content/browser-eme.js
+++ b/browser/base/content/browser-eme.js
@@ -1,12 +1,12 @@
-# -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
-# 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/.
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+ * 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/. */
 
 var gEMEHandler = {
   get uiEnabled() {
     let emeUIEnabled = Services.prefs.getBoolPref("browser.eme.ui.enabled");
     // Force-disable on WinXP:
     if (navigator.platform.toLowerCase().startsWith("win")) {
       emeUIEnabled = emeUIEnabled && parseFloat(Services.sysinfo.get("version")) >= 6;
     }
--- a/browser/base/content/browser-feeds.js
+++ b/browser/base/content/browser-feeds.js
@@ -1,12 +1,12 @@
-# -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
-# 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/.
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+ * 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/. */
 
 /**
  * The Feed Handler object manages discovery of RSS/ATOM feeds in web pages
  * and shows UI when they are discovered.
  */
 var FeedHandler = {
   /** Called when the user clicks on the Subscribe to This Page... menu item,
    * or when the user clicks the feed button when the page contains multiple
--- a/browser/base/content/browser-fullScreen.js
+++ b/browser/base/content/browser-fullScreen.js
@@ -1,12 +1,12 @@
-# -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
-# 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/.
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+ * 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/. */
 
 var FullScreen = {
   _MESSAGES: [
     "DOMFullscreen:Request",
     "DOMFullscreen:NewOrigin",
     "DOMFullscreen:Exit",
     "DOMFullscreen:Painted",
   ],
--- a/browser/base/content/browser-fullZoom.js
+++ b/browser/base/content/browser-fullZoom.js
@@ -1,15 +1,11 @@
-/*
-#ifdef 0
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* 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/.
-#endif
- */
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /**
  * Controls the "full zoom" setting and its site-specific preferences.
  */
 var FullZoom = {
   // Identifies the setting in the content prefs database.
   name: "browser.content.full-zoom",
 
--- a/browser/base/content/browser-fxaccounts.js
+++ b/browser/base/content/browser-fxaccounts.js
@@ -1,11 +1,11 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+/* This 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/. */
 
 var gFxAccounts = {
 
   PREF_SYNC_START_DOORHANGER: "services.sync.ui.showSyncStartDoorhanger",
   DOORHANGER_ACTIVATE_DELAY_MS: 5000,
   SYNC_MIGRATION_NOTIFICATION_TITLE: "fxa-migration",
 
   _initialized: false,
--- a/browser/base/content/browser-gestureSupport.js
+++ b/browser/base/content/browser-gestureSupport.js
@@ -1,11 +1,11 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+/* This 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/. */
 
 // Simple gestures support
 //
 // As per bug #412486, web content must not be allowed to receive any
 // simple gesture events.  Multi-touch gesture APIs are in their
 // infancy and we do NOT want to be forced into supporting an API that
 // will probably have to change in the future.  (The current Mac OS X
 // API is undocumented and was reverse-engineered.)  Until support is
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -1,11 +1,11 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+/* This 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/. */
 
 ////////////////////////////////////////////////////////////////////////////////
 //// StarUI
 
 var StarUI = {
   _itemId: -1,
   uri: null,
   _batching: false,
--- a/browser/base/content/browser-plugins.js
+++ b/browser/base/content/browser-plugins.js
@@ -1,12 +1,12 @@
-# -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
-# 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/.
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+ * 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/. */
 
 var gPluginHandler = {
   PREF_SESSION_PERSIST_MINUTES: "plugin.sessionPermissionNow.intervalInMinutes",
   PREF_PERSISTENT_DAYS: "plugin.persistentPermissionAlways.intervalInDays",
   MESSAGES: [
     "PluginContent:ShowClickToPlayNotification",
     "PluginContent:RemoveNotification",
     "PluginContent:UpdateHiddenPluginUI",
--- a/browser/base/content/browser-safebrowsing.js
+++ b/browser/base/content/browser-safebrowsing.js
@@ -1,11 +1,11 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+/* This 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/. */
 
 #ifdef MOZ_SAFE_BROWSING
 var gSafeBrowsing = {
 
   setReportPhishingMenu: function() {
     // A phishing page will have a specific about:blocked content documentURI
     var uri = gBrowser.currentURI;
     var isPhishingPage = uri && uri.spec.startsWith("about:blocked?e=phishingBlocked");
--- a/browser/base/content/browser-sidebar.js
+++ b/browser/base/content/browser-sidebar.js
@@ -1,11 +1,11 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+/* This 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/. */
 
 /**
  * SidebarUI controls showing and hiding the browser sidebar.
  *
  * @note
  * Some of these methods take a commandID argument - we expect to find a
  * xul:broadcaster element with the specified ID.
  * The following attributes on that element may be used and/or modified:
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -1,11 +1,11 @@
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+/* This 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/. */
 
 // the "exported" symbols
 var SocialUI,
     SocialFlyout,
     SocialMarks,
     SocialShare,
     SocialSidebar,
     SocialStatus,
--- a/browser/base/content/browser-syncui.js
+++ b/browser/base/content/browser-syncui.js
@@ -1,11 +1,11 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+/* This 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/. */
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 #ifdef MOZ_SERVICES_CLOUDSYNC
 XPCOMUtils.defineLazyModuleGetter(this, "CloudSync",
                                   "resource://gre/modules/CloudSync.jsm");
 #else
 var CloudSync = null;
--- a/browser/base/content/browser-tabview.js
+++ b/browser/base/content/browser-tabview.js
@@ -1,11 +1,11 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+/* This 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/. */
 
 var TabView = {
   _deck: null,
   _iframe: null,
   _window: null,
   _initialized: false,
   _browserKeyHandlerInitialized: false,
   _closedLastVisibleTabBeforeFrameInitialized: false,
--- a/browser/base/content/browser-thumbnails.js
+++ b/browser/base/content/browser-thumbnails.js
@@ -1,13 +1,11 @@
-#ifdef 0
 /* 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/. */
-#endif
+ * 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/. */
 
 /**
  * Keeps thumbnails of open web pages up-to-date.
  */
 var gBrowserThumbnails = {
   /**
    * Pref that controls whether we can store SSL content on disk
    */
--- a/browser/base/content/browser-trackingprotection.js
+++ b/browser/base/content/browser-trackingprotection.js
@@ -1,11 +1,11 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+/* This 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/. */
 
 var TrackingProtection = {
   MAX_INTROS: 0,
   PREF_ENABLED_GLOBALLY: "privacy.trackingprotection.enabled",
   PREF_ENABLED_IN_PRIVATE_WINDOWS: "privacy.trackingprotection.pbmode.enabled",
   enabledGlobally: false,
   enabledInPrivateWindows: false,
   container: null,
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1,12 +1,12 @@
-# -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
-# 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/.
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+ * 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/. */
 
 var Ci = Components.interfaces;
 var Cu = Components.utils;
 var Cc = Components.classes;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/NotificationDB.jsm");
 Cu.import("resource:///modules/RecentWindow.jsm");
@@ -260,41 +260,16 @@ var gInitialPages = [
   "about:blank",
   "about:newtab",
   "about:home",
   "about:privatebrowsing",
   "about:welcomeback",
   "about:sessionrestore"
 ];
 
-#include browser-addons.js
-#include browser-ctrlTab.js
-#include browser-customization.js
-#include browser-devedition.js
-#include browser-eme.js
-#include browser-feeds.js
-#include browser-fullScreen.js
-#include browser-fullZoom.js
-#include browser-gestureSupport.js
-#include browser-places.js
-#include browser-plugins.js
-#include browser-safebrowsing.js
-#include browser-sidebar.js
-#include browser-social.js
-#include browser-syncui.js
-#include browser-tabview.js
-#include browser-thumbnails.js
-#include browser-trackingprotection.js
-
-#ifdef MOZ_DATA_REPORTING
-#include browser-data-submission-info-bar.js
-#endif
-
-#include browser-fxaccounts.js
-
 XPCOMUtils.defineLazyGetter(this, "Win7Features", function () {
 #ifdef XP_WIN
   // Bug 666808 - AeroPeek support for e10s
   if (gMultiProcessBrowser)
     return null;
 
   const WINTASKBAR_CONTRACTID = "@mozilla.org/windows-taskbar;1";
   if (WINTASKBAR_CONTRACTID in Cc &&
--- a/browser/base/content/global-scripts.inc
+++ b/browser/base/content/global-scripts.inc
@@ -7,8 +7,33 @@
 <script type="application/javascript" src="chrome://global/content/viewZoomOverlay.js"/>
 <script type="application/javascript" src="chrome://browser/content/places/browserPlacesViews.js"/>
 <script type="application/javascript" src="chrome://browser/content/browser.js"/>
 <script type="application/javascript" src="chrome://browser/content/downloads/downloads.js"/>
 <script type="application/javascript" src="chrome://browser/content/downloads/indicator.js"/>
 <script type="application/javascript" src="chrome://browser/content/customizableui/panelUI.js"/>
 <script type="application/javascript" src="chrome://global/content/inlineSpellCheckUI.js"/>
 <script type="application/javascript" src="chrome://global/content/viewSourceUtils.js"/>
+
+<script type="application/javascript" src="chrome://browser/content/browser-addons.js"/>
+<script type="application/javascript" src="chrome://browser/content/browser-ctrlTab.js"/>
+<script type="application/javascript" src="chrome://browser/content/browser-customization.js"/>
+<script type="application/javascript" src="chrome://browser/content/browser-devedition.js"/>
+<script type="application/javascript" src="chrome://browser/content/browser-eme.js"/>
+<script type="application/javascript" src="chrome://browser/content/browser-feeds.js"/>
+<script type="application/javascript" src="chrome://browser/content/browser-fullScreen.js"/>
+<script type="application/javascript" src="chrome://browser/content/browser-fullZoom.js"/>
+<script type="application/javascript" src="chrome://browser/content/browser-gestureSupport.js"/>
+<script type="application/javascript" src="chrome://browser/content/browser-places.js"/>
+<script type="application/javascript" src="chrome://browser/content/browser-plugins.js"/>
+<script type="application/javascript" src="chrome://browser/content/browser-safebrowsing.js"/>
+<script type="application/javascript" src="chrome://browser/content/browser-sidebar.js"/>
+<script type="application/javascript" src="chrome://browser/content/browser-social.js"/>
+<script type="application/javascript" src="chrome://browser/content/browser-syncui.js"/>
+<script type="application/javascript" src="chrome://browser/content/browser-tabview.js"/>
+<script type="application/javascript" src="chrome://browser/content/browser-thumbnails.js"/>
+<script type="application/javascript" src="chrome://browser/content/browser-trackingprotection.js"/>
+
+#ifdef MOZ_DATA_REPORTING
+<script type="application/javascript" src="chrome://browser/content/browser-data-submission-info-bar.js"/>
+#endif
+
+<script type="application/javascript" src="chrome://browser/content/browser-fxaccounts.js"/>
--- a/browser/base/content/web-panels.xul
+++ b/browser/base/content/web-panels.xul
@@ -17,16 +17,18 @@
 ]>
 
 <page id="webpanels-window"
         xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         onload="load()" onunload="unload()">
   <script type="application/javascript" src="chrome://global/content/contentAreaUtils.js"/>
   <script type="application/javascript" src="chrome://browser/content/browser.js"/>
+  <script type="application/javascript" src="chrome://browser/content/browser-places.js"/>
+  <script type="application/javascript" src="chrome://browser/content/browser-social.js"/>
   <script type="application/javascript" src="chrome://global/content/inlineSpellCheckUI.js"/>
   <script type="application/javascript" src="chrome://browser/content/nsContextMenu.js"/>
   <script type="application/javascript" src="chrome://browser/content/web-panels.js"/>
 
   <stringbundleset id="stringbundleset"> 
     <stringbundle id="bundle_browser" src="chrome://browser/locale/browser.properties"/>
   </stringbundleset>
 
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -70,17 +70,37 @@ browser.jar:
         content/browser/aboutSocialError.xhtml        (content/aboutSocialError.xhtml)
         content/browser/aboutProviderDirectory.xhtml  (content/aboutProviderDirectory.xhtml)
         content/browser/aboutTabCrashed.css           (content/aboutTabCrashed.css)
         content/browser/aboutTabCrashed.js            (content/aboutTabCrashed.js)
         content/browser/aboutTabCrashed.xhtml         (content/aboutTabCrashed.xhtml)
 *       content/browser/browser.css                   (content/browser.css)
 *       content/browser/browser.js                    (content/browser.js)
 *       content/browser/browser.xul                   (content/browser.xul)
+        content/browser/browser-addons.js             (content/browser-addons.js)
+        content/browser/browser-ctrlTab.js            (content/browser-ctrlTab.js)
+*       content/browser/browser-customization.js      (content/browser-customization.js)
+        content/browser/browser-data-submission-info-bar.js (content/browser-data-submission-info-bar.js)
+*       content/browser/browser-devedition.js         (content/browser-devedition.js)
+        content/browser/browser-eme.js                (content/browser-eme.js)
+        content/browser/browser-feeds.js              (content/browser-feeds.js)
+*       content/browser/browser-fullScreen.js         (content/browser-fullScreen.js)
+        content/browser/browser-fullZoom.js           (content/browser-fullZoom.js)
+        content/browser/browser-fxaccounts.js         (content/browser-fxaccounts.js)
+*       content/browser/browser-gestureSupport.js     (content/browser-gestureSupport.js)
+*       content/browser/browser-places.js             (content/browser-places.js)
+*       content/browser/browser-plugins.js            (content/browser-plugins.js)
+*       content/browser/browser-safebrowsing.js       (content/browser-safebrowsing.js)
+        content/browser/browser-sidebar.js            (content/browser-sidebar.js)
+        content/browser/browser-social.js             (content/browser-social.js)
+*       content/browser/browser-syncui.js             (content/browser-syncui.js)
 *       content/browser/browser-tabPreviews.xml       (content/browser-tabPreviews.xml)
+        content/browser/browser-tabview.js            (content/browser-tabview.js)
+        content/browser/browser-thumbnails.js         (content/browser-thumbnails.js)
+        content/browser/browser-trackingprotection.js (content/browser-trackingprotection.js)
 *       content/browser/chatWindow.xul                (content/chatWindow.xul)
         content/browser/tab-content.js                (content/tab-content.js)
         content/browser/content.js                    (content/content.js)
         content/browser/social-content.js             (content/social-content.js)
         content/browser/defaultthemes/1.footer.jpg    (content/defaultthemes/1.footer.jpg)
         content/browser/defaultthemes/1.header.jpg    (content/defaultthemes/1.header.jpg)
         content/browser/defaultthemes/1.icon.jpg      (content/defaultthemes/1.icon.jpg)
         content/browser/defaultthemes/1.preview.jpg   (content/defaultthemes/1.preview.jpg)
--- a/browser/components/newtab/tests/xpcshell/test_RemoteNewTabUtils.js
+++ b/browser/components/newtab/tests/xpcshell/test_RemoteNewTabUtils.js
@@ -8,17 +8,17 @@ Cu.import("resource:///modules/RemoteNew
 Cu.import("resource://gre/modules/Promise.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 function run_test() {
   run_next_test();
 }
 
-add_task(function validCacheMidPopulation() {
+add_task(function* validCacheMidPopulation() {
   let expectedLinks = makeLinks(0, 3, 1);
 
   let provider = new TestProvider(done => done(expectedLinks));
   provider.maxNumLinks = expectedLinks.length;
 
   RemoteNewTabUtils.initWithoutProviders();
   RemoteNewTabUtils.links.addProvider(provider);
   let promise = new Promise(resolve => RemoteNewTabUtils.links.populateCache(resolve));
@@ -31,17 +31,17 @@ add_task(function validCacheMidPopulatio
   yield promise;
 
   // Once the cache is populated, we get the expected results
   do_check_true(RemoteNewTabUtils.isTopSiteGivenProvider("example1.com", provider));
   do_check_links(RemoteNewTabUtils.getProviderLinks(provider), expectedLinks);
   RemoteNewTabUtils.links.removeProvider(provider);
 });
 
-add_task(function notifyLinkDelete() {
+add_task(function* notifyLinkDelete() {
   let expectedLinks = makeLinks(0, 3, 1);
 
   let provider = new TestProvider(done => done(expectedLinks));
   provider.maxNumLinks = expectedLinks.length;
 
   RemoteNewTabUtils.initWithoutProviders();
   RemoteNewTabUtils.links.addProvider(provider);
   yield new Promise(resolve => RemoteNewTabUtils.links.populateCache(resolve));
@@ -90,17 +90,17 @@ add_task(function populatePromise() {
 
   RemoteNewTabUtils.links.populateProviderCache(provider, () => {});
   RemoteNewTabUtils.links.populateProviderCache(provider, () => {
     do_check_links(RemoteNewTabUtils.links.getLinks(), expectedLinks);
     RemoteNewTabUtils.links.removeProvider(provider);
   });
 });
 
-add_task(function isTopSiteGivenProvider() {
+add_task(function* isTopSiteGivenProvider() {
   let expectedLinks = makeLinks(0, 10, 2);
 
   // The lowest 2 frecencies have the same base domain.
   expectedLinks[expectedLinks.length - 2].url = expectedLinks[expectedLinks.length - 1].url + "Test";
 
   let provider = new TestProvider(done => done(expectedLinks));
   provider.maxNumLinks = expectedLinks.length;
 
@@ -129,17 +129,17 @@ add_task(function isTopSiteGivenProvider
 
   // Our count reached 0 for the example2.com domain so it's no longer a frecent site.
   do_check_eq(RemoteNewTabUtils.isTopSiteGivenProvider("example5.com", provider), true);
   do_check_eq(RemoteNewTabUtils.isTopSiteGivenProvider("example2.com", provider), false);
 
   RemoteNewTabUtils.links.removeProvider(provider);
 });
 
-add_task(function multipleProviders() {
+add_task(function* multipleProviders() {
   // Make each provider generate RemoteNewTabUtils.links.maxNumLinks links to check
   // that no more than maxNumLinks are actually returned in the merged list.
   let evenLinks = makeLinks(0, 2 * RemoteNewTabUtils.links.maxNumLinks, 2);
   let evenProvider = new TestProvider(done => done(evenLinks));
   let oddLinks = makeLinks(0, 2 * RemoteNewTabUtils.links.maxNumLinks - 1, 2);
   let oddProvider = new TestProvider(done => done(oddLinks));
 
   RemoteNewTabUtils.initWithoutProviders();
@@ -154,17 +154,17 @@ add_task(function multipleProviders() {
                                 1);
   do_check_eq(links.length, RemoteNewTabUtils.links.maxNumLinks);
   do_check_links(links, expectedLinks);
 
   RemoteNewTabUtils.links.removeProvider(evenProvider);
   RemoteNewTabUtils.links.removeProvider(oddProvider);
 });
 
-add_task(function changeLinks() {
+add_task(function* changeLinks() {
   let expectedLinks = makeLinks(0, 20, 2);
   let provider = new TestProvider(done => done(expectedLinks));
 
   RemoteNewTabUtils.initWithoutProviders();
   RemoteNewTabUtils.links.addProvider(provider);
 
   yield new Promise(resolve => RemoteNewTabUtils.links.populateCache(resolve));
 
@@ -212,17 +212,17 @@ add_task(function changeLinks() {
   yield RemoteNewTabUtils.links._providers.get(provider).populatePromise;
 
   // RemoteNewTabUtils.links will now repopulate its cache
   do_check_links(RemoteNewTabUtils.links.getLinks(), expectedLinks);
 
   RemoteNewTabUtils.links.removeProvider(provider);
 });
 
-add_task(function oneProviderAlreadyCached() {
+add_task(function* oneProviderAlreadyCached() {
   let links1 = makeLinks(0, 10, 1);
   let provider1 = new TestProvider(done => done(links1));
 
   RemoteNewTabUtils.initWithoutProviders();
   RemoteNewTabUtils.links.addProvider(provider1);
 
   yield new Promise(resolve => RemoteNewTabUtils.links.populateCache(resolve));
   do_check_links(RemoteNewTabUtils.links.getLinks(), links1);
@@ -233,17 +233,17 @@ add_task(function oneProviderAlreadyCach
 
   yield new Promise(resolve => RemoteNewTabUtils.links.populateCache(resolve));
   do_check_links(RemoteNewTabUtils.links.getLinks(), links2.concat(links1));
 
   RemoteNewTabUtils.links.removeProvider(provider1);
   RemoteNewTabUtils.links.removeProvider(provider2);
 });
 
-add_task(function newLowRankedLink() {
+add_task(function* newLowRankedLink() {
   // Init a provider with 10 links and make its maximum number also 10.
   let links = makeLinks(0, 10, 1);
   let provider = new TestProvider(done => done(links));
   provider.maxNumLinks = links.length;
 
   RemoteNewTabUtils.initWithoutProviders();
   RemoteNewTabUtils.links.addProvider(provider);
 
--- a/browser/components/search/test/browser_426329.js
+++ b/browser/components/search/test/browser_426329.js
@@ -143,134 +143,134 @@ function* prepareTest() {
     gURLBar.focus();
     searchBar.focus();
   } else {
     deferred.resolve();
   }
   return deferred.promise;
 }
 
-add_task(function testSetupEngine() {
+add_task(function* testSetupEngine() {
   yield promiseSetEngine();
 });
 
-add_task(function testReturn() {
+add_task(function* testReturn() {
   yield prepareTest();
   EventUtils.synthesizeKey("VK_RETURN", {});
   let event = yield promiseOnLoad();
 
   is(gBrowser.tabs.length, preTabNo, "Return key did not open new tab");
   is(event.originalTarget, preSelectedBrowser.contentDocument,
      "Return key loaded results in current tab");
   is(event.originalTarget.URL, expectedURL(searchBar.value), "testReturn opened correct search page");
 });
 
-add_task(function testAltReturn() {
+add_task(function* testAltReturn() {
   yield prepareTest();
   EventUtils.synthesizeKey("VK_RETURN", { altKey: true });
   let event = yield promiseOnLoad();
 
   is(gBrowser.tabs.length, preTabNo + 1, "Alt+Return key added new tab");
   isnot(event.originalTarget, preSelectedBrowser.contentDocument,
         "Alt+Return key loaded results in new tab");
   is(event.originalTarget, gBrowser.contentDocument,
      "Alt+Return key loaded results in foreground tab");
   is(event.originalTarget.URL, expectedURL(searchBar.value), "testAltReturn opened correct search page");
 });
 
 //Shift key has no effect for now, so skip it
-add_task(function testShiftAltReturn() {
+add_task(function* testShiftAltReturn() {
   return;
 
   yield prepareTest();
   EventUtils.synthesizeKey("VK_RETURN", { shiftKey: true, altKey: true });
   let event = yield promiseOnLoad();
 
   is(gBrowser.tabs.length, preTabNo + 1, "Shift+Alt+Return key added new tab");
   isnot(event.originalTarget, preSelectedBrowser.contentDocument,
         "Shift+Alt+Return key loaded results in new tab");
   isnot(event.originalTarget, gBrowser.contentDocument,
         "Shift+Alt+Return key loaded results in background tab");
   is(event.originalTarget.URL, expectedURL(searchBar.value), "testShiftAltReturn opened correct search page");
 });
 
-add_task(function testLeftClick() {
+add_task(function* testLeftClick() {
   yield prepareTest();
   simulateClick({ button: 0 }, searchButton);
   let event = yield promiseOnLoad();
   is(gBrowser.tabs.length, preTabNo, "LeftClick did not open new tab");
   is(event.originalTarget, preSelectedBrowser.contentDocument,
      "LeftClick loaded results in current tab");
   is(event.originalTarget.URL, expectedURL(searchBar.value), "testLeftClick opened correct search page");
 });
 
-add_task(function testMiddleClick() {
+add_task(function* testMiddleClick() {
   yield prepareTest();
   simulateClick({ button: 1 }, searchButton);
   let event = yield promiseOnLoad();
   is(gBrowser.tabs.length, preTabNo + 1, "MiddleClick added new tab");
   isnot(event.originalTarget, preSelectedBrowser.contentDocument,
         "MiddleClick loaded results in new tab");
   is(event.originalTarget, gBrowser.contentDocument,
      "MiddleClick loaded results in foreground tab");
   is(event.originalTarget.URL, expectedURL(searchBar.value), "testMiddleClick opened correct search page");
 });
 
-add_task(function testShiftMiddleClick() {
+add_task(function* testShiftMiddleClick() {
   yield prepareTest();
   simulateClick({ button: 1, shiftKey: true }, searchButton);
   let event = yield promiseOnLoad();
   is(gBrowser.tabs.length, preTabNo + 1, "Shift+MiddleClick added new tab");
   isnot(event.originalTarget, preSelectedBrowser.contentDocument,
         "Shift+MiddleClick loaded results in new tab");
   isnot(event.originalTarget, gBrowser.contentDocument,
         "Shift+MiddleClick loaded results in background tab");
   is(event.originalTarget.URL, expectedURL(searchBar.value), "testShiftMiddleClick opened correct search page");
 });
 
-add_task(function testRightClick() {
+add_task(function* testRightClick() {
   preTabNo = gBrowser.tabs.length;
   content.location.href = "about:blank";
   simulateClick({ button: 2 }, searchButton);
   let deferred = Promise.defer();
   setTimeout(function() {
     is(gBrowser.tabs.length, preTabNo, "RightClick did not open new tab");
     is(gBrowser.currentURI.spec, "about:blank", "RightClick did nothing");
     deferred.resolve();
   }, 5000);
   yield deferred.promise;
   // The click in the searchbox focuses it, which opens the suggestion
   // panel. Clean up after ourselves.
   searchBar.textbox.popup.hidePopup();
 });
 
-add_task(function testSearchHistory() {
+add_task(function* testSearchHistory() {
   var textbox = searchBar._textbox;
   for (var i = 0; i < searchEntries.length; i++) {
     let count = yield countEntries(textbox.getAttribute("autocompletesearchparam"), searchEntries[i]);
     ok(count > 0, "form history entry '" + searchEntries[i] + "' should exist");
   }
 });
 
-add_task(function testAutocomplete() {
+add_task(function* testAutocomplete() {
   var popup = searchBar.textbox.popup;
   let popupShownPromise = promiseEvent(popup, "popupshown");
   searchBar.textbox.showHistoryPopup();
   yield popupShownPromise;
   checkMenuEntries(searchEntries);
 });
 
-add_task(function testClearHistory() {
+add_task(function* testClearHistory() {
   let controller = searchBar.textbox.controllers.getControllerForCommand("cmd_clearhistory")
   ok(controller.isCommandEnabled("cmd_clearhistory"), "Clear history command enabled");
   controller.doCommand("cmd_clearhistory");
   let count = yield countEntries();
   ok(count == 0, "History cleared");
 });
 
-add_task(function asyncCleanup() {
+add_task(function* asyncCleanup() {
   searchBar.value = "";
   while (gBrowser.tabs.length != 1) {
     gBrowser.removeTab(gBrowser.tabs[0], {animate: false});
   }
   content.location.href = "about:blank";
   yield promiseRemoveEngine();
 });
--- a/browser/components/search/test/browser_healthreport.js
+++ b/browser/components/search/test/browser_healthreport.js
@@ -101,9 +101,9 @@ function test() {
 }
 
 function resetPreferences() {
   let service = Components.classes["@mozilla.org/datareporting/service;1"]
                                   .getService(Components.interfaces.nsISupports)
                                   .wrappedJSObject;
   service.policy._prefs.resetBranch("datareporting.policy.");
   service.policy.dataSubmissionPolicyBypassNotification = true;
-}
\ No newline at end of file
+}
--- a/browser/experiments/Experiments.jsm
+++ b/browser/experiments/Experiments.jsm
@@ -139,29 +139,29 @@ function configureLogging() {
 }
 
 // Loads a JSON file using OS.file. file is a string representing the path
 // of the file to be read, options contains additional options to pass to
 // OS.File.read.
 // Returns a Promise resolved with the json payload or rejected with
 // OS.File.Error or JSON.parse() errors.
 function loadJSONAsync(file, options) {
-  return Task.spawn(function() {
+  return Task.spawn(function*() {
     let rawData = yield OS.File.read(file, options);
     // Read json file into a string
     let data;
     try {
       // Obtain a converter to read from a UTF-8 encoded input stream.
       let converter = new TextDecoder();
       data = JSON.parse(converter.decode(rawData));
     } catch (ex) {
       gLogger.error("Experiments: Could not parse JSON: " + file + " " + ex);
       throw ex;
     }
-    throw new Task.Result(data);
+    return data;
   });
 }
 
 function telemetryEnabled() {
   return gPrefsTelemetry.get(PREF_TELEMETRY_ENABLED, false);
 }
 
 // Returns a promise that is resolved with the AddonInstall for that URL.
deleted file mode 100644
--- a/browser/extensions/loop/.eslintignore
+++ /dev/null
@@ -1,35 +0,0 @@
-# This file currently uses a non-standard (and not on a standards track)
-# if statement within catch.
-content/modules/MozLoopWorker.js
-# This file currently uses es7 features eslint issue:
-# https://github.com/eslint/espree/issues/125
-content/modules/MozLoopAPI.jsm
-# Need to fix the configuration for this.
-bootstrap.js
-# Need to drop the preprocessing (bug 1212428)
-content/preferences/prefs.js
-# Libs we don't need to check
-content/panels/vendor
-content/shared/vendor
-standalone/content/libs
-standalone/node_modules
-# Libs we don't need to check
-test/shared/vendor
-# Coverage files
-test/coverage
-test/node_modules
-# These are generated react files that we don't need to check
-content/panels/js/conversation.js
-content/panels/js/conversationViews.js
-content/panels/js/panel.js
-content/panels/js/roomViews.js
-content/panels/js/feedbackViews.js
-content/shared/js/textChatView.js
-content/shared/js/linkifiedTextView.js
-content/shared/js/views.js
-standalone/content/js/standaloneRoomViews.js
-standalone/content/js/webapp.js
-ui/ui-showcase.js
-# Don't need to check the built tree
-standalone/dist
-
--- a/browser/extensions/loop/.eslintrc
+++ b/browser/extensions/loop/.eslintrc
@@ -1,21 +1,32 @@
 // Note: there are extra allowances for files used solely in Firefox desktop,
 // see content/js/.eslintrc and modules/.eslintrc
 {
   "plugins": [
     "react"
   ],
   "ecmaFeatures": {
+    // Allow these.
     "forOf": true,
     "jsx": true,
+    // Disallow due to content.
+    "arrowFunctions": false,
+    "blockBindings": false,
+    "destructuring": false,
+    "generators": false,
+    "objectLiteralShorthandMethods": false,
+    "restParams": false,
+    "spread": false,
+    "templateStrings": false,
   },
   "env": {
     "browser": true,
-    "mocha": true
+    "es6": false,
+    "mocha": true,
   },
   "extends": "eslint:recommended",
   "globals": {
     "_": false,
     "Backbone": false,
     "chai": false,
     "classNames": false,
     "console": false,
--- a/devtools/.eslintrc
+++ b/devtools/.eslintrc
@@ -1,12 +1,9 @@
 {
-  "env": {
-    "es6": true
-  },
   "globals": {
     "Cc": true,
     "Ci": true,
     "Components": true,
     "console": true,
     "Cr": true,
     "Cu": true,
     "devtools": true,
--- a/devtools/client/markupview/markup-view.js
+++ b/devtools/client/markupview/markup-view.js
@@ -2626,17 +2626,17 @@ ElementEditor.prototype = {
 
       if (canSimplyShowEditor) {
         // Element already exists and doesn't need to be recreated.
         // Just show it (it's hidden by default due to the template).
         el.style.removeProperty("display");
       } else {
         // Create a new editor, because the value of an existing attribute
         // has changed.
-        let attribute = this._createAttribute(attr);
+        let attribute = this._createAttribute(attr, el);
         attribute.style.removeProperty("display");
 
         // Temporarily flash the attribute to highlight the change.
         // But not if this is the first time the editor instance has
         // been created.
         if (this.initialized) {
           this.flashAttribute(attr.name);
         }
--- a/devtools/client/markupview/test/browser.ini
+++ b/devtools/client/markupview/test/browser.ini
@@ -111,13 +111,14 @@ skip-if = e10s # Bug 1036409 - The last 
 [browser_markupview_tag_edit_05.js]
 [browser_markupview_tag_edit_06.js]
 [browser_markupview_tag_edit_07.js]
 [browser_markupview_tag_edit_08.js]
 [browser_markupview_tag_edit_09.js]
 [browser_markupview_tag_edit_10.js]
 [browser_markupview_tag_edit_11.js]
 [browser_markupview_tag_edit_12.js]
+[browser_markupview_tag_edit_13-other.js]
 [browser_markupview_textcontent_edit_01.js]
 [browser_markupview_toggle_01.js]
 [browser_markupview_toggle_02.js]
 [browser_markupview_toggle_03.js]
 [browser_markupview_update-on-navigtion.js]
--- a/devtools/client/markupview/test/browser_markupview_keybindings_01.js
+++ b/devtools/client/markupview/test/browser_markupview_keybindings_01.js
@@ -1,17 +1,17 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Tests tabbing through attributes on a node
 
-const TEST_URL = "data:text/html;charset=utf8,<div a b c d e id='test'></div>";
+const TEST_URL = "data:text/html;charset=utf8,<div id='test' a b c d e></div>";
 
 add_task(function*() {
   let {inspector} = yield addTab(TEST_URL).then(openInspector);
 
   info("Focusing the tag editor of the test element");
   let {editor} = yield getContainerForSelector("div", inspector);
   editor.tag.focus();
 
@@ -20,28 +20,28 @@ add_task(function*() {
   checkFocusedAttribute("id");
 
   info("Hit enter to turn the attribute to edit mode");
   EventUtils.sendKey("return", inspector.panelWin);
   checkFocusedAttribute("id", true);
 
   // Check the order of the other attributes in the DOM to the check they appear
   // correctly in the markup-view
-  let attributes = [...getNode("div").attributes].filter(attr => attr.name !== "id");
+  let attributes = (yield getAttributesFromEditor("div", inspector)).slice(1);
 
   info("Tabbing forward through attributes in edit mode");
-  for (let {name} of attributes) {
+  for (let attribute of attributes) {
     collapseSelectionAndTab(inspector);
-    checkFocusedAttribute(name, true);
+    checkFocusedAttribute(attribute, true);
   }
 
   info("Tabbing backward through attributes in edit mode");
 
   // Just reverse the attributes other than id and remove the first one since
   // it's already focused now.
   let reverseAttributes = attributes.reverse();
   reverseAttributes.shift();
 
-  for (let {name} of reverseAttributes) {
+  for (let attribute of reverseAttributes) {
     collapseSelectionAndShiftTab(inspector);
-    checkFocusedAttribute(name, true);
+    checkFocusedAttribute(attribute, true);
   }
 });
--- a/devtools/client/markupview/test/browser_markupview_tag_edit_12.js
+++ b/devtools/client/markupview/test/browser_markupview_tag_edit_12.js
@@ -2,84 +2,62 @@
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Tests that focus position is correct when tabbing through and editing
 // attributes.
 
-const TEST_URL = "data:text/html;charset=utf8,<div id='attr' c='3' b='2' a='1'></div><div id='delattr' last='1' tobeinvalid='2'></div>";
+const TEST_URL = "data:text/html;charset=utf8,<div id='attr' a='1' b='2' c='3'></div><div id='delattr' tobeinvalid='1' last='2'></div>";
 
 add_task(function*() {
   let {inspector} = yield addTab(TEST_URL).then(openInspector);
 
   yield testAttributeEditing(inspector);
   yield testAttributeDeletion(inspector);
 });
 
 function* testAttributeEditing(inspector) {
   info("Testing focus position after attribute editing");
 
-  // Modifying attributes reorders them in the internal representation to move
-  // the modified attribute to the end. breadcrumbs.js will update attributes
-  // to match original order if you selectNode before modifying attributes.
-  // So, hacky workaround for consistency with manual testing.
-  // Should be removed after Bug 1093593.
-  yield selectNode("#attr", inspector);
-
   info("Setting the first non-id attribute in edit mode");
   yield activateFirstAttribute("#attr", inspector); // focuses id
   collapseSelectionAndTab(inspector); // focuses the first attr after id
 
-  // Detect the attributes order from the DOM, instead of assuming an order in
-  // the test, because the NamedNodeMap returned by element.attributes doesn't
-  // guaranty any specific order.
-  // Filter out the id attribute as the markup-view places it first anyway.
-  let attrs = getNodeAttributesOtherThanId("#attr");
+  let attrs = yield getAttributesFromEditor("#attr", inspector);
 
   info("Editing this attribute, keeping the same name, and tabbing to the next");
-  yield editAttributeAndTab(attrs[0].name + '="99"', inspector);
-  checkFocusedAttribute(attrs[1].name, true);
+  yield editAttributeAndTab(attrs[1] + '="99"', inspector);
+  checkFocusedAttribute(attrs[2], true);
 
   info("Editing the new focused attribute, keeping the name, and tabbing to the previous");
-  yield editAttributeAndTab(attrs[1].name + '="99"', inspector, true);
-  checkFocusedAttribute(attrs[0].name, true);
+  yield editAttributeAndTab(attrs[2] + '="99"', inspector, true);
+  checkFocusedAttribute(attrs[1], true);
 
   info("Editing attribute name, changes attribute order");
   yield editAttributeAndTab("d='4'", inspector);
   checkFocusedAttribute("id", true);
 
   // Escape of the currently focused field for the next test
   EventUtils.sendKey("escape", inspector.panelWin);
 }
 
 function* testAttributeDeletion(inspector) {
   info("Testing focus position after attribute deletion");
 
-  // Modifying attributes reorders them in the internal representation to move
-  // the modified attribute to the end. breadcrumbs.js will update attributes
-  // to match original order if you selectNode before modifying attributes.
-  // So, hacky workaround for consistency with manual testing.
-  // Should be removed after Bug 1093593.
-  yield selectNode("#delattr", inspector);
-
   info("Setting the first non-id attribute in edit mode");
   yield activateFirstAttribute("#delattr", inspector); // focuses id
   collapseSelectionAndTab(inspector); // focuses the first attr after id
 
-  // Detect the attributes order from the DOM, instead of assuming an order in
-  // the test, because the NamedNodeMap returned by element.attributes doesn't
-  // guaranty any specific order.
-  // Filter out the id attribute as the markup-view places it first anyway.
-  let attrs = getNodeAttributesOtherThanId("#delattr");
+  let attrs = yield getAttributesFromEditor("#delattr", inspector);
 
   info("Entering an invalid attribute to delete the attribute");
   yield editAttributeAndTab('"', inspector);
-  checkFocusedAttribute(attrs[1].name, true);
+  checkFocusedAttribute(attrs[2], true);
 
   info("Deleting the last attribute");
   yield editAttributeAndTab(" ", inspector);
 
   // Check we're on the newattr element
   let focusedAttr = Services.focus.focusedElement;
   ok(focusedAttr.classList.contains("styleinspector-propertyeditor"), "in newattr");
   is(focusedAttr.tagName, "input", "newattr is active");
@@ -104,12 +82,8 @@ function* editAttributeAndTab(newValue, 
 function* activateFirstAttribute(container, inspector) {
   let {editor} = yield getContainerForSelector(container, inspector);
   editor.tag.focus();
 
   // Go to "id" attribute and trigger edit mode.
   EventUtils.sendKey("tab", inspector.panelWin);
   EventUtils.sendKey("return", inspector.panelWin);
 }
-
-function getNodeAttributesOtherThanId(selector) {
-  return [...getNode(selector).attributes].filter(attr => attr.name !== "id");
-}
new file mode 100644
--- /dev/null
+++ b/devtools/client/markupview/test/browser_markupview_tag_edit_13-other.js
@@ -0,0 +1,38 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that doesn't fit into any specific category.
+
+const TEST_URL = "data:text/html;charset=utf8,<div a b id='order' c class></div>";
+
+add_task(function*() {
+  let {inspector, testActor} = yield addTab(TEST_URL).then(openInspector);
+
+  yield testOriginalAttributesOrder(inspector);
+  yield testOrderAfterAttributeChange(inspector, testActor);
+});
+
+function* testOriginalAttributesOrder(inspector) {
+  info("Testing order of attributes on initial node render");
+
+  let attributes = yield getAttributesFromEditor("#order", inspector);
+  ok(isEqual(attributes, ["id", "class", "a", "b", "c"]), "ordered correctly");
+}
+
+function* testOrderAfterAttributeChange(inspector, testActor) {
+  info("Testing order of attributes after attribute is change by setAttribute");
+
+  let container = getContainerForSelector("#order", inspector);
+  yield testActor.setAttribute("#order", "a", "changed");
+
+  let attributes = yield getAttributesFromEditor("#order", inspector);
+  ok(isEqual(attributes, ["id", "class", "a", "b", "c"]),
+    "order isn't changed");
+}
+
+function isEqual(a, b) {
+  return a.toString() === b.toString();
+}
--- a/devtools/client/markupview/test/head.js
+++ b/devtools/client/markupview/test/head.js
@@ -18,16 +18,20 @@ waitForExplicitFinish();
 
 // If a test times out we want to see the complete log and not just the last few
 // lines.
 SimpleTest.requestCompleteLog();
 
 // Uncomment this pref to dump all devtools emitted events to the console.
 // Services.prefs.setBoolPref("devtools.dump.emit", true);
 
+// Import helpers registering the test-actor in remote targets
+var testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
+Services.scriptloader.loadSubScript(testDir + "../../../shared/test/test-actor-registry.js", this);
+
 // Set the testing flag on DevToolsUtils and reset it when the test ends
 DevToolsUtils.testing = true;
 registerCleanupFunction(() => DevToolsUtils.testing = false);
 
 // Clear preferences that may be set during the course of tests.
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("devtools.inspector.htmlPanelOpen");
   Services.prefs.clearUserPref("devtools.inspector.sidebarOpen");
@@ -132,17 +136,21 @@ function openToolbox(toolId) {
  * @return a promise that resolves when the inspector is ready
  */
 function openInspector() {
   return openToolbox("inspector").then(({toolbox}) => {
     let inspector = toolbox.getCurrentPanel();
     let eventId = "inspector-updated";
     return inspector.once("inspector-updated").then(() => {
       info("The inspector panel is active and ready");
-      return {toolbox: toolbox, inspector: inspector};
+      return registerTestActor(toolbox.target.client);
+    }).then(() => {
+      return getTestActor(toolbox);
+    }).then((testActor) => {
+      return {toolbox, inspector, testActor};
     });
   });
 }
 
 /**
  * Wait for a content -> chrome message on the message manager (the window
  * messagemanager is used).
  * @param {String} name The message name
@@ -651,16 +659,32 @@ function checkFocusedAttribute(attrName,
   let focusedAttr = Services.focus.focusedElement;
   is(focusedAttr ? focusedAttr.parentNode.dataset.attr : undefined,
     attrName, attrName + " attribute editor is currently focused.");
   is(focusedAttr ? focusedAttr.tagName : undefined,
     editMode ? "input": "span",
     editMode ? attrName + " is in edit mode" : attrName + " is not in edit mode");
 }
 
+/**
+ * Get attributes for node as how they are represented in editor.
+ *
+ * @param  {String} selector
+ * @param  {InspectorPanel} inspector
+ * @return {Promise}
+ *         A promise that resolves with an array of attribute names
+ *         (e.g. ["id", "class", "href"])
+ */
+var getAttributesFromEditor = Task.async(function*(selector, inspector) {
+  let nodeList = (yield getContainerForSelector(selector, inspector))
+    .tagLine.querySelectorAll("[data-attr]");
+
+  return [...nodeList].map(node => node.getAttribute("data-attr"));
+});
+
 // The expand all operation of the markup-view calls itself recursively and
 // there's not one event we can wait for to know when it's done
 // so use this helper function to wait until all recursive children updates are done.
 function* waitForMultipleChildrenUpdates(inspector) {
   // As long as child updates are queued up while we wait for an update already
   // wait again
   if (inspector.markup._queuedChildUpdates &&
       inspector.markup._queuedChildUpdates.size) {
--- a/devtools/client/shared/test/test-actor.js
+++ b/devtools/client/shared/test/test-actor.js
@@ -1,15 +1,15 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
-// A helper actor for brower/devtools/inspector tests.
+// A helper actor for inspector and markupview tests.
 
 var { Cc, Ci, Cu, Cr } = require("chrome");
 const {getRect, getElementFromPoint, getAdjustedQuads} = require("devtools/shared/layout/utils");
 const promise = require("promise");
 const {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
 var DOMUtils = Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
 var loader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
             .getService(Ci.mozIJSSubScriptLoader);
@@ -408,17 +408,17 @@ var TestActor = exports.TestActor = prot
     response: {
       value: RetVal("json")
     }
   }),
 
   /**
    * Set a JS property on a DOM Node.
    * @param {String} selector The node selector
-   * @param {String} attribute The attribute name
+   * @param {String} property The property name
    * @param {String} value The attribute value
    */
   setProperty: protocol.method(function (selector, property, value) {
     let node = this._querySelector(selector);
     node[property] = value;
   }, {
     request: {
       selector: Arg(0, "string"),
@@ -426,33 +426,51 @@ var TestActor = exports.TestActor = prot
       value: Arg(2, "string")
     },
     response: {}
   }),
 
   /**
    * Get a JS property on a DOM Node.
    * @param {String} selector The node selector
-   * @param {String} attribute The attribute name
+   * @param {String} property The property name
    * @return {String} value The attribute value
    */
   getProperty: protocol.method(function (selector, property) {
     let node = this._querySelector(selector);
     return node[property];
   }, {
     request: {
       selector: Arg(0, "string"),
       property: Arg(1, "string")
     },
     response: {
       value: RetVal("string")
     }
   }),
 
   /**
+   * Set an attribute on a DOM Node.
+   * @param {String} selector The node selector
+   * @param {String} attribute The attribute name
+   * @param {String} value The attribute value
+   */
+  setAttribute: protocol.method(function (selector, attribute, value) {
+    let node = this._querySelector(selector);
+    node.setAttribute(attribute, value);
+  }, {
+    request: {
+      selector: Arg(0, "string"),
+      property: Arg(1, "string"),
+      value: Arg(2, "string")
+    },
+    response: {}
+  }),
+
+  /**
    * Reload an iframe and wait for its load event.
    * @param {String} selector The node selector
    */
   reloadFrame: protocol.method(function (selector) {
     let node = this._querySelector(selector);
 
     let deferred = promise.defer();
 
--- a/devtools/client/webconsole/test/browser_webconsole_output_dom_elements_02.js
+++ b/devtools/client/webconsole/test/browser_webconsole_output_dom_elements_02.js
@@ -22,41 +22,41 @@ const TEST_DATA = [
     attrs: [{name: "some-attribute", value: "some-value"}]
   },
   {
     input: "testBodyNode()",
     output: '<body id="body-id" class="body-class">',
     tagName: "BODY",
     attrs: [
       {
-        name: "id", value: "body-id"
+        name: "class", value: "body-class"
       },
       {
-        name: "class", value: "body-class"
+        name: "id", value: "body-id"
       }
     ]
   },
   {
     input: "testNodeInIframe()",
     output: "<p>",
     tagName: "P",
     attrs: []
   },
   {
     input: "testDocumentElement()",
     output: '<html lang="en-US" dir="ltr">',
     tagName: "HTML",
     attrs: [
       {
+        name: "dir",
+        value: "ltr"
+      },
+      {
         name: "lang",
         value: "en-US"
-      },
-      {
-        name: "dir",
-        value: "ltr"
       }
     ]
   }
 ];
 
 function test() {
   Task.spawn(function*() {
     let {tab} = yield loadTab(TEST_URI);
--- a/devtools/server/actors/inspector.js
+++ b/devtools/server/actors/inspector.js
@@ -417,17 +417,21 @@ var NodeActor = exports.NodeActor = prot
     }
     return false;
   },
 
   writeAttrs: function() {
     if (!this.rawNode.attributes) {
       return undefined;
     }
-    return [...this.rawNode.attributes].map(attr => {
+
+    // The NamedNodeMap implementation in Firefox (returned by
+    // node.attributes) gives attributes in the reverse order compared
+    // to the source file when iterated. So reverse the list here.
+    return [...this.rawNode.attributes].reverse().map(attr => {
       return {namespace: attr.namespace, name: attr.name, value: attr.value };
     });
   },
 
   writePseudoClassLocks: function() {
     if (this.rawNode.nodeType !== Ci.nsIDOMNode.ELEMENT_NODE) {
       return undefined;
     }
--- a/dom/bluetooth/bluedroid/BluetoothDaemonGattInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonGattInterface.cpp
@@ -601,19 +601,20 @@ BluetoothDaemonGattModule::ClientSetAdvD
   nsresult rv = PackPDU(
     PackConversion<int, int32_t>(aServerIf),
     PackConversion<bool, uint8_t>(aIsScanRsp),
     PackConversion<bool, uint8_t>(aIsNameIncluded),
     PackConversion<bool, uint8_t>(aIsTxPowerIncluded),
     PackConversion<int, int32_t>(aMinInterval),
     PackConversion<int, int32_t>(aMaxInterval),
     PackConversion<int, int32_t>(aApperance),
-    aManufacturerLen, PackArray<char>(aManufacturerData, aManufacturerLen),
-    aServiceDataLen, PackArray<char>(aServiceData, aServiceDataLen),
-    aServiceUuidLen, PackArray<char>(aServiceUuid, aServiceUuidLen), *pdu);
+    aManufacturerLen, aServiceDataLen, aServiceUuidLen,
+    PackArray<char>(aManufacturerData, aManufacturerLen),
+    PackArray<char>(aServiceData, aServiceDataLen),
+    PackArray<char>(aServiceUuid, aServiceUuidLen), *pdu);
   if (NS_FAILED(rv)) {
     return rv;
   }
   rv = Send(pdu, aRes);
   if (NS_FAILED(rv)) {
     return rv;
   }
   Unused << pdu.forget();
@@ -984,17 +985,17 @@ BluetoothDaemonGattModule::ServerSendRes
 
   nsAutoPtr<DaemonSocketPDU> pdu(
     new DaemonSocketPDU(SERVICE_ID, OPCODE_SERVER_SEND_RESPONSE,
                         0));
 
   nsresult rv = PackPDU(
     PackConversion<int, int32_t>(aConnId),
     PackConversion<int, int32_t>(aTransId),
-    aResponse.mHandle,
+    PackConversion<BluetoothAttributeHandle, uint16_t>(aResponse.mHandle),
     aResponse.mOffset,
     PackConversion<BluetoothGattAuthReq, uint8_t>(aResponse.mAuthReq),
     PackConversion<uint16_t, int32_t>(aStatus),
     aResponse.mLength,
     PackArray<uint8_t>(aResponse.mValue, aResponse.mLength), *pdu);
 
   if (NS_FAILED(rv)) {
     return rv;
@@ -2003,124 +2004,16 @@ BluetoothDaemonGattModule::HandleNtf(
 BluetoothDaemonGattInterface::BluetoothDaemonGattInterface(
   BluetoothDaemonGattModule* aModule)
   : mModule(aModule)
 { }
 
 BluetoothDaemonGattInterface::~BluetoothDaemonGattInterface()
 { }
 
-#if 0
-class BluetoothDaemonGattInterface::InitResultHandler final
-  : public BluetoothSetupResultHandler
-{
-public:
-  InitResultHandler(BluetoothGattResultHandler* aRes)
-    : mRes(aRes)
-  {
-    MOZ_ASSERT(mRes);
-  }
-
-  void OnError(BluetoothStatus aStatus) override
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    mRes->OnError(aStatus);
-  }
-
-  void RegisterModule() override
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    mRes->Init();
-  }
-
-private:
-  RefPtr<BluetoothGattResultHandler> mRes;
-};
-
-void
-BluetoothDaemonGattInterface::Init(
-  BluetoothGattNotificationHandler* aNotificationHandler,
-  BluetoothGattResultHandler* aRes)
-{
-  // Set notification handler _before_ registering the module. It could
-  // happen that we receive notifications, before the result handler runs.
-  mModule->SetNotificationHandler(aNotificationHandler);
-
-  InitResultHandler* res;
-
-  if (aRes) {
-    res = new InitResultHandler(aRes);
-  } else {
-    // We don't need a result handler if the caller is not interested.
-    res = nullptr;
-  }
-
-  nsresult rv = mModule->RegisterModule(
-    SETUP_SERVICE_ID_GATT, 0x00, BluetoothDaemonGattModule::MAX_NUM_CLIENTS,
-    res);
-
-  if (NS_FAILED(rv) && aRes) {
-    DispatchError(aRes, rv);
-  }
-}
-
-class BluetoothDaemonGattInterface::CleanupResultHandler final
-  : public BluetoothSetupResultHandler
-{
-public:
-  CleanupResultHandler(BluetoothDaemonGattModule* aModule,
-                       BluetoothGattResultHandler* aRes)
-    : mModule(aModule)
-    , mRes(aRes)
-  {
-    MOZ_ASSERT(mModule);
-  }
-
-  void OnError(BluetoothStatus aStatus) override
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    if (mRes) {
-      mRes->OnError(aStatus);
-    }
-  }
-
-  void UnregisterModule() override
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    // Clear notification handler _after_ module has been
-    // unregistered. While unregistering the module, we might
-    // still receive notifications.
-    mModule->SetNotificationHandler(nullptr);
-
-    if (mRes) {
-      mRes->Cleanup();
-    }
-  }
-
-private:
-  BluetoothDaemonGattModule* mModule;
-  RefPtr<BluetoothGattResultHandler> mRes;
-};
-
-void
-BluetoothDaemonGattInterface::Cleanup(
-  BluetoothGattResultHandler* aRes)
-{
-  nsresult rv = mModule->UnregisterModule(
-    SETUP_SERVICE_ID_GATT, new CleanupResultHandler(mModule, aRes));
-  if (NS_FAILED(rv)) {
-    DispatchError(aRes, rv);
-  }
-}
-#endif
-
 void
 BluetoothDaemonGattInterface::SetNotificationHandler(
   BluetoothGattNotificationHandler* aNotificationHandler)
 {
   MOZ_ASSERT(mModule);
 
   mModule->SetNotificationHandler(aNotificationHandler);
 }
--- a/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.cpp
@@ -529,16 +529,24 @@ Convert(nsresult aIn, BluetoothStatus& a
 nsresult
 Convert(const BluetoothAttributeHandle& aIn, int32_t& aOut)
 {
   aOut = static_cast<int32_t>(aIn.mHandle);
   return NS_OK;
 }
 
 nsresult
+Convert(const BluetoothAttributeHandle& aIn, uint16_t& aOut)
+{
+  aOut = aIn.mHandle;
+  return NS_OK;
+}
+
+
+nsresult
 Convert(BluetoothAvrcpEvent aIn, uint8_t& aOut)
 {
   static const uint8_t sValue[] = {
     [AVRCP_EVENT_PLAY_STATUS_CHANGED] = 0x01,
     [AVRCP_EVENT_TRACK_CHANGE] = 0x02,
     [AVRCP_EVENT_TRACK_REACHED_END] = 0x03,
     [AVRCP_EVENT_TRACK_REACHED_START] = 0x04,
     [AVRCP_EVENT_PLAY_POS_CHANGED] = 0x05,
@@ -929,16 +937,36 @@ Convert(BluetoothGattAuthReq aIn, int32_
     aOut = GATT_AUTH_REQ_NONE; // silences compiler warning
     return NS_ERROR_ILLEGAL_VALUE;
   }
   aOut = sGattAuthReq[aIn];
   return NS_OK;
 }
 
 nsresult
+Convert(BluetoothGattAuthReq aIn, uint8_t& aOut)
+{
+  static const uint8_t sGattAuthReq[] = {
+    [GATT_AUTH_REQ_NONE] = 0x00,
+    [GATT_AUTH_REQ_NO_MITM] = 0x01,
+    [GATT_AUTH_REQ_MITM] = 0x02,
+    [GATT_AUTH_REQ_SIGNED_NO_MITM] = 0x03,
+    [GATT_AUTH_REQ_SIGNED_MITM] = 0x04
+  };
+  if (MOZ_HAL_IPC_CONVERT_WARN_IF(
+        aIn >= MOZ_ARRAY_LENGTH(sGattAuthReq), BluetoothGattAuthReq,
+        uint8_t)) {
+    aOut = GATT_AUTH_REQ_NONE; // silences compiler warning
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sGattAuthReq[aIn];
+  return NS_OK;
+}
+
+nsresult
 Convert(BluetoothGattWriteType aIn, int32_t& aOut)
 {
   static const int32_t sGattWriteType[] = {
     [GATT_WRITE_TYPE_NO_RESPONSE] = 0x01,
     [GATT_WRITE_TYPE_NORMAL] = 0x02,
     [GATT_WRITE_TYPE_PREPARE] = 0x03,
     [GATT_WRITE_TYPE_SIGNED] = 0x04
   };
--- a/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.h
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.h
@@ -175,16 +175,19 @@ Convert(int32_t aIn, BluetoothAttributeH
 
 nsresult
 Convert(int32_t aIn, BluetoothGattStatus& aOut);
 
 nsresult
 Convert(const BluetoothAttributeHandle& aIn, int32_t& aOut);
 
 nsresult
+Convert(const BluetoothAttributeHandle& aIn, uint16_t& aOut);
+
+nsresult
 Convert(BluetoothAvrcpEvent aIn, uint8_t& aOut);
 
 nsresult
 Convert(BluetoothAvrcpNotification aIn, uint8_t& aOut);
 
 nsresult
 Convert(BluetoothAvrcpPlayerAttribute aIn, uint8_t& aOut);
 
@@ -241,16 +244,19 @@ Convert(BluetoothSspVariant aIn, uint8_t
 
 nsresult
 Convert(ControlPlayStatus aIn, uint8_t& aOut);
 
 nsresult
 Convert(BluetoothGattAuthReq aIn, int32_t& aOut);
 
 nsresult
+Convert(BluetoothGattAuthReq aIn, uint8_t& aOut);
+
+nsresult
 Convert(BluetoothGattWriteType aIn, int32_t& aOut);
 
 nsresult
 Convert(nsresult aIn, BluetoothStatus& aOut);
 
 //
 // Packing
 //
--- a/dom/bluetooth/bluedroid/BluetoothGattManager.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothGattManager.cpp
@@ -3682,17 +3682,17 @@ BluetoothGattManager::RequestReadNotific
 
   // Distribute a signal to gattServer
   InfallibleTArray<BluetoothNamedValue> properties;
 
   AppendNamedValue(properties, "TransId", aTransId);
   AppendNamedValue(properties, "AttrHandle", aAttributeHandle);
   AppendNamedValue(properties, "Address", bdAddrStr);
   AppendNamedValue(properties, "NeedResponse", true);
-  AppendNamedValue(properties, "Value", new nsTArray<uint8_t>());
+  AppendNamedValue(properties, "Value", nsTArray<uint8_t>());
 
   bs->DistributeSignal(NS_LITERAL_STRING("ReadRequested"),
                        server->mAppUuid,
                        properties);
 }
 
 void
 BluetoothGattManager::RequestWriteNotification(
--- a/mobile/android/.eslintrc
+++ b/mobile/android/.eslintrc
@@ -1,11 +1,10 @@
 env:
     browser: true
-    es6: true
 
 globals:
     Components: false
 
     # TODO: Create custom rule for `Cu.import`
     AddonManager: false
     AppConstants: false
     Downloads: false
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -664,29 +664,16 @@ public abstract class GeckoApp
 
             showSnackbar(msg,
                     duration,
                     action != null ? action.optString("label", null) : null,
                     snackbarCallback);
         } else if ("SystemUI:Visibility".equals(event)) {
             setSystemUiVisible(message.getBoolean("visible"));
 
-        } else if ("Toast:Show".equals(event)) {
-            final String msg = message.getString("message");
-            final String duration = message.getString("duration");
-            final NativeJSObject button = message.optObject("button", null);
-            if (button != null) {
-                final String label = button.optString("label", "");
-                final String icon = button.optString("icon", "");
-                final String id = button.optString("id", "");
-                showButtonToast(msg, duration, label, icon, id);
-            } else {
-                showNormalToast(msg, duration);
-            }
-
         } else if ("ToggleChrome:Focus".equals(event)) {
             focusChrome();
 
         } else if ("ToggleChrome:Hide".equals(event)) {
             toggleChrome(false);
 
         } else if ("ToggleChrome:Show".equals(event)) {
             toggleChrome(true);
@@ -845,31 +832,16 @@ public abstract class GeckoApp
                             clearButton.setEnabled(false);
                         }
                     }
                 });
             }
         });
     }
 
-    public void showNormalToast(final String message, final String duration) {
-        ThreadUtils.postToUiThread(new Runnable() {
-            @Override
-            public void run() {
-                Toast toast;
-                if (duration.equals("long")) {
-                    toast = Toast.makeText(GeckoApp.this, message, Toast.LENGTH_LONG);
-                } else {
-                    toast = Toast.makeText(GeckoApp.this, message, Toast.LENGTH_SHORT);
-                }
-                toast.show();
-            }
-        });
-    }
-
     public ButtonToast getButtonToast() {
         if (mToast != null) {
             return mToast;
         }
 
         ViewStub toastStub = (ViewStub) findViewById(R.id.toast_stub);
         mToast = new ButtonToast(toastStub.inflate());
 
@@ -1359,17 +1331,16 @@ public abstract class GeckoApp
             "Image:SetAs",
             "Locale:Set",
             "Permissions:Data",
             "PrivateBrowsing:Data",
             "Session:StatePurged",
             "Share:Text",
             "Snackbar:Show",
             "SystemUI:Visibility",
-            "Toast:Show",
             "ToggleChrome:Focus",
             "ToggleChrome:Hide",
             "ToggleChrome:Show",
             "Update:Check",
             "Update:Download",
             "Update:Install");
 
         EventDispatcher.getInstance().registerBackgroundThreadListener((BundleEventListener) this,
@@ -2184,17 +2155,16 @@ public abstract class GeckoApp
             "DOMFullScreen:Stop",
             "Image:SetAs",
             "Locale:Set",
             "Permissions:Data",
             "PrivateBrowsing:Data",
             "Session:StatePurged",
             "Share:Text",
             "SystemUI:Visibility",
-            "Toast:Show",
             "ToggleChrome:Focus",
             "ToggleChrome:Hide",
             "ToggleChrome:Show",
             "Update:Check",
             "Update:Download",
             "Update:Install");
 
         EventDispatcher.getInstance().unregisterBackgroundThreadListener((BundleEventListener) this,
--- a/mobile/android/base/locales/en-US/android_strings.dtd
+++ b/mobile/android/base/locales/en-US/android_strings.dtd
@@ -712,23 +712,25 @@ just addresses the organization to follo
      desktop Firefox via WebIDE), so you just need to aim this device at the QR
      code. -->
 <!ENTITY devtools_auth_scan_header "Scanning for the QR code displayed on your other device">
 
 <!-- Restrictable features -->
 <!-- Localization note: These are features the device owner (e.g. parent) can enable or disable for
      a restricted profile (e.g. child). Used inside the Android settings UI. -->
 <!ENTITY restrictable_feature_addons_installation "Add-ons">
+<!ENTITY restrictable_feature_addons_installation_description "Add features or functionality to Firefox. Note: Add-ons can disable certain restrictions.">
 <!ENTITY restrictable_feature_private_browsing "Private Browsing">
-<!ENTITY restrictable_feature_location_services "Location Services">
+<!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_guest_browsing "Guest browsing">
-<!ENTITY restrictable_feature_master_password "Master password">
+<!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.">
 
 <!-- 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
@@ -785,23 +785,16 @@ OnSharedPreferenceChangeListener
                     pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
                         @Override
                         public boolean onPreferenceClick(Preference preference) {
                             GeckoPreferences.this.restoreDefaultSearchEngines();
                             Telemetry.sendUIEvent(TelemetryContract.Event.SEARCH_RESTORE_DEFAULTS, Method.LIST_ITEM);
                             return true;
                         }
                     });
-                } else if (handlers.containsKey(key)) {
-                    PrefHandler handler = handlers.get(key);
-                    if (!handler.setupPref(this, pref)) {
-                        preferences.removePreference(pref);
-                        i--;
-                        continue;
-                    }
                 } else if (PREFS_TAB_QUEUE.equals(key)) {
                     // Only show tab queue pref on nightly builds with the tab queue build flag.
                     if (!TabQueueHelper.TAB_QUEUE_ENABLED) {
                         preferences.removePreference(pref);
                         i--;
                         continue;
                     }
                 } else if (PREFS_VOICE_INPUT_ENABLED.equals(key)) {
@@ -855,16 +848,25 @@ OnSharedPreferenceChangeListener
                 } else if (PREFS_FAQ_LINK.equals(key)) {
                     // Format the FAQ link
                     final String VERSION = AppConstants.MOZ_APP_VERSION;
                     final String OS = AppConstants.OS_TARGET;
                     final String LOCALE = Locales.getLanguageTag(Locale.getDefault());
 
                     final String url = getResources().getString(R.string.faq_link, VERSION, OS, LOCALE);
                     ((LinkPreference) pref).setUrl(url);
+                } else if (handlers.containsKey(key)) {
+                    // This should be the last task. We might have removed some of this preferences previously. We only
+                    // want to run the PrefHandler for a preference if it still exists.
+                    PrefHandler handler = handlers.get(key);
+                    if (!handler.setupPref(this, pref)) {
+                        preferences.removePreference(pref);
+                        i--;
+                        continue;
+                    }
                 }
 
                 // Some Preference UI elements are not actually preferences,
                 // but they require a key to work correctly. For example,
                 // "Clear private data" requires a key for its state to be
                 // saved when the orientation changes. It uses the
                 // "android.not_a_preference.privacy.clear" key - which doesn't
                 // exist in Gecko - to satisfy this requirement.
--- a/mobile/android/base/restrictions/Restrictable.java
+++ b/mobile/android/base/restrictions/Restrictable.java
@@ -11,65 +11,88 @@ import android.content.Context;
 import android.support.annotation.StringRes;
 
 /**
  * This is a list of things we can restrict you from doing. Some of these are reflected in Android UserManager constants.
  * Others are specific to us.
  * These constants should be in sync with the ones from toolkit/components/parentalcontrols/nsIParentalControlsService.idl
  */
 public enum Restrictable {
-    DOWNLOAD(1, "downloads", 0),
+    DOWNLOAD(1, "downloads", 0, 0),
 
-    INSTALL_EXTENSION(2, "no_install_extensions", R.string.restrictable_feature_addons_installation),
+    INSTALL_EXTENSION(
+            2, "no_install_extensions",
+            R.string.restrictable_feature_addons_installation,
+            R.string.restrictable_feature_addons_installation_description),
 
     // UserManager.DISALLOW_INSTALL_APPS
-    INSTALL_APPS(3, "no_install_apps", 0),
+    INSTALL_APPS(3, "no_install_apps", 0 , 0),
 
-    BROWSE(4, "browse", 0),
+    BROWSE(4, "browse", 0, 0),
 
-    SHARE(5, "share", 0),
+    SHARE(5, "share", 0, 0),
 
-    BOOKMARK(6, "bookmark", 0),
+    BOOKMARK(6, "bookmark", 0, 0),
 
-    ADD_CONTACT(7, "add_contact", 0),
+    ADD_CONTACT(7, "add_contact", 0, 0),
 
-    SET_IMAGE(8, "set_image", 0),
+    SET_IMAGE(8, "set_image", 0, 0),
 
     // UserManager.DISALLOW_MODIFY_ACCOUNTS
-    MODIFY_ACCOUNTS(9, "no_modify_accounts", 0),
+    MODIFY_ACCOUNTS(9, "no_modify_accounts", 0, 0),
 
-    REMOTE_DEBUGGING(10, "remote_debugging", 0),
+    REMOTE_DEBUGGING(10, "remote_debugging", 0, 0),
+
+    IMPORT_SETTINGS(11, "import_settings", 0, 0),
 
-    IMPORT_SETTINGS(11, "import_settings", 0),
+    PRIVATE_BROWSING(
+            12, "private_browsing",
+            R.string.restrictable_feature_private_browsing,
+            R.string.restrictable_feature_private_browsing_description),
 
-    PRIVATE_BROWSING(12, "private_browsing", R.string.restrictable_feature_private_browsing),
-
-    LOCATION_SERVICE(13, "location_service", R.string.restrictable_feature_location_services),
+    LOCATION_SERVICE(13, "location_service", 0, 0),
 
-    CLEAR_HISTORY(14, "clear_history", R.string.restrictable_feature_clear_history),
+    CLEAR_HISTORY(14, "clear_history",
+            R.string.restrictable_feature_clear_history,
+            R.string.restrictable_feature_clear_history_description),
 
-    MASTER_PASSWORD(15, "master_password", R.string.restrictable_feature_master_password),
+    MASTER_PASSWORD(15, "master_password", 0, 0),
+
+    GUEST_BROWSING(16, "guest_browsing",  0, 0),
 
-    GUEST_BROWSING(16, "guest_browsing",  R.string.restrictable_feature_guest_browsing),
+    ADVANCED_SETTINGS(17, "advanced_settings",
+            R.string.restrictable_feature_advanced_settings,
+            R.string.restrictable_feature_advanced_settings_description),
 
-    ADVANCED_SETTINGS(17, "advanced_settings", R.string.restrictable_feature_advanced_settings),
-
-    CAMERA_MICROPHONE(18, "camera_microphone", R.string.restrictable_feature_camera_microphone);
+    CAMERA_MICROPHONE(18, "camera_microphone",
+            R.string.restrictable_feature_camera_microphone,
+            R.string.restrictable_feature_camera_microphone_description);
 
     public final int id;
     public final String name;
 
     @StringRes
     public final int title;
 
-    Restrictable(final int id, final String name, @StringRes int title) {
+    @StringRes
+    public final int description;
+
+    Restrictable(final int id, final String name, @StringRes int title, @StringRes int description) {
         this.id = id;
         this.name = name;
         this.title = title;
+        this.description = description;
     }
 
     public String getTitle(Context context) {
         if (title == 0) {
             return toString();
         }
         return context.getResources().getString(title);
     }
+
+    public String getDescription(Context context) {
+        if (description == 0) {
+            return null;
+        }
+        return context.getResources().getString(description);
+    }
 }
--- a/mobile/android/base/restrictions/RestrictedProfileConfiguration.java
+++ b/mobile/android/base/restrictions/RestrictedProfileConfiguration.java
@@ -26,16 +26,29 @@ public class RestrictedProfileConfigurat
             Restrictable.LOCATION_SERVICE,
             Restrictable.CLEAR_HISTORY,
             Restrictable.MASTER_PASSWORD,
             Restrictable.GUEST_BROWSING,
             Restrictable.ADVANCED_SETTINGS,
             Restrictable.CAMERA_MICROPHONE
     );
 
+    /**
+     * 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
+    );
+
+    /* package-private */ static boolean shouldHide(Restrictable restrictable) {
+        return hiddenRestrictions.contains(restrictable);
+    }
+
     private Context context;
     private Bundle cachedAppRestrictions;
     private Bundle cachedUserRestrictions;
     private boolean isCacheInvalid = true;
 
     public RestrictedProfileConfiguration(Context context) {
         this.context = context.getApplicationContext();
     }
@@ -106,29 +119,17 @@ public class RestrictedProfileConfigurat
         if (!bundle.containsKey(Restrictable.INSTALL_EXTENSION.name) && bundle.containsKey("no_install_extensions")) {
             bundle.putBoolean(Restrictable.INSTALL_EXTENSION.name, !bundle.getBoolean("no_install_extensions"));
         }
 
         if (!bundle.containsKey(Restrictable.PRIVATE_BROWSING.name) && bundle.containsKey("no_private_browsing")) {
             bundle.putBoolean(Restrictable.PRIVATE_BROWSING.name, !bundle.getBoolean("no_private_browsing"));
         }
 
-        if (!bundle.containsKey(Restrictable.LOCATION_SERVICE.name) && bundle.containsKey("no_location_service")) {
-            bundle.putBoolean(Restrictable.LOCATION_SERVICE.name, !bundle.getBoolean("no_location_service"));
-        }
-
         if (!bundle.containsKey(Restrictable.CLEAR_HISTORY.name) && bundle.containsKey("no_clear_history")) {
             bundle.putBoolean(Restrictable.CLEAR_HISTORY.name, !bundle.getBoolean("no_clear_history"));
         }
 
-        if (!bundle.containsKey(Restrictable.MASTER_PASSWORD.name) && bundle.containsKey("no_master_password")) {
-            bundle.putBoolean(Restrictable.MASTER_PASSWORD.name, !bundle.getBoolean("no_master_password"));
-        }
-
-        if (!bundle.containsKey(Restrictable.GUEST_BROWSING.name) && bundle.containsKey("no_guest_browsing")) {
-            bundle.putBoolean(Restrictable.GUEST_BROWSING.name, !bundle.getBoolean("no_guest_browsing"));
-        }
-
         if (!bundle.containsKey(Restrictable.ADVANCED_SETTINGS.name) && bundle.containsKey("no_advanced_settings")) {
             bundle.putBoolean(Restrictable.ADVANCED_SETTINGS.name, !bundle.getBoolean("no_advanced_settings"));
         }
     }
 }
--- a/mobile/android/base/restrictions/RestrictionProvider.java
+++ b/mobile/android/base/restrictions/RestrictionProvider.java
@@ -10,16 +10,17 @@ import org.mozilla.gecko.AppConstants;
 import android.annotation.TargetApi;
 import android.app.Activity;
 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;
 
 /**
  * Broadcast receiver providing supported restrictions to the system.
  */
 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
 public class RestrictionProvider extends BroadcastReceiver {
@@ -52,24 +53,33 @@ public class RestrictionProvider extends
     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;
             }
 
+            if (RestrictedProfileConfiguration.shouldHide(restrictable)) {
+                continue;
+            }
+
             RestrictionEntry entry = createRestrictionEntryWithDefaultValue(context, restrictable,
                     oldRestrictions.getBoolean(restrictable.name, false));
             entries.add(entry);
         }
 
         return entries;
     }
 
     private RestrictionEntry createRestrictionEntryWithDefaultValue(Context context, Restrictable restrictable, boolean defaultValue) {
         RestrictionEntry entry = new RestrictionEntry(restrictable.name, defaultValue);
 
         entry.setTitle(restrictable.getTitle(context));
 
+        final String description = restrictable.getDescription(context);
+        if (!TextUtils.isEmpty(description)) {
+            entry.setDescription(description);
+        }
+
         return entry;
     }
 }
--- a/mobile/android/base/strings.xml.in
+++ b/mobile/android/base/strings.xml.in
@@ -561,23 +561,25 @@
   <string name="actionbar_menu">&actionbar_menu;</string>
   <string name="actionbar_done">&actionbar_done;</string>
 
   <!-- Voice search from the Awesome Bar -->
   <string name="voicesearch_prompt">&voicesearch_prompt;</string>
 
   <!-- Restrictable features -->
   <string name="restrictable_feature_addons_installation">&restrictable_feature_addons_installation;</string>
+  <string name="restrictable_feature_addons_installation_description">&restrictable_feature_addons_installation_description;</string>
   <string name="restrictable_feature_private_browsing">&restrictable_feature_private_browsing;</string>
-  <string name="restrictable_feature_location_services">&restrictable_feature_location_services;</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_guest_browsing">&restrictable_feature_guest_browsing;</string>
-  <string name="restrictable_feature_master_password">&restrictable_feature_master_password;</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>
 
   <!-- Miscellaneous -->
   <string name="ellipsis">&ellipsis;</string>
 
   <string name="colon">&colon;</string>
 
   <string name="percent">&percent;</string>
 
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -2263,18 +2263,16 @@ var BrowserApp = {
     };
   },
 };
 
 var NativeWindow = {
   init: function() {
     Services.obs.addObserver(this, "Menu:Clicked", false);
     Services.obs.addObserver(this, "Doorhanger:Reply", false);
-    Services.obs.addObserver(this, "Toast:Click", false);
-    Services.obs.addObserver(this, "Toast:Hidden", false);
     this.contextmenus.init();
   },
 
   loadDex: function(zipFile, implClass) {
     Messaging.sendRequest({
       type: "Dex:Load",
       zipfile: zipFile,
       impl: implClass || "Main"
@@ -2283,48 +2281,16 @@ var NativeWindow = {
 
   unloadDex: function(zipFile) {
     Messaging.sendRequest({
       type: "Dex:Unload",
       zipfile: zipFile
     });
   },
 
-  toast: {
-    _callbacks: {},
-    show: function(aMessage, aDuration, aOptions) {
-      let msg = {
-        type: "Toast:Show",
-        message: aMessage,
-        duration: aDuration
-      };
-
-      if (aOptions && aOptions.button) {
-        msg.button = {
-          id: uuidgen.generateUUID().toString(),
-        };
-
-        // null is badly handled by the receiver, so try to avoid including nulls.
-        if (aOptions.button.label) {
-          msg.button.label = aOptions.button.label;
-        }
-
-        if (aOptions.button.icon) {
-          // If the caller specified a button, make sure we convert any chrome urls
-          // to jar:jar urls so that the frontend can show them
-          msg.button.icon = resolveGeckoURI(aOptions.button.icon);
-        };
-
-        this._callbacks[msg.button.id] = aOptions.button.callback;
-      }
-
-      Messaging.sendRequest(msg);
-    }
-  },
-
   menu: {
     _callbacks: [],
     _menuId: 1,
     toolsMenuID: -1,
     add: function() {
       let options;
       if (arguments.length == 1) {
         options = arguments[0];
@@ -2427,24 +2393,16 @@ var NativeWindow = {
       });
     }
   },
 
   observe: function(aSubject, aTopic, aData) {
     if (aTopic == "Menu:Clicked") {
       if (this.menu._callbacks[aData])
         this.menu._callbacks[aData]();
-    } else if (aTopic == "Toast:Click") {
-      if (this.toast._callbacks[aData]) {
-        this.toast._callbacks[aData]();
-        delete this.toast._callbacks[aData];
-      }
-    } else if (aTopic == "Toast:Hidden") {
-      if (this.toast._callbacks[aData])
-        delete this.toast._callbacks[aData];
     } else if (aTopic == "Doorhanger:Reply") {
       let data = JSON.parse(aData);
       let reply_id = data["callback"];
 
       if (this.doorhanger._callbacks[reply_id]) {
         // Pass the value of the optional checkbox to the callback
         let checked = data["checked"];
         this.doorhanger._callbacks[reply_id].cb(checked, data.inputs);
@@ -3130,17 +3088,18 @@ var NativeWindow = {
   }
 };
 
 XPCOMUtils.defineLazyModuleGetter(this, "PageActions",
                                   "resource://gre/modules/PageActions.jsm");
 
 // These alias to the old, deprecated NativeWindow interfaces
 [
-  ["pageactions", "resource://gre/modules/PageActions.jsm", "PageActions"]
+  ["pageactions", "resource://gre/modules/PageActions.jsm", "PageActions"],
+  ["toast", "resource://gre/modules/Snackbars.jsm", "Snackbars"]
 ].forEach(item => {
   let [name, script, exprt] = item;
 
   XPCOMUtils.defineLazyGetter(NativeWindow, name, () => {
     var err = Strings.browser.formatStringFromName("nativeWindow.deprecated", ["NativeWindow." + name, script], 2);
     Cu.reportError(err);
 
     let sandbox = {};
--- a/mobile/android/modules/Snackbars.jsm
+++ b/mobile/android/modules/Snackbars.jsm
@@ -17,16 +17,22 @@ const LENGTH_LONG = 0;
 const LENGTH_SHORT = -1;
 
 var Snackbars = {
   LENGTH_INDEFINITE: LENGTH_INDEFINITE,
   LENGTH_LONG: LENGTH_LONG,
   LENGTH_SHORT: LENGTH_SHORT,
 
   show: function(aMessage, aDuration, aOptions) {
+
+    // Takes care of the deprecated toast calls
+    if (typeof aDuration === "string") {
+      [aDuration, aOptions] = migrateToastIfNeeded(aDuration, aOptions);
+    }
+
     let msg = {
       type: 'Snackbar:Show',
       message: aMessage,
       duration: aDuration,
     };
 
     if (aOptions && aOptions.action) {
       msg.action = {};
@@ -36,8 +42,27 @@ var Snackbars = {
       }
 
       Messaging.sendRequestForResult(msg).then(result => aOptions.action.callback());
     } else {
       Messaging.sendRequest(msg);
     }
   }
 };
+
+function migrateToastIfNeeded(aDuration, aOptions) {
+  let duration;
+  if (aDuration === "long") {
+    duration = LENGTH_LONG;
+  }
+  else {
+    duration = LENGTH_SHORT;
+  }
+
+  let options = {};
+  if (aOptions && aOptions.button) {
+    options.action = {
+      label: aOptions.button.label,
+      callback: () => aOptions.button.callback(),
+    };
+  }
+  return [duration, options];
+}
\ No newline at end of file
--- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
@@ -214,16 +214,17 @@ const TYPES = {
 // externally
 const TYPE_ALIASES = {
   "webextension": "extension",
 };
 
 const CHROME_TYPES = new Set([
   "extension",
   "locale",
+  "experiment",
 ]);
 
 const RESTARTLESS_TYPES = new Set([
   "webextension",
   "dictionary",
   "experiment",
   "locale",
 ]);
--- a/toolkit/mozapps/extensions/test/xpcshell/head_addons.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/head_addons.js
@@ -68,35 +68,68 @@ var TEST_UNPACKED = false;
 
 // Map resource://xpcshell-data/ to the data directory
 var resHandler = Services.io.getProtocolHandler("resource")
                          .QueryInterface(AM_Ci.nsISubstitutingProtocolHandler);
 // Allow non-existent files because of bug 1207735
 var dataURI = NetUtil.newURI(do_get_file("data", true));
 resHandler.setSubstitution("xpcshell-data", dataURI);
 
+function isManifestRegistered(file) {
+  let manifests = Components.manager.getManifestLocations();
+  for (let i = 0; i < manifests.length; i++) {
+    let manifest = manifests.queryElementAt(i, AM_Ci.nsIURI);
+
+    // manifest is the url to the manifest file either in an XPI or a directory.
+    // We want the location of the XPI or directory itself.
+    if (manifest instanceof AM_Ci.nsIJARURI) {
+      manifest = manifest.JARFile.QueryInterface(AM_Ci.nsIFileURL).file;
+    }
+    else if (manifest instanceof AM_Ci.nsIFileURL) {
+      manifest = manifest.file.parent;
+    }
+    else {
+      continue;
+    }
+
+    if (manifest.equals(file))
+      return true;
+  }
+  return false;
+}
+
 // Listens to messages from bootstrap.js telling us what add-ons were started
 // and stopped etc. and performs some sanity checks that only installed add-ons
 // are started etc.
 this.BootstrapMonitor = {
+  inited: false,
+
   // Contain the current state of add-ons in the system
   installed: new Map(),
   started: new Map(),
 
   // Contain the last state of shutdown and uninstall calls for an add-on
   stopped: new Map(),
   uninstalled: new Map(),
 
   startupPromises: [],
   installPromises: [],
 
   init() {
+    this.inited = true;
     Services.obs.addObserver(this, "bootstrapmonitor-event", false);
   },
 
+  shutdownCheck() {
+    if (!this.inited)
+      return;
+
+    do_check_eq(this.started.size, 0);
+  },
+
   clear(id) {
     this.installed.delete(id);
     this.started.delete(id);
     this.stopped.delete(id);
     this.uninstalled.delete(id);
   },
 
   promiseAddonStartup(id) {
@@ -118,16 +151,21 @@ this.BootstrapMonitor = {
     do_check_eq(current.data.resourceURI, cached.data.resourceURI);
   },
 
   checkAddonStarted(id, version = undefined) {
     let started = this.started.get(id);
     do_check_neq(started, undefined);
     if (version != undefined)
       do_check_eq(started.data.version, version);
+
+    // Chrome should be registered by now
+    let installPath = new FileUtils.File(started.data.installPath);
+    let isRegistered = isManifestRegistered(installPath);
+    do_check_true(isRegistered);
   },
 
   checkAddonNotStarted(id) {
     do_check_false(this.started.has(id));
   },
 
   checkAddonInstalled(id, version = undefined) {
     let installed = this.installed.get(id);
@@ -138,16 +176,17 @@ this.BootstrapMonitor = {
 
   checkAddonNotInstalled(id) {
     do_check_false(this.installed.has(id));
   },
 
   observe(subject, topic, data) {
     let info = JSON.parse(data);
     let id = info.data.id;
+    let installPath = new FileUtils.File(info.data.installPath);
 
     // If this is the install event the add-ons shouldn't already be installed
     if (info.event == "install") {
       this.checkAddonNotInstalled(id);
 
       this.installed.set(id, info);
 
       for (let resolve of this.installPromises)
@@ -159,28 +198,46 @@ this.BootstrapMonitor = {
     }
 
     // If this is the shutdown event than the add-on should already be started
     if (info.event == "shutdown") {
       this.checkMatches(this.started.get(id), info);
 
       this.started.delete(id);
       this.stopped.set(id, info);
+
+      // Chrome should still be registered at this point
+      let isRegistered = isManifestRegistered(installPath);
+      do_check_true(isRegistered);
+
+      // XPIProvider doesn't bother unregistering chrome on app shutdown but
+      // since we simulate restarts we must do so manually to keep the registry
+      // consistent.
+      if (info.reason == 2 /* APP_SHUTDOWN */)
+        Components.manager.removeBootstrappedManifestLocation(installPath);
     }
     else {
       this.checkAddonNotStarted(id);
     }
 
     if (info.event == "uninstall") {
+      // Chrome should be unregistered at this point
+      let isRegistered = isManifestRegistered(installPath);
+      do_check_false(isRegistered);
+
       this.installed.delete(id);
       this.uninstalled.set(id, info)
     }
     else if (info.event == "startup") {
       this.started.set(id, info);
 
+      // Chrome should be registered at this point
+      let isRegistered = isManifestRegistered(installPath);
+      do_check_true(isRegistered);
+
       for (let resolve of this.startupPromises)
         resolve();
       this.startupPromises = [];
     }
   }
 }
 
 function isNightlyChannel() {
@@ -582,16 +639,17 @@ function promiseShutdownManager() {
     return Promise.resolve(false);
   }
 
   let hookErr = null;
   Services.obs.notifyObservers(null, "quit-application-granted", null);
   return MockAsyncShutdown.hook()
     .then(null, err => hookErr = err)
     .then( () => {
+      BootstrapMonitor.shutdownCheck();
       gInternalManager = null;
 
       // Load the add-ons list as it was after application shutdown
       loadAddonsList();
 
       // Clear any crash report annotations
       gAppInfo.annotations = {};