Merge m-c to m-i
authorPhil Ringnalda <philringnalda@gmail.com>
Sat, 12 Sep 2015 10:34:34 -0700
changeset 294780 0bdadeda24894e4bee22d50fc613f1482a34e3eb
parent 294779 9f508ff5e0138d6f7ee1cf230d4e85421d2323ee (current diff)
parent 294759 7ef618c56760cbfcd6143c4fcd03e7c7ec99fb19 (diff)
child 294786 68718290640b0ca195344fa5cc4c55fbc260e19e
child 294806 8a316d4c6458cfda9ef83b9d0aa0feea44a0adff
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone43.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 m-i
browser/devtools/webconsole/NetworkPanel.xhtml
browser/devtools/webconsole/network-panel.js
browser/devtools/webconsole/test/browser_netpanel_longstring_expand.js
browser/devtools/webconsole/test/browser_webconsole_bug_594477_clickable_output.js
browser/devtools/webconsole/test/browser_webconsole_bug_602572_log_bodies_checkbox.js
browser/devtools/webconsole/test/browser_webconsole_bug_618311_close_panels.js
browser/devtools/webconsole/test/browser_webconsole_network_panel.js
browser/themes/shared/devtools/webconsole_networkpanel.css
--- 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="e938ac2795efeeb2ecec8c47b33c9f7f8183e4eb"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="2a7461a2c839280440239214552d3c2cf79b5e2d"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="f5d65f5b17d9766d7925aefd0486a1e526ae9bf0"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="c6cace53426b5be7e56c0fd202118009689bc707"/>
--- 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="e938ac2795efeeb2ecec8c47b33c9f7f8183e4eb"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="2a7461a2c839280440239214552d3c2cf79b5e2d"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="f5d65f5b17d9766d7925aefd0486a1e526ae9bf0"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="c6cace53426b5be7e56c0fd202118009689bc707"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <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="gaia.git" path="gaia" remote="mozillaorg" revision="e938ac2795efeeb2ecec8c47b33c9f7f8183e4eb"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="2a7461a2c839280440239214552d3c2cf79b5e2d"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="27eb2f04e149fc2c9976d881b1b5984bbe7ee089"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="067c08fb3e5744b42b68d1f861245f7d507109bc"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="f5d65f5b17d9766d7925aefd0486a1e526ae9bf0"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- 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="e938ac2795efeeb2ecec8c47b33c9f7f8183e4eb"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="2a7461a2c839280440239214552d3c2cf79b5e2d"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="f5d65f5b17d9766d7925aefd0486a1e526ae9bf0"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="c6cace53426b5be7e56c0fd202118009689bc707"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- 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="e938ac2795efeeb2ecec8c47b33c9f7f8183e4eb"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="2a7461a2c839280440239214552d3c2cf79b5e2d"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="f5d65f5b17d9766d7925aefd0486a1e526ae9bf0"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="c6cace53426b5be7e56c0fd202118009689bc707"/>
--- 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="e938ac2795efeeb2ecec8c47b33c9f7f8183e4eb"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="2a7461a2c839280440239214552d3c2cf79b5e2d"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="f5d65f5b17d9766d7925aefd0486a1e526ae9bf0"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="c6cace53426b5be7e56c0fd202118009689bc707"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <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="gaia.git" path="gaia" remote="mozillaorg" revision="e938ac2795efeeb2ecec8c47b33c9f7f8183e4eb"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="2a7461a2c839280440239214552d3c2cf79b5e2d"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="27eb2f04e149fc2c9976d881b1b5984bbe7ee089"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="067c08fb3e5744b42b68d1f861245f7d507109bc"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="f5d65f5b17d9766d7925aefd0486a1e526ae9bf0"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- 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="e938ac2795efeeb2ecec8c47b33c9f7f8183e4eb"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="2a7461a2c839280440239214552d3c2cf79b5e2d"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="f5d65f5b17d9766d7925aefd0486a1e526ae9bf0"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="c6cace53426b5be7e56c0fd202118009689bc707"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
-        "git_revision": "e938ac2795efeeb2ecec8c47b33c9f7f8183e4eb", 
+        "git_revision": "2a7461a2c839280440239214552d3c2cf79b5e2d", 
         "remote": "https://git.mozilla.org/releases/gaia.git", 
         "branch": ""
     }, 
-    "revision": "c0f536773eca24b5eaf30ceffe3bb8d41c51827f", 
+    "revision": "229ccafd68fd865b99244b220ba2d1d13ff62621", 
     "repo_path": "integration/gaia-central"
 }
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/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="e938ac2795efeeb2ecec8c47b33c9f7f8183e4eb"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="2a7461a2c839280440239214552d3c2cf79b5e2d"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="f5d65f5b17d9766d7925aefd0486a1e526ae9bf0"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="c6cace53426b5be7e56c0fd202118009689bc707"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- 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="e938ac2795efeeb2ecec8c47b33c9f7f8183e4eb"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="2a7461a2c839280440239214552d3c2cf79b5e2d"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="f5d65f5b17d9766d7925aefd0486a1e526ae9bf0"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="c6cace53426b5be7e56c0fd202118009689bc707"/>
--- a/browser/app/blocklist.xml
+++ b/browser/app/blocklist.xml
@@ -1,10 +1,10 @@
 <?xml version="1.0"?>
-<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1441146756000">
+<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1441833117000">
   <emItems>
       <emItem  blockID="i58" id="webmaster@buzzzzvideos.info">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                     <prefs>
               </prefs>
     </emItem>
       <emItem  blockID="i71" id="youtube@2youtube.com">
@@ -1948,16 +1948,22 @@
               </prefs>
     </emItem>
       <emItem  blockID="i492" id="{af95cc15-3b9b-45ae-8d9b-98d08eda3111}">
                         <versionRange  minVersion="0" maxVersion="*" severity="3">
                     </versionRange>
                     <prefs>
               </prefs>
     </emItem>
+      <emItem  blockID="i998" id="meOYKQEbBBjH5Ml91z0p9Aosgus8P55bjTa4KPfl@jetpack">
+                        <versionRange  minVersion="0" maxVersion="*" severity="3">
+                    </versionRange>
+                    <prefs>
+              </prefs>
+    </emItem>
       <emItem  blockID="i474" id="{906000a4-88d9-4d52-b209-7a772970d91f}">
                         <versionRange  minVersion="0" maxVersion="*" severity="3">
                     </versionRange>
                     <prefs>
               </prefs>
     </emItem>
       <emItem  blockID="i516" id="/^({3f3cddf8-f74d-430c-bd19-d2c9147aed3d}|{515b2424-5911-40bd-8a2c-bdb20286d8f5}|{17464f93-137e-4646-a0c6-0dc13faf0113}|{d1b5aad5-d1ae-4b20-88b1-feeaeb4c1ebc}|{aad50c91-b136-49d9-8b30-0e8d3ead63d0})$/">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
@@ -2164,16 +2170,22 @@
               </prefs>
     </emItem>
       <emItem  blockID="i396" id="/@(ft|putlocker|clickmovie|m2k|sharerepo|smarter-?)downloader\.com$/">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                     <prefs>
               </prefs>
     </emItem>
+      <emItem  blockID="i1000" id="jufa098j-LKooapd9jasJ9jliJsd@jetpack">
+                        <versionRange  minVersion="0" maxVersion="*" severity="3">
+                    </versionRange>
+                    <prefs>
+              </prefs>
+    </emItem>
       <emItem  blockID="i44" id="sigma@labs.mozilla">
                           <prefs>
               </prefs>
     </emItem>
       <emItem  blockID="i501" id="xivars@aol.com">
                         <versionRange  minVersion="0" maxVersion="*" severity="3">
                     </versionRange>
                     <prefs>
@@ -2308,16 +2320,22 @@
               </prefs>
     </emItem>
       <emItem  blockID="i493" id="12x3q@3244516.com">
                         <versionRange  minVersion="0" maxVersion="*" severity="3">
                     </versionRange>
                     <prefs>
               </prefs>
     </emItem>
+      <emItem  blockID="i996" id="9598582LLKmjasieijkaslesae@jetpack">
+                        <versionRange  minVersion="0" maxVersion="*" severity="3">
+                    </versionRange>
+                    <prefs>
+              </prefs>
+    </emItem>
       <emItem  blockID="i728" id="l@AdLJ7uz.net">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                     <prefs>
                   <pref>browser.startup.homepage</pref>
               </prefs>
     </emItem>
       <emItem  blockID="i694" id="59D317DB041748fdB89B47E6F96058F3@jetpack">
@@ -3017,20 +3035,20 @@
       <pluginItem  blockID="p459">
                   <match name="filename" exp="JavaAppletPlugin\.plugin" />                                    <versionRange  minVersion="Java 7 Update 25" maxVersion="Java 7 Update 44" severity="0" vulnerabilitystatus="1">
                                 <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
                               <versionRange  minVersion="17.0" maxVersion="*" />
                           </targetApplication>
                   </versionRange>
                         </pluginItem>
       <pluginItem  blockID="p556">
-                  <match name="filename" exp="npUnity3D32\.dll" />                      <versionRange  minVersion="0" maxVersion="4.3.4.99999999" severity="0" vulnerabilitystatus="1"></versionRange>
+                  <match name="filename" exp="npUnity3D32\.dll" />                      <versionRange  minVersion="0" maxVersion="4.6.6f1" severity="0" vulnerabilitystatus="1"></versionRange>
                         </pluginItem>
       <pluginItem  blockID="p558">
-            <match name="description" exp="^($|Unity Web Player version ([0-3]|(4\.([0-2]|3(\.[0-4])?[^0-9.]))))" />      <match name="filename" exp="Unity Web Player\.plugin" />                      <versionRange  severity="0" vulnerabilitystatus="1"></versionRange>
+            <match name="description" exp="^($|Unity Web Player version ([0-3]|(4\.([0-5]|6(\.([0-5]|6f1)))?[^0-9.])))" />      <match name="filename" exp="Unity Web Player\.plugin" />                      <versionRange  severity="0" vulnerabilitystatus="1"></versionRange>
                         </pluginItem>
       <pluginItem  blockID="p572">
                   <match name="filename" exp="npdjvu\.dll" />                      <versionRange  minVersion="0" maxVersion="6.1.4.27993" severity="0" vulnerabilitystatus="1"></versionRange>
                         </pluginItem>
       <pluginItem  blockID="p574">
                   <match name="filename" exp="NPDjVu\.plugin" />                      <versionRange  minVersion="0" maxVersion="6.1.1" severity="0" vulnerabilitystatus="1"></versionRange>
                         </pluginItem>
       <pluginItem  blockID="p592">
@@ -3154,16 +3172,22 @@
       <pluginItem  blockID="p962">
       <match name="name" exp="Java(\(TM\))? Plug-in 10\.(79|80)(\.[0-9]+)?([^\d\._]|$)" />            <match name="filename" exp="libnpjp2\.so" />                      <versionRange  severity="0" vulnerabilitystatus="1"></versionRange>
                             <infoURL>https://java.com/</infoURL>
           </pluginItem>
       <pluginItem  blockID="p964">
       <match name="name" exp="Java(\(TM\))? Plug-in 11\.45(\.[0-9]+)?([^\d\._]|$)" />            <match name="filename" exp="libnpjp2\.so" />                      <versionRange  severity="0" vulnerabilitystatus="1"></versionRange>
                             <infoURL>https://java.com/</infoURL>
           </pluginItem>
+      <pluginItem  blockID="p1002">
+                  <match name="filename" exp="npUnity3D32\.dll" />                      <versionRange  minVersion="5.0" maxVersion="5.0.3f1" severity="0" vulnerabilitystatus="1"></versionRange>
+                        </pluginItem>
+      <pluginItem  blockID="p1004">
+            <match name="description" exp="^($|Unity Web Player version 5.0(\.([0-2]|3f1))?[^0-9.])" />      <match name="filename" exp="Unity Web Player\.plugin" />                      <versionRange  severity="0" vulnerabilitystatus="1"></versionRange>
+                        </pluginItem>
     </pluginItems>
 
   <gfxItems>
     <gfxBlacklistEntry  blockID="g35">      <os>WINNT 6.1</os>      <vendor>0x10de</vendor>              <devices>
                       <device>0x0a6c</device>
                   </devices>
             <feature>DIRECT2D</feature>      <featureStatus>BLOCKED_DRIVER_VERSION</featureStatus>      <driverVersion>8.17.12.5896</driverVersion>      <driverVersionComparator>LESS_THAN_OR_EQUAL</driverVersionComparator>    </gfxBlacklistEntry>
     <gfxBlacklistEntry  blockID="g36">      <os>WINNT 6.1</os>      <vendor>0x10de</vendor>              <devices>
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1418,17 +1418,18 @@ pref("devtools.memory.enabled", false);
 // Enable the Performance tools
 pref("devtools.performance.enabled", true);
 
 // The default Performance UI settings
 pref("devtools.performance.memory.sample-probability", "0.05");
 // Can't go higher than this without causing internal allocation overflows while
 // serializing the allocations data over the RDP.
 pref("devtools.performance.memory.max-log-length", 125000);
-pref("devtools.performance.timeline.hidden-markers", "[\"Composite\"]");
+pref("devtools.performance.timeline.hidden-markers",
+  "[\"Composite\",\"CompositeForwardTransaction\"]");
 pref("devtools.performance.profiler.buffer-size", 10000000);
 pref("devtools.performance.profiler.sample-frequency-khz", 1);
 pref("devtools.performance.ui.invert-call-tree", true);
 pref("devtools.performance.ui.invert-flame-graph", false);
 pref("devtools.performance.ui.flatten-tree-recursion", true);
 pref("devtools.performance.ui.show-platform-data", false);
 pref("devtools.performance.ui.show-idle-blocks", true);
 pref("devtools.performance.ui.enable-memory", false);
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1130,21 +1130,25 @@ var gBrowserInit = {
     let mm = window.messageManager;
     mm.addMessageListener("PageVisibility:Show", function(message) {
       if (message.target == gBrowser.selectedBrowser) {
         setTimeout(pageShowEventHandlers, 0, message.data.persisted);
       }
     });
 
     gBrowser.addEventListener("AboutTabCrashedLoad", function(event) {
+      let browser = gBrowser.getBrowserForDocument(event.target);
 #ifdef MOZ_CRASHREPORTER
-      TabCrashReporter.onAboutTabCrashedLoad(gBrowser.getBrowserForDocument(event.target), {
+      TabCrashReporter.onAboutTabCrashedLoad(browser, {
         crashedTabCount: SessionStore.crashedTabCount,
       });
 #endif
+
+      // Reset the zoom for the tabcrashed page.
+      ZoomManager.setZoomForBrowser(browser, 1);
     }, false, true);
 
     gBrowser.addEventListener("AboutTabCrashedMessage", function(event) {
       let ownerDoc = event.originalTarget;
 
       if (!ownerDoc.documentURI.startsWith("about:tabcrashed")) {
         return;
       }
--- a/browser/base/content/socialchat.xml
+++ b/browser/base/content/socialchat.xml
@@ -800,20 +800,15 @@
         let winWidth = 400;
         let winHeight = 420;
         // ensure new window entirely within screen
         let left = Math.min(Math.max(eX, sX.value),
                             sX.value + sWidth.value - winWidth);
         let top = Math.min(Math.max(eY, sY.value),
                            sY.value + sHeight.value - winHeight);
 
-        let title = draggedChat.content.getAttribute("title");
-        this.detachChatbox(draggedChat, { screenX: left, screenY: top }).then(
-          chatbox => {
-            chatbox.contentWindow.document.title = title;
-          }
-        );
+        this.detachChatbox(draggedChat, { screenX: left, screenY: top });
         event.stopPropagation();
       ]]></handler>
     </handlers>
   </binding>
 
 </bindings>
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1106,17 +1106,16 @@
             this._appendStatusPanel();
 
             if (updateBlockedPopups)
               this.mCurrentBrowser.updateBlockedPopups();
 
             // Update the URL bar.
             var loc = this.mCurrentBrowser.currentURI;
 
-            // Bug 666809 - SecurityUI support for e10s
             var webProgress = this.mCurrentBrowser.webProgress;
             var securityUI = this.mCurrentBrowser.securityUI;
 
             this._callProgressListeners(null, "onLocationChange",
                                         [webProgress, null, loc, 0], true,
                                         false);
 
             if (securityUI) {
@@ -1548,16 +1547,26 @@
             // deactivate it if this is not the selected tab's browser or the
             // browser window is minimized.
             aBrowser.docShellIsActive = (aBrowser == this.selectedBrowser &&
                                          window.windowState != window.STATE_MINIMIZED);
 
             // Restore the progress listener.
             aBrowser.webProgress.addProgressListener(filter, Ci.nsIWebProgress.NOTIFY_ALL);
 
+            // Restore the securityUI state.
+            let securityUI = aBrowser.securityUI;
+            let state = securityUI ? securityUI.state
+                                   : Ci.nsIWebProgressListener.STATE_IS_INSECURE;
+            // Include the true final argument to indicate that this event is
+            // simulated (instead of being observed by the webProgressListener).
+            this._callProgressListeners(aBrowser, "onSecurityChange",
+                                        [aBrowser.webProgress, null, securityUI.state, true],
+                                        true, false);
+
             if (aShouldBeRemote) {
               // Switching the browser to be remote will connect to a new child
               // process so the browser can no longer be considered to be
               // crashed.
               tab.removeAttribute("crashed");
             } else {
               aBrowser.messageManager.sendAsyncMessage("Browser:AppTab", { isAppTab: tab.pinned })
 
--- a/browser/components/loop/content/css/contacts.css
+++ b/browser/components/loop/content/css/contacts.css
@@ -246,28 +246,20 @@ html[dir="rtl"] .contact-filter {
   background-image: url("../shared/img/avatars.svg#green-avatar");
   background-color: #56B397;
 }
 
 .contact > .avatar > img {
   width: 100%;
 }
 
-.panel-text-medium,
-.panel-text-large {
+.panel-text-medium{
   margin: 3px;
   color: #4a4a4a;
-}
-
-.panel-text-medium {
-  font-size: 1.2rem;
-}
-
-.panel-text-large {
-  font-size: 2.2rem;
+  font-size: 1.3rem;
 }
 
 .contact > .details > .username {
   font-size: 1.3rem;
   line-height: 20px;
   color: #000;
 }
 
--- a/browser/components/loop/content/css/panel.css
+++ b/browser/components/loop/content/css/panel.css
@@ -287,18 +287,18 @@ html[dir="rtl"] .tab-view li:nth-child(2
 
 
 .no-conversations-message {
   /* example of vertical aligning a container in an element
     see: http://zerosixthree.se/vertical-align-anything-with-just-3-lines-of-css/ */
   position: relative;
   top: 50%;
   transform: translateY(-50%);
-  padding-top: 75px;
-  padding-bottom: 10px;
+  padding-top: 11rem;
+  padding-bottom: 1rem;
   background-image: url("../shared/img/empty_conversations.svg");
 }
 
 .panel-text-medium,
 .panel-text-large {
   margin: 3px 0;
 }
 
@@ -576,21 +576,21 @@ html[dir="rtl"] .room-entry-call-btn {
   height: 24px;
   background-size: 12px;
   background-repeat: no-repeat;
   vertical-align: middle;
 }
 
 html[dir="rtl"] .room-entry-context-actions > .dropdown-menu {
   right: auto;
-  left: 45px;
+  left: 21px;
 }
 
 .room-entry-context-actions > .dropdown-menu {
-  right: 45px;
+  right: 21px;
   bottom: auto;
   left: auto;
 }
 
 /* Keep ".room-list > .room-entry > h2" in sync with these. */
 .room-entry-context-item {
   display: inline-block;
   vertical-align: middle;
--- a/browser/components/loop/content/js/panel.js
+++ b/browser/components/loop/content/js/panel.js
@@ -824,21 +824,21 @@ loop.panel = (function(_, mozL10n) {
       );
     },
 
     _renderNoRoomsView: function() {
       return (
         React.createElement("div", {className: "rooms"}, 
           React.createElement("div", {className: "room-list-empty"}, 
             React.createElement("div", {className: "no-conversations-message"}, 
-              React.createElement("p", {className: "panel-text-large"}, 
-                mozL10n.get("no_conversations_message_heading")
+              React.createElement("p", {className: "panel-text-medium"}, 
+                mozL10n.get("no_conversations_message_heading2")
               ), 
               React.createElement("p", {className: "panel-text-medium"}, 
-                mozL10n.get("no_conversations_start_message")
+                mozL10n.get("no_conversations_start_message2")
               )
             )
           ), 
           this._renderNewRoomButton()
         )
       );
     },
 
--- a/browser/components/loop/content/js/panel.jsx
+++ b/browser/components/loop/content/js/panel.jsx
@@ -824,21 +824,21 @@ loop.panel = (function(_, mozL10n) {
       );
     },
 
     _renderNoRoomsView: function() {
       return (
         <div className="rooms">
           <div className="room-list-empty">
             <div className="no-conversations-message">
-              <p className="panel-text-large">
-                {mozL10n.get("no_conversations_message_heading")}
+              <p className="panel-text-medium">
+                {mozL10n.get("no_conversations_message_heading2")}
               </p>
               <p className="panel-text-medium">
-                {mozL10n.get("no_conversations_start_message")}
+                {mozL10n.get("no_conversations_start_message2")}
               </p>
             </div>
           </div>
           {this._renderNewRoomButton()}
         </div>
       );
     },
 
--- a/browser/components/loop/content/shared/img/empty_conversations.svg
+++ b/browser/components/loop/content/shared/img/empty_conversations.svg
@@ -1,1 +1,1 @@
-<svg width="119" height="70" viewBox="0 0 119 70" xmlns="http://www.w3.org/2000/svg"><g fill="#D8D8D8"><path d="M96.767 5c12.017 0 21.763 8.244 21.763 18.41 0 5.061-2.416 9.647-6.323 12.975.679 2.303 2.022 5.429 4.677 8.481-.454.773-7.931-1.954-13.201-3.994-2.175.613-4.497.949-6.916.949-12.02 0-21.766-8.243-21.766-18.41 0-10.166 9.746-18.41 21.766-18.41z" fill-opacity=".8"/><path d="M21.763 5c-12.017 0-21.763 8.244-21.763 18.41 0 5.061 2.416 9.647 6.323 12.975-.679 2.303-2.022 5.429-4.677 8.481.454.773 7.931-1.954 13.201-3.994 2.175.613 4.497.949 6.916.949 12.02 0 21.766-8.243 21.766-18.41 0-10.166-9.746-18.41-21.766-18.41z" fill-opacity=".8"/><path d="M56.742 4c-18.631 0-33.742 12.782-33.742 28.543 0 7.847 3.747 14.957 9.803 20.117-1.052 3.571-3.135 8.418-7.251 13.149.704 1.199 12.296-3.03 20.467-6.193 3.372.951 6.973 1.471 10.723 1.471 18.637 0 33.746-12.78 33.746-28.544 0-15.761-15.11-28.543-33.746-28.543z" stroke="#FBFBFB" stroke-width="4"/></g></svg>
\ No newline at end of file
+<svg width="128" height="128" viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg"><title>Hello_Conversations@1x</title><g fill="none" fill-rule="evenodd"><g fill-opacity=".8" fill="#D8D8D8"><path d="M92.6857529,36.4972478 C94.0074365,36.7092895 95.3714061,36.8202443 96.765995,36.8202443 C99.1850012,36.8202443 101.507433,36.4843962 103.682261,35.8711789 C108.95254,37.9114461 116.428855,40.6388416 116.883051,39.8656193 C114.228301,36.8141527 112.88469,33.6883692 112.206137,31.3849465 C116.112562,28.0573291 118.529038,23.471195 118.529038,18.4099191 C118.529038,8.2443202 108.782585,0 96.765995,0 C91.4188478,0 86.5218392,1.63140695 82.732597,4.33762852 C89.8596493,10.1193334 94.2968293,18.2546551 94.2968293,27.2647358 C94.2968293,30.4757572 93.7334546,33.5755489 92.6857559,36.4972483 Z" transform="translate(5 32)"/><path d="M20.9154969,36.8064637 C18.8009901,36.7376004 16.766387,36.4124345 14.846777,35.8711789 C9.57649798,37.9114461 2.10018319,40.6388416 1.64598695,39.8656193 C4.30073659,36.8141527 5.64434776,33.6883692 6.32290093,31.3849465 C2.41647584,28.0573291 0,23.471195 0,18.4099191 C0,8.2443202 9.74645257,0 21.7630429,0 C25.8798482,0 29.7298309,0.967027199 33.0128711,2.64707103 C24.5779765,8.47249535 19.1912092,17.3376798 19.1912092,27.2647358 C19.1912092,30.5889558 19.7953644,33.7943831 20.9154969,36.8064637 Z" transform="translate(5 32)"/></g><path d="M62,31 C43.77575,31 29,43.92775 29,59.875 C29,68.21575 33.06725,75.710875 39.531125,80.9785 C39.20525,82.084 38.763875,83.2885 38.13275,84.571375 C35.171,90.610375 33.125,92.875 33.125,92.875 C33.125,92.875 40.562375,91.4725 46.898375,88.321 C48.03275,87.755875 48.952625,87.211375 49.785875,86.683375 C53.564375,88.003375 57.681125,88.75 62,88.75 C80.22425,88.75 95,75.82225 95,59.875 C95,43.92775 80.22425,31 62,31 L62,31 Z M72.3125,47.24425 C75.303125,47.24425 77.728625,49.665625 77.728625,52.65625 C77.728625,55.646875 75.303125,58.072375 72.3125,58.072375 C69.321875,58.072375 66.9005,55.646875 66.9005,52.65625 C66.9005,49.665625 69.321875,47.24425 72.3125,47.24425 L72.3125,47.24425 Z M51.6875,47.24425 C54.678125,47.24425 57.103625,49.665625 57.103625,52.65625 C57.103625,55.646875 54.678125,58.072375 51.6875,58.072375 C48.696875,58.072375 46.2755,55.646875 46.2755,52.65625 C46.2755,49.665625 48.696875,47.24425 51.6875,47.24425 L51.6875,47.24425 Z M62,78.64375 C45.231875,78.64375 41.375,64 41.375,64 C41.375,64 50.099375,68.125 62,68.125 C73.715,68.125 82.625,64 82.625,64 C82.625,64 78.768125,78.64375 62,78.64375 L62,78.64375 Z" fill="#00A9DC"/></g></svg>
\ No newline at end of file
--- a/browser/components/loop/content/shared/js/actions.js
+++ b/browser/components/loop/content/shared/js/actions.js
@@ -223,49 +223,41 @@ loop.shared.actions = (function() {
      */
     VideoDimensionsChanged: Action.define("videoDimensionsChanged", {
       isLocal: Boolean,
       videoType: String,
       dimensions: Object
     }),
 
     /**
-     * Video has been enabled from the remote sender.
-     *
-     * XXX somewhat tangled up with remote video muting semantics; see bug
-     * 1171969
-     *
-     * @note if/when we want to untangle this, we'll may want to include the
-     *       reason provided by the SDK and documented hereI:
-     *       https://tokbox.com/opentok/libraries/client/js/reference/VideoEnabledChangedEvent.html
+     * A stream from local or remote media has been created.
      */
-    RemoteVideoEnabled: Action.define("remoteVideoEnabled", {
-      /* The SDK video object that the views will be copying the remote
-         stream from. */
+    MediaStreamCreated: Action.define("mediaStreamCreated", {
+      hasVideo: Boolean,
+      isLocal: Boolean,
       srcVideoObject: Object
     }),
 
     /**
-     * Video has been disabled by the remote sender.
-     *
-     *  @see RemoteVideoEnabled
+     * A stream from local or remote media has been destroyed.
      */
-    RemoteVideoDisabled: Action.define("remoteVideoDisabled", {
+    MediaStreamDestroyed: Action.define("mediaStreamDestroyed", {
+      isLocal: Boolean
     }),
 
     /**
-     * Video from the local camera has been enabled.
+     * Used to inform that the remote stream has enabled or disabled the video
+     * part of the stream.
      *
-     * XXX we should implement a LocalVideoDisabled action to cleanly prevent
-     * leakage; see bug 1171978 for details
+     * @note We'll may want to include the future the reason provided by the SDK
+     *       and documented here:
+     *       https://tokbox.com/opentok/libraries/client/js/reference/VideoEnabledChangedEvent.html
      */
-    LocalVideoEnabled: Action.define("localVideoEnabled", {
-      /* The SDK video object that the views will be copying the remote
-         stream from. */
-      srcVideoObject: Object
+    RemoteVideoStatus: Action.define("remoteVideoStatus", {
+      videoEnabled: Boolean
     }),
 
     /**
      * Used to mute or unmute a stream
      */
     SetMute: Action.define("setMute", {
       // The part of the stream to enable, e.g. "audio" or "video"
       type: String,
--- a/browser/components/loop/content/shared/js/activeRoomStore.js
+++ b/browser/components/loop/content/shared/js/activeRoomStore.js
@@ -247,19 +247,19 @@ loop.store.ActiveRoomStore = (function()
         "setMute",
         "screenSharingState",
         "receivingScreenShare",
         "remotePeerDisconnected",
         "remotePeerConnected",
         "windowUnload",
         "leaveRoom",
         "feedbackComplete",
-        "localVideoEnabled",
-        "remoteVideoEnabled",
-        "remoteVideoDisabled",
+        "mediaStreamCreated",
+        "mediaStreamDestroyed",
+        "remoteVideoStatus",
         "videoDimensionsChanged",
         "startScreenShare",
         "endScreenShare",
         "updateSocialShareInfo",
         "connectionStatus",
         "mediaConnected"
       ]);
     },
@@ -627,41 +627,62 @@ loop.store.ActiveRoomStore = (function()
      */
     setMute: function(actionData) {
       var muteState = {};
       muteState[actionData.type + "Muted"] = !actionData.enabled;
       this.setStoreState(muteState);
     },
 
     /**
-     * Records the local video object for the room.
+     * Handles a media stream being created. This may be a local or a remote stream.
      *
-     * @param {sharedActions.LocalVideoEnabled} actionData
+     * @param {sharedActions.MediaStreamCreated} actionData
      */
-    localVideoEnabled: function(actionData) {
-      this.setStoreState({localSrcVideoObject: actionData.srcVideoObject});
-    },
+    mediaStreamCreated: function(actionData) {
+      if (actionData.isLocal) {
+        this.setStoreState({
+          localVideoEnabled: actionData.hasVideo,
+          localSrcVideoObject: actionData.srcVideoObject
+        });
+        return;
+      }
 
-    /**
-     * Records the remote video object for the room.
-     *
-     * @param  {sharedActions.RemoteVideoEnabled} actionData
-     */
-    remoteVideoEnabled: function(actionData) {
       this.setStoreState({
-        remoteVideoEnabled: true,
+        remoteVideoEnabled: actionData.hasVideo,
         remoteSrcVideoObject: actionData.srcVideoObject
       });
     },
 
     /**
-     * Records when remote video is disabled (e.g. due to mute).
+     * Handles a media stream being destroyed. This may be a local or a remote stream.
+     *
+     * @param {sharedActions.MediaStreamDestroyed} actionData
      */
-    remoteVideoDisabled: function() {
-      this.setStoreState({remoteVideoEnabled: false});
+    mediaStreamDestroyed: function(actionData) {
+      if (actionData.isLocal) {
+        this.setStoreState({
+          localSrcVideoObject: null
+        });
+        return;
+      }
+
+      this.setStoreState({
+        remoteSrcVideoObject: null
+      });
+    },
+
+    /**
+     * Handles a remote stream having video enabled or disabled.
+     *
+     * @param {sharedActions.RemoteVideoStatus} actionData
+     */
+    remoteVideoStatus: function(actionData) {
+      this.setStoreState({
+        remoteVideoEnabled: actionData.videoEnabled
+      });
     },
 
     /**
      * Records when the remote media has been connected.
      */
     mediaConnected: function() {
       this.setStoreState({mediaConnected: true});
     },
@@ -800,16 +821,17 @@ loop.store.ActiveRoomStore = (function()
       var participants = this.getStoreState("participants");
       if (participants) {
         participants = participants.filter(function(participant) {
           return participant.owner;
         });
       }
 
       this.setStoreState({
+        mediaConnected: false,
         participants: participants,
         roomState: ROOM_STATES.SESSION_CONNECTED,
         remoteSrcVideoObject: null
       });
     },
 
     /**
      * Handles an SDK status update, forwarding it to the server.
--- a/browser/components/loop/content/shared/js/conversationStore.js
+++ b/browser/components/loop/content/shared/js/conversationStore.js
@@ -218,19 +218,19 @@ loop.store = loop.store || {};
         "connectCall",
         "hangupCall",
         "remotePeerDisconnected",
         "cancelCall",
         "retryCall",
         "mediaConnected",
         "setMute",
         "fetchRoomEmailLink",
-        "localVideoEnabled",
-        "remoteVideoDisabled",
-        "remoteVideoEnabled",
+        "mediaStreamCreated",
+        "mediaStreamDestroyed",
+        "remoteVideoStatus",
         "windowUnload"
       ]);
 
       this.setStoreState({
         apiKey: actionData.apiKey,
         callerId: actionData.callerId,
         callId: actionData.callId,
         callState: CALL_STATES.GATHER,
@@ -435,50 +435,61 @@ loop.store = loop.store || {};
           return;
         }
         this.setStoreState({"emailLink": createdRoomData.roomUrl});
         this.mozLoop.telemetryAddValue("LOOP_ROOM_CREATE", buckets.CREATE_SUCCESS);
       }.bind(this));
     },
 
     /**
-     * Handles when the remote stream has been enabled and is supplied.
+     * Handles a media stream being created. This may be a local or a remote stream.
      *
-     * @param  {sharedActions.RemoteVideoEnabled} actionData
+     * @param {sharedActions.MediaStreamCreated} actionData
      */
-    remoteVideoEnabled: function(actionData) {
+    mediaStreamCreated: function(actionData) {
+      if (actionData.isLocal) {
+        this.setStoreState({
+          localVideoEnabled: actionData.hasVideo,
+          localSrcVideoObject: actionData.srcVideoObject
+        });
+        return;
+      }
+
       this.setStoreState({
-        remoteVideoEnabled: true,
+        remoteVideoEnabled: actionData.hasVideo,
         remoteSrcVideoObject: actionData.srcVideoObject
       });
     },
 
     /**
-     * Handles when the remote stream has been disabled, e.g. due to video mute.
+     * Handles a media stream being destroyed. This may be a local or a remote stream.
      *
-     * @param {sharedActions.RemoteVideoDisabled} actionData
+     * @param {sharedActions.MediaStreamDestroyed} actionData
      */
-    remoteVideoDisabled: function(actionData) {
+    mediaStreamDestroyed: function(actionData) {
+      if (actionData.isLocal) {
+        this.setStoreState({
+          localSrcVideoObject: null
+        });
+        return;
+      }
+
       this.setStoreState({
-        remoteVideoEnabled: false,
-        remoteSrcVideoObject: undefined});
+        remoteSrcVideoObject: null
+      });
     },
 
     /**
-     * Handles when the local stream is supplied.
-     *
-     * XXX should write a localVideoDisabled action in otSdkDriver.js to
-     * positively ensure proper cleanup (handled by window teardown currently)
-     * (see bug 1171978)
+     * Handles a remote stream having video enabled or disabled.
      *
-     * @param  {sharedActions.LocalVideoEnabled} actionData
+     * @param {sharedActions.RemoteVideoStatus} actionData
      */
-    localVideoEnabled: function(actionData) {
+    remoteVideoStatus: function(actionData) {
       this.setStoreState({
-        localSrcVideoObject: actionData.srcVideoObject
+        remoteVideoEnabled: actionData.videoEnabled
       });
     },
 
     /**
      * Called when the window is unloaded, either by code, or by the user
      * explicitly closing it.  Expected to do any necessary housekeeping, such
      * as shutting down the call cleanly and adding any relevant telemetry data.
      */
--- a/browser/components/loop/content/shared/js/otSdkDriver.js
+++ b/browser/components/loop/content/shared/js/otSdkDriver.js
@@ -265,16 +265,22 @@ loop.OTSdkDriver = (function() {
      * Disconnects the sdk session.
      */
     disconnectSession: function() {
       this.endScreenShare();
 
       this.dispatcher.dispatch(new sharedActions.DataChannelsAvailable({
         available: false
       }));
+      this.dispatcher.dispatch(new sharedActions.MediaStreamDestroyed({
+        isLocal: true
+      }));
+      this.dispatcher.dispatch(new sharedActions.MediaStreamDestroyed({
+        isLocal: false
+      }));
 
       if (this.session) {
         this.session.off("sessionDisconnected streamCreated streamDestroyed " +
                          "connectionCreated connectionDestroyed " +
                          "streamPropertyChanged signal:readyForDataChannel");
         this.session.disconnect();
         delete this.session;
 
@@ -587,23 +593,21 @@ loop.OTSdkDriver = (function() {
         this._mockSubscribeEl.querySelector("video");
       if (!sdkSubscriberVideo) {
         console.error("sdkSubscriberVideo unexpectedly falsy!");
       }
 
       sdkSubscriberObject.on("videoEnabled", this._onVideoEnabled.bind(this));
       sdkSubscriberObject.on("videoDisabled", this._onVideoDisabled.bind(this));
 
-      // XXX for some reason, the SDK deliberately suppresses sending the
-      // videoEnabled event after subscribe, in spite of docs claiming
-      // otherwise, so we do it ourselves.
-      if (sdkSubscriberObject.stream.hasVideo) {
-        this.dispatcher.dispatch(new sharedActions.RemoteVideoEnabled({
-          srcVideoObject: sdkSubscriberVideo}));
-      }
+      this.dispatcher.dispatch(new sharedActions.MediaStreamCreated({
+        hasVideo: sdkSubscriberObject.stream[STREAM_PROPERTIES.HAS_VIDEO],
+        isLocal: false,
+        srcVideoObject: sdkSubscriberVideo
+      }));
 
       this._subscribedRemoteStream = true;
       if (this._checkAllStreamsConnected()) {
         this._setTwoWayMediaStartTime(performance.now());
         this.dispatcher.dispatch(new sharedActions.MediaConnected());
       }
 
       this._setupDataChannelIfNeeded(sdkSubscriberObject.stream.connection);
@@ -752,23 +756,27 @@ loop.OTSdkDriver = (function() {
      * Handles the event when the local stream is created.
      *
      * @param {StreamEvent} event The event details:
      * https://tokbox.com/opentok/libraries/client/js/reference/StreamEvent.html
      */
     _onLocalStreamCreated: function(event) {
       this._notifyMetricsEvent("Publisher.streamCreated");
 
-      if (event.stream[STREAM_PROPERTIES.HAS_VIDEO]) {
-
-        var sdkLocalVideo = this._mockPublisherEl.querySelector("video");
+      var sdkLocalVideo = this._mockPublisherEl.querySelector("video");
+      var hasVideo = event.stream[STREAM_PROPERTIES.HAS_VIDEO];
 
-        this.dispatcher.dispatch(new sharedActions.LocalVideoEnabled(
-              {srcVideoObject: sdkLocalVideo}));
+      this.dispatcher.dispatch(new sharedActions.MediaStreamCreated({
+        hasVideo: hasVideo,
+        isLocal: true,
+        srcVideoObject: sdkLocalVideo
+      }));
 
+      // Only dispatch the video dimensions if we actually have video.
+      if (hasVideo) {
         this.dispatcher.dispatch(new sharedActions.VideoDimensionsChanged({
           isLocal: true,
           videoType: event.stream.videoType,
           dimensions: event.stream[STREAM_PROPERTIES.VIDEO_DIMENSIONS]
         }));
       }
     },
 
@@ -831,38 +839,43 @@ loop.OTSdkDriver = (function() {
      */
     _onRemoteStreamDestroyed: function(event) {
       this._notifyMetricsEvent("Session.streamDestroyed");
 
       if (event.stream.videoType !== "screen") {
         this.dispatcher.dispatch(new sharedActions.DataChannelsAvailable({
           available: false
         }));
+        this.dispatcher.dispatch(new sharedActions.MediaStreamDestroyed({
+          isLocal: false
+        }));
         delete this._subscriberChannel;
         delete this._mockSubscribeEl;
         return;
       }
 
       // All we need to do is notify the store we're no longer receiving,
       // the sdk should do the rest.
       this.dispatcher.dispatch(new sharedActions.ReceivingScreenShare({
         receiving: false
       }));
-
       delete this._mockScreenShareEl;
     },
 
     /**
      * Handles the event when the remote stream is destroyed.
      */
     _onLocalStreamDestroyed: function() {
       this._notifyMetricsEvent("Publisher.streamDestroyed");
       this.dispatcher.dispatch(new sharedActions.DataChannelsAvailable({
         available: false
       }));
+      this.dispatcher.dispatch(new sharedActions.MediaStreamDestroyed({
+        isLocal: true
+      }));
       delete this._publisherChannel;
       delete this._mockPublisherEl;
     },
 
     /**
      * Called from the sdk when the media access dialog is opened.
      * Prevents the default action, to prevent the SDK's "allow access"
      * dialog from being shown.
@@ -947,33 +960,34 @@ loop.OTSdkDriver = (function() {
      * @private
      */
     _onVideoEnabled: function(event) {
       var sdkSubscriberVideo = this._mockSubscribeEl.querySelector("video");
       if (!sdkSubscriberVideo) {
         console.error("sdkSubscriberVideo unexpectedly falsy!");
       }
 
-      this.dispatcher.dispatch(
-        new sharedActions.RemoteVideoEnabled(
-          {srcVideoObject: sdkSubscriberVideo}));
+      this.dispatcher.dispatch(new sharedActions.RemoteVideoStatus({
+        videoEnabled: true
+      }));
     },
 
     /**
      * Handle the SDK disabling of remote video by dispatching the
      * appropriate event.
      *
      * @param event {OT.VideoEnabledChangedEvent) from the SDK
      *
      * @see https://tokbox.com/opentok/libraries/client/js/reference/VideoEnabledChangedEvent.html
      * @private
      */
     _onVideoDisabled: function(event) {
-      this.dispatcher.dispatch(
-        new sharedActions.RemoteVideoDisabled());
+      this.dispatcher.dispatch(new sharedActions.RemoteVideoStatus({
+        videoEnabled: false
+      }));
     },
 
     /**
      * Publishes the local stream if the session is connected
      * and the publisher is ready.
      */
     _maybePublishLocalStream: function() {
       if (this._sessionConnected && this._publisherReady) {
--- a/browser/components/loop/test/desktop-local/panel_test.js
+++ b/browser/components/loop/test/desktop-local/panel_test.js
@@ -843,17 +843,19 @@ describe("loop.panel", function() {
 
       expect(node.querySelectorAll(".room-list-empty").length).to.eql(1);
     });
 
     it("should call mozL10n.get for room empty strings", function() {
       var view = createTestComponent();
 
       sinon.assert.calledWithExactly(document.mozL10n.get,
-                                     "no_conversations_message_heading");
+                                     "no_conversations_message_heading2");
+      sinon.assert.calledWithExactly(document.mozL10n.get,
+                                     "no_conversations_start_message2");
     });
 
     it("should display a loading animation when rooms are pending", function() {
       var view = createTestComponent();
       roomStore.setStoreState({pendingInitialRetrieval: true});
 
       expect(view.getDOMNode().querySelectorAll(".room-list-loading").length).to.eql(1);
     });
--- a/browser/components/loop/test/shared/activeRoomStore_test.js
+++ b/browser/components/loop/test/shared/activeRoomStore_test.js
@@ -989,58 +989,134 @@ describe("loop.store.ActiveRoomStore", f
         type: "video",
         enabled: false
       }));
 
       expect(store.getStoreState().videoMuted).eql(true);
     });
   });
 
-  describe("#localVideoEnabled", function() {
-    it("should add a localSrcVideoObject to the store", function() {
-      var fakeVideoElement = {name: "fakeVideoElement"};
-      expect(store.getStoreState()).to.not.have.property("localSrcVideoObject");
-
-      store.localVideoEnabled({srcVideoObject: fakeVideoElement});
-
-      expect(store.getStoreState()).to.have.property("localSrcVideoObject",
-        fakeVideoElement);
-    });
-  });
-
-  describe("#remoteVideoEnabled", function() {
+  describe("#mediaStreamCreated", function() {
     var fakeVideoElement;
 
     beforeEach(function() {
       fakeVideoElement = {name: "fakeVideoElement"};
     });
 
-    it("should add a remoteSrcVideoObject to the store", function() {
+    it("should add a local video object to the store", function() {
+      expect(store.getStoreState()).to.not.have.property("localSrcVideoObject");
+
+      store.mediaStreamCreated(new sharedActions.MediaStreamCreated({
+        hasVideo: false,
+        isLocal: true,
+        srcVideoObject: fakeVideoElement
+      }));
+
+      expect(store.getStoreState().localSrcVideoObject).eql(fakeVideoElement);
+      expect(store.getStoreState()).to.not.have.property("remoteSrcVideoObject");
+    });
+
+    it("should set the local video enabled", function() {
+      store.setStoreState({
+        localVideoEnabled: false,
+        remoteVideoEnabled: false
+      });
+
+      store.mediaStreamCreated(new sharedActions.MediaStreamCreated({
+        hasVideo: true,
+        isLocal: true,
+        srcVideoObject: fakeVideoElement
+      }));
+
+      expect(store.getStoreState().localVideoEnabled).eql(true);
+      expect(store.getStoreState().remoteVideoEnabled).eql(false);
+    });
+
+    it("should add a remote video object to the store", function() {
       expect(store.getStoreState()).to.not.have.property("remoteSrcVideoObject");
 
-      store.remoteVideoEnabled({srcVideoObject: fakeVideoElement});
+      store.mediaStreamCreated(new sharedActions.MediaStreamCreated({
+        hasVideo: false,
+        isLocal: false,
+        srcVideoObject: fakeVideoElement
+      }));
 
-      expect(store.getStoreState()).to.have.property("remoteSrcVideoObject",
-        fakeVideoElement);
+      expect(store.getStoreState()).not.have.property("localSrcVideoObject");
+      expect(store.getStoreState().remoteSrcVideoObject).eql(fakeVideoElement);
     });
 
-    it("should set remoteVideoEnabled", function() {
-      store.remoteVideoEnabled({srcVideoObject: fakeVideoElement});
+    it("should set the remote video enabled", function() {
+      store.setStoreState({
+        localVideoEnabled: false,
+        remoteVideoEnabled: false
+      });
 
+      store.mediaStreamCreated(new sharedActions.MediaStreamCreated({
+        hasVideo: true,
+        isLocal: false,
+        srcVideoObject: fakeVideoElement
+      }));
+
+      expect(store.getStoreState().localVideoEnabled).eql(false);
       expect(store.getStoreState().remoteVideoEnabled).eql(true);
     });
   });
 
-  describe("#remoteVideoDisabled", function() {
+  describe("#mediaStreamDestroyed", function() {
+    var fakeVideoElement;
+
+    beforeEach(function() {
+      fakeVideoElement = {name: "fakeVideoElement"};
+
+      store.setStoreState({
+        localSrcVideoObject: fakeVideoElement,
+        remoteSrcVideoObject: fakeVideoElement
+      });
+    });
+
+    it("should clear the local video object", function() {
+      store.mediaStreamDestroyed(new sharedActions.MediaStreamDestroyed({
+        isLocal: true
+      }));
+
+      expect(store.getStoreState().localSrcVideoObject).eql(null);
+      expect(store.getStoreState().remoteSrcVideoObject).eql(fakeVideoElement);
+    });
+
+    it("should clear the remote video object", function() {
+      store.mediaStreamDestroyed(new sharedActions.MediaStreamDestroyed({
+        isLocal: false
+      }));
+
+      expect(store.getStoreState().localSrcVideoObject).eql(fakeVideoElement);
+      expect(store.getStoreState().remoteSrcVideoObject).eql(null);
+    });
+  });
+
+  describe("#remoteVideoStatus", function() {
+    it("should set remoteVideoEnabled to true", function() {
+      store.setStoreState({
+        remoteVideoEnabled: false
+      });
+
+      store.remoteVideoStatus(new sharedActions.RemoteVideoStatus({
+        videoEnabled: true
+      }));
+
+      expect(store.getStoreState().remoteVideoEnabled).eql(true);
+    });
+
     it("should set remoteVideoEnabled to false", function() {
       store.setStoreState({
         remoteVideoEnabled: true
       });
 
-      store.remoteVideoDisabled();
+      store.remoteVideoStatus(new sharedActions.RemoteVideoStatus({
+        videoEnabled: false
+      }));
 
       expect(store.getStoreState().remoteVideoEnabled).eql(false);
     });
   });
 
   describe("#mediaConnected", function() {
     it("should set mediaConnected to true", function() {
       store.mediaConnected();
@@ -1265,16 +1341,26 @@ describe("loop.store.ActiveRoomStore", f
 
   describe("#remotePeerDisconnected", function() {
     it("should set the state to `SESSION_CONNECTED`", function() {
       store.remotePeerDisconnected();
 
       expect(store.getStoreState().roomState).eql(ROOM_STATES.SESSION_CONNECTED);
     });
 
+    it("should clear the mediaConnected state", function() {
+      store.setStoreState({
+        mediaConnected: true
+      });
+
+      store.remotePeerDisconnected();
+
+      expect(store.getStoreState().mediaConnected).eql(false);
+    });
+
     it("should clear the remoteSrcVideoObject", function() {
       store.setStoreState({
         remoteSrcVideoObject: { name: "fakeVideoElement" }
       });
 
       store.remotePeerDisconnected();
 
       expect(store.getStoreState().remoteSrcVideoObject).eql(null);
--- a/browser/components/loop/test/shared/conversationStore_test.js
+++ b/browser/components/loop/test/shared/conversationStore_test.js
@@ -950,62 +950,127 @@ describe("loop.store.ConversationStore",
       store._websocket = fakeWebsocket;
 
       store.mediaConnected(new sharedActions.MediaConnected());
 
       expect(store.getStoreState("mediaConnected")).eql(true);
     });
   });
 
-  describe("#localVideoEnabled", function() {
-    it("should set store.localSrcVideoObject from the action data", function () {
-      store.localVideoEnabled(
-        new sharedActions.LocalVideoEnabled({srcVideoObject: fakeVideoElement}));
+  describe("#mediaStreamCreated", function() {
+    it("should add a local video object to the store", function() {
+      expect(store.getStoreState()).to.not.have.property("localSrcVideoObject");
+
+      store.mediaStreamCreated(new sharedActions.MediaStreamCreated({
+        hasVideo: false,
+        isLocal: true,
+        srcVideoObject: fakeVideoElement
+      }));
+
+      expect(store.getStoreState().localSrcVideoObject).eql(fakeVideoElement);
+      expect(store.getStoreState()).to.not.have.property("remoteSrcVideoObject");
+    });
+
+    it("should set the local video enabled", function() {
+      store.setStoreState({
+        localVideoEnabled: false,
+        remoteVideoEnabled: false
+      });
+
+      store.mediaStreamCreated(new sharedActions.MediaStreamCreated({
+        hasVideo: true,
+        isLocal: true,
+        srcVideoObject: fakeVideoElement
+      }));
 
-      expect(store.getStoreState("localSrcVideoObject")).eql(fakeVideoElement);
+      expect(store.getStoreState().localVideoEnabled).eql(true);
+      expect(store.getStoreState().remoteVideoEnabled).eql(false);
+    });
+
+    it("should add a remote video object to the store", function() {
+      expect(store.getStoreState()).to.not.have.property("remoteSrcVideoObject");
+
+      store.mediaStreamCreated(new sharedActions.MediaStreamCreated({
+        hasVideo: false,
+        isLocal: false,
+        srcVideoObject: fakeVideoElement
+      }));
+
+      expect(store.getStoreState()).not.have.property("localSrcVideoObject");
+      expect(store.getStoreState().remoteSrcVideoObject).eql(fakeVideoElement);
+    });
+
+    it("should set the remote video enabled", function() {
+      store.setStoreState({
+        localVideoEnabled: false,
+        remoteVideoEnabled: false
+      });
+
+      store.mediaStreamCreated(new sharedActions.MediaStreamCreated({
+        hasVideo: true,
+        isLocal: false,
+        srcVideoObject: fakeVideoElement
+      }));
+
+      expect(store.getStoreState().localVideoEnabled).eql(false);
+      expect(store.getStoreState().remoteVideoEnabled).eql(true);
     });
   });
 
-  describe("#remoteVideoEnabled", function() {
-    it("should set store.remoteSrcVideoObject from the actionData", function () {
-      store.setStoreState({remoteSrcVideoObject: undefined});
-
-      store.remoteVideoEnabled(
-        new sharedActions.RemoteVideoEnabled({srcVideoObject: fakeVideoElement}));
-
-      expect(store.getStoreState("remoteSrcVideoObject")).eql(fakeVideoElement);
+  describe("#mediaStreamDestroyed", function() {
+    beforeEach(function() {
+      store.setStoreState({
+        localSrcVideoObject: fakeVideoElement,
+        remoteSrcVideoObject: fakeVideoElement
+      });
     });
 
-    it("should set store.remoteVideoEnabled to true", function () {
-      store.setStoreState({remoteVideoEnabled: false});
+    it("should clear the local video object", function() {
+      store.mediaStreamDestroyed(new sharedActions.MediaStreamDestroyed({
+        isLocal: true
+      }));
 
-      store.remoteVideoEnabled(
-        new sharedActions.RemoteVideoEnabled({srcVideoObject: fakeVideoElement}));
+      expect(store.getStoreState().localSrcVideoObject).eql(null);
+      expect(store.getStoreState().remoteSrcVideoObject).eql(fakeVideoElement);
+    });
 
-      expect(store.getStoreState("remoteVideoEnabled")).to.be.true;
+    it("should clear the remote video object", function() {
+      store.mediaStreamDestroyed(new sharedActions.MediaStreamDestroyed({
+        isLocal: false
+      }));
+
+      expect(store.getStoreState().localSrcVideoObject).eql(fakeVideoElement);
+      expect(store.getStoreState().remoteSrcVideoObject).eql(null);
     });
   });
 
-  describe("#remoteVideoDisabled", function() {
-    it("should set store.remoteVideoEnabled to false", function () {
-      store.setStoreState({remoteVideoEnabled: true});
+  describe("#remoteVideoStatus", function() {
+    it("should set remoteVideoEnabled to true", function() {
+      store.setStoreState({
+        remoteVideoEnabled: false
+      });
 
-      store.remoteVideoDisabled(new sharedActions.RemoteVideoDisabled({}));
+      store.remoteVideoStatus(new sharedActions.RemoteVideoStatus({
+        videoEnabled: true
+      }));
 
-      expect(store.getStoreState("remoteVideoEnabled")).to.be.false;
+      expect(store.getStoreState().remoteVideoEnabled).eql(true);
     });
 
-    it("should set store.remoteSrcVideoObject to undefined", function () {
-      store.setStoreState({remoteSrcVideoObject: fakeVideoElement});
+    it("should set remoteVideoEnabled to false", function() {
+      store.setStoreState({
+        remoteVideoEnabled: true
+      });
 
-      store.remoteVideoDisabled(new sharedActions.RemoteVideoDisabled({}));
+      store.remoteVideoStatus(new sharedActions.RemoteVideoStatus({
+        videoEnabled: false
+      }));
 
-      expect(store.getStoreState("remoteSrcVideoObject")).to.be.undefined;
+      expect(store.getStoreState().remoteVideoEnabled).eql(false);
     });
-
   });
 
   describe("#setMute", function() {
     beforeEach(function() {
       dispatcher.dispatch(
         // Setup store to prevent console warnings.
         new sharedActions.SetupWindowData({
           windowId: "123456",
--- a/browser/components/loop/test/shared/otSdkDriver_test.js
+++ b/browser/components/loop/test/shared/otSdkDriver_test.js
@@ -471,23 +471,43 @@ describe("loop.OTSdkDriver", function ()
       driver.disconnectSession();
 
       expect(subscribedEvents).eql([]);
     });
 
     it("should dispatch a DataChannelsAvailable action with available = false", function() {
       driver.disconnectSession();
 
-      sinon.assert.calledOnce(dispatcher.dispatch);
+      sinon.assert.called(dispatcher.dispatch);
       sinon.assert.calledWithExactly(dispatcher.dispatch,
         new sharedActions.DataChannelsAvailable({
           available: false
         }));
     });
 
+    it("should dispatch a MediaStreamDestroyed action with isLocal = false", function() {
+      driver.disconnectSession();
+
+      sinon.assert.called(dispatcher.dispatch);
+      sinon.assert.calledWithExactly(dispatcher.dispatch,
+        new sharedActions.MediaStreamDestroyed({
+          isLocal: false
+        }));
+    });
+
+    it("should dispatch a MediaStreamDestroyed action with isLocal = true", function() {
+      driver.disconnectSession();
+
+      sinon.assert.called(dispatcher.dispatch);
+      sinon.assert.calledWithExactly(dispatcher.dispatch,
+        new sharedActions.MediaStreamDestroyed({
+          isLocal: true
+        }));
+    });
+
     it("should destroy the publisher", function() {
       driver.publisher = publisher;
 
       driver.disconnectSession();
 
       sinon.assert.calledOnce(publisher.destroy);
     });
 
@@ -868,22 +888,37 @@ describe("loop.OTSdkDriver", function ()
         sinon.assert.calledWithExactly(dispatcher.dispatch,
           new sharedActions.VideoDimensionsChanged({
             isLocal: true,
             videoType: "camera",
             dimensions: {width: 1, height: 2}
           }));
       });
 
-      it("should dispatch a LocalVideoEnabled action", function() {
+      it("should dispatch a MediaStreamCreated action", function() {
         publisher.trigger("streamCreated", { stream: stream });
 
         sinon.assert.called(dispatcher.dispatch);
         sinon.assert.calledWithExactly(dispatcher.dispatch,
-          new sharedActions.LocalVideoEnabled({
+          new sharedActions.MediaStreamCreated({
+            hasVideo: true,
+            isLocal: true,
+            srcVideoObject: fakeMockVideo
+          }));
+      });
+
+      it("should dispatch a MediaStreamCreated action with hasVideo false for audio-only streams", function() {
+        stream.hasVideo = false;
+        publisher.trigger("streamCreated", { stream: stream });
+
+        sinon.assert.called(dispatcher.dispatch);
+        sinon.assert.calledWithExactly(dispatcher.dispatch,
+          new sharedActions.MediaStreamCreated({
+            hasVideo: false,
+            isLocal: true,
             srcVideoObject: fakeMockVideo
           }));
       });
 
       it("should dispatch a ConnectionStatus action", function() {
         driver._metrics.recvStreams = 1;
         driver._metrics.connections = 2;
 
@@ -935,44 +970,47 @@ describe("loop.OTSdkDriver", function ()
         session.trigger("streamCreated", { stream: fakeStream });
 
         sinon.assert.calledOnce(session.subscribe);
         sinon.assert.calledWithExactly(session.subscribe,
           fakeStream, sinon.match.instanceOf(HTMLDivElement), publisherConfig,
           sinon.match.func);
       });
 
-      it("should dispatch RemoteVideoEnabled if the stream has video" +
-        " after subscribe is complete", function() {
+      it("should dispatch MediaStreamCreated after subscribe is complete", function() {
         session.subscribe.yieldsOn(driver, null, fakeSubscriberObject,
           videoElement).returns(this.fakeSubscriberObject);
         driver.session = session;
         fakeStream.connection = fakeConnection;
         fakeStream.hasVideo = true;
 
         session.trigger("streamCreated", { stream: fakeStream });
 
         sinon.assert.called(dispatcher.dispatch);
         sinon.assert.calledWithExactly(dispatcher.dispatch,
-          new sharedActions.RemoteVideoEnabled({
+          new sharedActions.MediaStreamCreated({
+            hasVideo: true,
+            isLocal: false,
             srcVideoObject: videoElement
           }));
       });
 
-      it("should not dispatch RemoteVideoEnabled if the stream is audio-only", function() {
+      it("should dispatch MediaStreamCreated after subscribe with audio-only indication if hasVideo=false", function() {
         session.subscribe.yieldsOn(driver, null, fakeSubscriberObject,
           videoElement);
         fakeStream.connection = fakeConnection;
         fakeStream.hasVideo = false;
 
         session.trigger("streamCreated", { stream: fakeStream });
 
         sinon.assert.called(dispatcher.dispatch);
-        sinon.assert.neverCalledWith(dispatcher.dispatch,
-          new sharedActions.RemoteVideoEnabled({
+        sinon.assert.calledWithExactly(dispatcher.dispatch,
+          new sharedActions.MediaStreamCreated({
+            hasVideo: false,
+            isLocal: false,
             srcVideoObject: videoElement
           }));
       });
 
       it("should trigger a readyForDataChannel signal after subscribe is complete", function() {
         session.subscribe.yieldsOn(driver, null, fakeSubscriberObject,
           document.createElement("video"));
         driver._useDataChannels = true;
@@ -1086,36 +1124,46 @@ describe("loop.OTSdkDriver", function ()
     describe("streamDestroyed: publisher/local", function() {
       it("should dispatch a ConnectionStatus action", function() {
         driver._metrics.sendStreams = 1;
         driver._metrics.recvStreams = 1;
         driver._metrics.connections = 2;
 
         publisher.trigger("streamDestroyed");
 
-        sinon.assert.calledTwice(dispatcher.dispatch);
+        sinon.assert.called(dispatcher.dispatch);
         sinon.assert.calledWithExactly(dispatcher.dispatch,
           new sharedActions.ConnectionStatus({
             event: "Publisher.streamDestroyed",
             state: "receiving",
             connections: 2,
             recvStreams: 1,
             sendStreams: 0
           }));
       });
 
       it("should dispatch a DataChannelsAvailable action", function() {
         publisher.trigger("streamDestroyed");
 
-        sinon.assert.calledTwice(dispatcher.dispatch);
+        sinon.assert.called(dispatcher.dispatch);
         sinon.assert.calledWithExactly(dispatcher.dispatch,
           new sharedActions.DataChannelsAvailable({
             available: false
           }));
       });
+
+      it("should dispatch a MediaStreamDestroyed action", function() {
+        publisher.trigger("streamDestroyed");
+
+        sinon.assert.called(dispatcher.dispatch);
+        sinon.assert.calledWithExactly(dispatcher.dispatch,
+          new sharedActions.MediaStreamDestroyed({
+            isLocal: true
+          }));
+      });
     });
 
     describe("streamDestroyed: session/remote", function() {
       var stream;
 
       beforeEach(function() {
         stream = {
           videoType: "screen"
@@ -1159,29 +1207,50 @@ describe("loop.OTSdkDriver", function ()
           sinon.match.hasOwn("name", "receivingScreenShare"));
       });
 
       it("should dispatch a DataChannelsAvailable action for videoType = camera", function() {
         stream.videoType = "camera";
 
         session.trigger("streamDestroyed", { stream: stream });
 
-        sinon.assert.calledTwice(dispatcher.dispatch);
+        sinon.assert.calledThrice(dispatcher.dispatch);
         sinon.assert.calledWithExactly(dispatcher.dispatch,
           new sharedActions.DataChannelsAvailable({
             available: false
           }));
       });
 
       it("should not dispatch a DataChannelsAvailable action for videoType = screen", function() {
         session.trigger("streamDestroyed", { stream: stream });
 
         sinon.assert.neverCalledWithMatch(dispatcher.dispatch,
           sinon.match.hasOwn("name", "dataChannelsAvailable"));
       });
+
+      it("should dispatch a MediaStreamDestroyed action for videoType = camera", function() {
+        stream.videoType = "camera";
+
+        session.trigger("streamDestroyed", { stream: stream });
+
+        sinon.assert.calledThrice(dispatcher.dispatch);
+        sinon.assert.calledWithExactly(dispatcher.dispatch,
+          new sharedActions.MediaStreamDestroyed({
+            isLocal: false
+          }));
+      });
+
+      it("should not dispatch a MediaStreamDestroyed action for videoType = screen", function() {
+        session.trigger("streamDestroyed", { stream: stream });
+
+        sinon.assert.neverCalledWithMatch(dispatcher.dispatch,
+          new sharedActions.MediaStreamDestroyed({
+            isLocal: false
+          }));
+      });
     });
 
     describe("streamPropertyChanged", function() {
       var stream = {
         connection: { id: "fake" },
         videoType: "screen",
         videoDimensions: {
           width: 320,
@@ -1341,42 +1410,46 @@ describe("loop.OTSdkDriver", function ()
       it("should prevent the default event behavior", function() {
         publisher.trigger("accessDialogOpened", fakeEvent);
 
         sinon.assert.calledOnce(fakeEvent.preventDefault);
       });
     });
 
     describe("videoEnabled", function() {
-      it("should dispatch RemoteVideoEnabled", function() {
+      it("should dispatch a RemoteVideoStatus action", function() {
         session.subscribe.yieldsOn(driver, null, fakeSubscriberObject,
           videoElement).returns(this.fakeSubscriberObject);
         session.trigger("streamCreated", {stream: fakeSubscriberObject.stream});
         driver._mockSubscribeEl.appendChild(videoElement);
 
         fakeSubscriberObject.trigger("videoEnabled");
 
         sinon.assert.called(dispatcher.dispatch);
         sinon.assert.calledWith(dispatcher.dispatch,
-          new sharedActions.RemoteVideoEnabled({srcVideoObject: videoElement}));
+          new sharedActions.RemoteVideoStatus({
+            videoEnabled: true
+          }));
       });
     });
 
     describe("videoDisabled", function() {
-      it("should dispatch RemoteVideoDisabled", function() {
+      it("should dispatch a RemoteVideoStatus action", function() {
         session.subscribe.yieldsOn(driver, null, fakeSubscriberObject,
           videoElement).returns(this.fakeSubscriberObject);
         session.trigger("streamCreated", {stream: fakeSubscriberObject.stream});
 
 
         fakeSubscriberObject.trigger("videoDisabled");
 
         sinon.assert.called(dispatcher.dispatch);
         sinon.assert.calledWithExactly(dispatcher.dispatch,
-          new sharedActions.RemoteVideoDisabled({}));
+          new sharedActions.RemoteVideoStatus({
+            videoEnabled: false
+          }));
       });
     });
 
     describe("signal:readyForDataChannel", function() {
       beforeEach(function() {
         driver.subscriber = subscriber;
         driver._useDataChannels = true;
       });
--- a/browser/components/loop/ui/ui-showcase.js
+++ b/browser/components/loop/ui/ui-showcase.js
@@ -1266,17 +1266,17 @@
                 React.createElement(OngoingConversationView, {
                   audio: { enabled: true, visible: true}, 
                   conversationStore: conversationStores[3], 
                   dispatcher: dispatcher, 
                   localPosterUrl: "sample-img/video-screen-local.png", 
                   mediaConnected: true, 
                   remotePosterUrl: "sample-img/video-screen-remote.png", 
                   remoteVideoEnabled: true, 
-                  video: { enabled: true, visible: true}})
+                  video: { enabled: false, visible: true}})
               )
             ), 
 
             React.createElement(FramedExample, {dashed: true, 
                            height: 394, 
                            onContentsRendered: conversationStores[4].forcedUpdate, 
                            summary: "Desktop ongoing conversation window - remote face mute", 
                            width: 298}, 
--- a/browser/components/loop/ui/ui-showcase.jsx
+++ b/browser/components/loop/ui/ui-showcase.jsx
@@ -1266,17 +1266,17 @@
                 <OngoingConversationView
                   audio={{ enabled: true, visible: true }}
                   conversationStore={conversationStores[3]}
                   dispatcher={dispatcher}
                   localPosterUrl="sample-img/video-screen-local.png"
                   mediaConnected={true}
                   remotePosterUrl="sample-img/video-screen-remote.png"
                   remoteVideoEnabled={true}
-                  video={{ enabled: true, visible: true }} />
+                  video={{ enabled: false, visible: true }} />
               </div>
             </FramedExample>
 
             <FramedExample dashed={true}
                            height={394}
                            onContentsRendered={conversationStores[4].forcedUpdate}
                            summary="Desktop ongoing conversation window - remote face mute"
                            width={298} >
--- a/browser/components/sessionstore/test/browser_crashedTabs.js
+++ b/browser/components/sessionstore/test/browser_crashedTabs.js
@@ -382,8 +382,38 @@ add_task(function* test_hide_restore_all
   restoreOneButton = doc.getElementById("restoreTab");
 
   ok(!restoreAllButton.hasAttribute("hidden"), "Restore All button should not be hidden");
   ok(!(restoreOneButton.classList.contains("primary")), "Restore Tab button should not have the primary class");
 
   gBrowser.removeTab(newTab);
   gBrowser.removeTab(newTab2);
 });
+
+add_task(function* test_aboutcrashedtabzoom() {
+  let newTab = gBrowser.addTab();
+  gBrowser.selectedTab = newTab;
+  let browser = newTab.linkedBrowser;
+  ok(browser.isRemoteBrowser, "Should be a remote browser");
+  yield promiseBrowserLoaded(browser);
+
+  browser.loadURI(PAGE_1);
+  yield promiseBrowserLoaded(browser);
+
+  FullZoom.enlarge();
+  let zoomLevel = ZoomManager.getZoomForBrowser(browser);
+  ok(zoomLevel !== 1, "should have enlarged");
+
+  yield TabStateFlusher.flush(browser);
+
+  // Crash the tab
+  yield crashBrowser(browser);
+
+  ok(ZoomManager.getZoomForBrowser(browser) === 1, "zoom should have reset on crash");
+
+  clickButton(browser, "restoreTab");
+  yield promiseTabRestored(newTab);
+
+  ok(ZoomManager.getZoomForBrowser(browser) === zoomLevel, "zoom should have gone back to enlarged");
+  FullZoom.reset();
+
+  gBrowser.removeTab(newTab);
+});
--- a/browser/devtools/jar.mn
+++ b/browser/devtools/jar.mn
@@ -11,17 +11,16 @@ browser.jar:
     content/browser/devtools/readdir.js                                (projecteditor/lib/helpers/readdir.js)
     content/browser/devtools/projecteditor-loader.xul                        (projecteditor/chrome/content/projecteditor-loader.xul)
     content/browser/devtools/projecteditor-test.xul                          (projecteditor/chrome/content/projecteditor-test.xul)
     content/browser/devtools/projecteditor-loader.js                         (projecteditor/chrome/content/projecteditor-loader.js)
     content/browser/devtools/netmonitor.xul                            (netmonitor/netmonitor.xul)
     content/browser/devtools/netmonitor.css                            (netmonitor/netmonitor.css)
     content/browser/devtools/netmonitor-controller.js                  (netmonitor/netmonitor-controller.js)
     content/browser/devtools/netmonitor-view.js                        (netmonitor/netmonitor-view.js)
-    content/browser/devtools/NetworkPanel.xhtml                        (webconsole/NetworkPanel.xhtml)
     content/browser/devtools/webconsole.xul                            (webconsole/webconsole.xul)
 *   content/browser/devtools/scratchpad.xul                            (scratchpad/scratchpad.xul)
     content/browser/devtools/scratchpad.js                             (scratchpad/scratchpad.js)
     content/browser/devtools/splitview.css                             (shared/splitview.css)
     content/browser/devtools/theme-switching.js                        (shared/theme-switching.js)
     content/browser/devtools/frame-script-utils.js                     (shared/frame-script-utils.js)
     content/browser/devtools/styleeditor.xul                           (styleeditor/styleeditor.xul)
     content/browser/devtools/styleeditor.css                           (styleeditor/styleeditor.css)
--- a/browser/devtools/netmonitor/netmonitor-controller.js
+++ b/browser/devtools/netmonitor/netmonitor-controller.js
@@ -318,16 +318,47 @@ let NetMonitorController = {
       this._currentActivity = aType;
       return reconfigureTab({ cacheDisabled: true, performReload: false }).then(standBy);
     }
     this._currentActivity = ACTIVITY_TYPE.NONE;
     return promise.reject(new Error("Invalid activity type"));
   },
 
   /**
+   * Selects the specified request in the waterfall and opens the details view.
+   *
+   * @param string requestId
+   *        The actor ID of the request to inspect.
+   * @return object
+   *         A promise resolved once the task finishes.
+   */
+  inspectRequest: function(requestId) {
+    // Look for the request in the existing ones or wait for it to appear, if
+    // the network monitor is still loading.
+    let deferred = promise.defer();
+    let request = null;
+    let inspector = function() {
+      let predicate = i => i.value === requestId;
+      request = NetMonitorView.RequestsMenu.getItemForPredicate(predicate);
+      if (request) {
+        window.off(EVENTS.REQUEST_ADDED, inspector);
+        NetMonitorView.RequestsMenu.filterOn("all");
+        NetMonitorView.RequestsMenu.selectedItem = request;
+        deferred.resolve();
+      }
+    }
+
+    inspector();
+    if (!request) {
+      window.on(EVENTS.REQUEST_ADDED, inspector);
+    }
+    return deferred.promise;
+  },
+
+  /**
    * Getter that tells if the server supports sending custom network requests.
    * @type boolean
    */
   get supportsCustomRequest() {
     return this.webConsoleClient &&
            (this.webConsoleClient.traits.customNetworkRequest ||
             !this._target.isApp);
   },
--- a/browser/devtools/performance/modules/markers.js
+++ b/browser/devtools/performance/modules/markers.js
@@ -73,16 +73,21 @@ const TIMELINE_BLUEPRINT = {
     colorName: "graphs-green",
     label: L10N.getStr("marker.label.paint"),
   },
   "Composite": {
     group: 0,
     colorName: "graphs-green",
     label: L10N.getStr("marker.label.composite"),
   },
+  "CompositeForwardTransaction": {
+    group: 0,
+    colorName: "graphs-bluegrey",
+    label: L10N.getStr("marker.label.compositeForwardTransaction"),
+  },
 
   /* Group 1 - JS */
   "DOMEvent": {
     group: 1,
     colorName: "graphs-yellow",
     label: L10N.getStr("marker.label.domevent"),
     fields: Formatters.DOMEventFields,
   },
deleted file mode 100644
--- a/browser/devtools/webconsole/NetworkPanel.xhtml
+++ /dev/null
@@ -1,124 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
-  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd" [
-<!ENTITY % webConsoleDTD SYSTEM "chrome://browser/locale/devtools/webConsole.dtd" >
-%webConsoleDTD;
-]>
-
-<!-- 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/. -->
-
-
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
-<head>
-  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
-  <link rel="stylesheet" href="chrome://browser/skin/devtools/webconsole_networkpanel.css" type="text/css"/>
-</head>
-<body role="application">
-<table id="header">
-  <tr>
-    <th class="property-name"
-        scope="row">&networkPanel.requestURLColon;</th>
-    <td class="property-value"
-        id="headUrl"></td>
-  </tr>
-  <tr>
-    <th class="property-name"
-        scope="row">&networkPanel.requestMethodColon;</th>
-    <td class="property-value"
-        id="headMethod"></td>
-  </tr>
-  <tr>
-    <th class="property-name"
-        scope="row">&networkPanel.statusCodeColon;</th>
-    <td class="property-value"
-        id="headStatus"></td>
-  </tr>
-</table>
-
-<div class="group">
-  <h1>
-    &networkPanel.requestHeaders;
-    <span id="requestHeadersInfo" class="info"></span>
-  </h1>
-  <table class="property-table" id="requestHeadersContent"></table>
-
-  <div id="requestCookie" style="display:none">
-    <h1>&networkPanel.requestCookie;</h1>
-    <table class="property-table" id="requestCookieContent"></table>
-  </div>
-
-  <div id="requestBody" style="display:none">
-    <h1>&networkPanel.requestBody;</h1>
-    <table class="property-table" id="requestBodyContent"></table>
-  </div>
-  <div id="requestFormData" style="display:none">
-    <h1>&networkPanel.requestFormData;</h1>
-    <table class="property-table" id="requestFormDataContent"></table>
-  </div>
-  <p id="requestBodyFetchLink" style="display:none"></p>
-</div>
-
-<div class="group" id="responseContainer" style="display:none">
-  <h1>
-    &networkPanel.responseHeaders;
-    <span id="responseHeadersInfo" class="info">&Delta;</span>
-  </h1>
-  <table class="property-table" id="responseHeadersContent"></table>
-
-  <div id="responseCookie" style="display:none">
-    <h1>&networkPanel.responseCookie;</h1>
-    <table class="property-table" id="responseCookieContent"></table>
-  </div>
-
-  <div id="responseBody" style="display:none">
-    <h1>
-      &networkPanel.responseBody;
-      <span class="info" id="responseBodyInfo">&Delta;</span>
-    </h1>
-    <table class="property-table" id="responseBodyContent"></table>
-  </div>
-  <div id="responseBodyCached" style="display:none">
-    <h1>
-      &networkPanel.responseBodyCached;
-      <span class="info" id="responseBodyCachedInfo">&Delta;</span>
-    </h1>
-    <table class="property-table" id="responseBodyCachedContent"></table>
-  </div>
-  <div id="responseNoBody" style="display:none">
-    <h1>
-      &networkPanel.responseNoBody;
-      <span id="responseNoBodyInfo" class="info">&Delta;</span>
-    </h1>
-  </div>
-  <div id="responseBodyUnknownType" style="display:none">
-    <h1>
-      &networkPanel.responseBodyUnknownType;
-      <span id="responseBodyUnknownTypeInfo" class="info">&Delta;</span>
-    </h1>
-    <table class="property-table" id="responseBodyUnknownTypeContent"></table>
-  </div>
-  <div id="responseImage" style="display:none">
-    <h1>
-      &networkPanel.responseImage;
-      <span id="responseImageInfo" class="info"></span>
-    </h1>
-    <div id="responseImageNodeDiv">
-      <img id="responseImageNode" />
-    </div>
-  </div>
-  <div id="responseImageCached" style="display:none">
-    <h1>
-      &networkPanel.responseImageCached;
-      <span id="responseImageCachedInfo" class="info"></span>
-    </h1>
-    <div id="responseImageNodeDiv">
-      <img id="responseImageCachedNode" />
-    </div>
-  </div>
-  <p id="responseBodyFetchLink" style="display:none"></p>
-</div>
-</body>
-</html>
--- a/browser/devtools/webconsole/moz.build
+++ b/browser/devtools/webconsole/moz.build
@@ -5,12 +5,11 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
 
 EXTRA_JS_MODULES.devtools.webconsole += [
     'console-commands.js',
     'console-output.js',
     'hudservice.js',
-    'network-panel.js',
     'panel.js',
     'webconsole.js',
 ]
deleted file mode 100644
--- a/browser/devtools/webconsole/network-panel.js
+++ /dev/null
@@ -1,835 +0,0 @@
-/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
-/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-const {Cc, Ci, Cu} = require("chrome");
-
-loader.lazyGetter(this, "NetworkHelper", () => require("devtools/toolkit/webconsole/network-helper"));
-loader.lazyImporter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm");
-loader.lazyServiceGetter(this, "mimeService", "@mozilla.org/mime;1", "nsIMIMEService");
-
-let WebConsoleUtils = require("devtools/toolkit/webconsole/utils").Utils;
-
-const STRINGS_URI = "chrome://browser/locale/devtools/webconsole.properties";
-let l10n = new WebConsoleUtils.l10n(STRINGS_URI);
-
-
-/**
- * Creates a new NetworkPanel.
- *
- * @constructor
- * @param nsIDOMNode aParent
- *        Parent node to append the created panel to.
- * @param object aHttpActivity
- *        HttpActivity to display in the panel.
- * @param object aWebConsoleFrame
- *        The parent WebConsoleFrame object that owns this network panel
- *        instance.
- */
-function NetworkPanel(aParent, aHttpActivity, aWebConsoleFrame)
-{
-  let doc = aParent.ownerDocument;
-  this.httpActivity = aHttpActivity;
-  this.webconsole = aWebConsoleFrame;
-  this._responseBodyFetch = this._responseBodyFetch.bind(this);
-  this._requestBodyFetch = this._requestBodyFetch.bind(this);
-
-  // Create the underlaying panel
-  this.panel = createElement(doc, "panel", {
-    label: l10n.getStr("NetworkPanel.label"),
-    titlebar: "normal",
-    noautofocus: "true",
-    noautohide: "true",
-    close: "true"
-  });
-
-  // Create the iframe that displays the NetworkPanel XHTML.
-  this.iframe = createAndAppendElement(this.panel, "iframe", {
-    src: "chrome://browser/content/devtools/NetworkPanel.xhtml",
-    type: "content",
-    flex: "1"
-  });
-
-  let self = this;
-
-  // Destroy the panel when it's closed.
-  this.panel.addEventListener("popuphidden", function onPopupHide() {
-    self.panel.removeEventListener("popuphidden", onPopupHide, false);
-    self.panel.parentNode.removeChild(self.panel);
-    self.panel = null;
-    self.iframe = null;
-    self.httpActivity = null;
-    self.webconsole = null;
-
-    if (self.linkNode) {
-      self.linkNode._panelOpen = false;
-      self.linkNode = null;
-    }
-  }, false);
-
-  // Set the document object and update the content once the panel is loaded.
-  this.iframe.addEventListener("load", function onLoad() {
-    if (!self.iframe) {
-      return;
-    }
-
-    self.iframe.removeEventListener("load", onLoad, true);
-    self.update();
-  }, true);
-
-  this.panel.addEventListener("popupshown", function onPopupShown() {
-    self.panel.removeEventListener("popupshown", onPopupShown, true);
-    self.update();
-  }, true);
-
-  // Create the footer.
-  let footer = createElement(doc, "hbox", { align: "end" });
-  createAndAppendElement(footer, "spacer", { flex: 1 });
-
-  createAndAppendElement(footer, "resizer", { dir: "bottomend" });
-  this.panel.appendChild(footer);
-
-  aParent.appendChild(this.panel);
-}
-exports.NetworkPanel = NetworkPanel;
-
-NetworkPanel.prototype =
-{
-  /**
-   * The current state of the output.
-   */
-  _state: 0,
-
-  /**
-   * State variables.
-   */
-  _INIT: 0,
-  _DISPLAYED_REQUEST_HEADER: 1,
-  _DISPLAYED_REQUEST_BODY: 2,
-  _DISPLAYED_RESPONSE_HEADER: 3,
-  _TRANSITION_CLOSED: 4,
-
-  _fromDataRegExp: /Content-Type\:\s*application\/x-www-form-urlencoded/,
-
-  _contentType: null,
-
-  /**
-   * Function callback invoked whenever the panel content is updated. This is
-   * used only by tests.
-   *
-   * @private
-   * @type function
-   */
-  _onUpdate: null,
-
-  get document() {
-    return this.iframe && this.iframe.contentWindow ?
-           this.iframe.contentWindow.document : null;
-  },
-
-  /**
-   * Small helper function that is nearly equal to l10n.getFormatStr
-   * except that it prefixes aName with "NetworkPanel.".
-   *
-   * @param string aName
-   *        The name of an i10n string to format. This string is prefixed with
-   *        "NetworkPanel." before calling the HUDService.getFormatStr function.
-   * @param array aArray
-   *        Values used as placeholder for the i10n string.
-   * @returns string
-   *          The i10n formated string.
-   */
-  _format: function NP_format(aName, aArray)
-  {
-    return l10n.getFormatStr("NetworkPanel." + aName, aArray);
-  },
-
-  /**
-   * Returns the content type of the response body. This is based on the
-   * response.content.mimeType property. If this value is not available, then
-   * the content type is guessed by the file extension of the request URL.
-   *
-   * @return string
-   *         Content type or empty string if no content type could be figured
-   *         out.
-   */
-  get contentType()
-  {
-    if (this._contentType) {
-      return this._contentType;
-    }
-
-    let request = this.httpActivity.request;
-    let response = this.httpActivity.response;
-
-    let contentType = "";
-    let types = response.content ?
-                (response.content.mimeType || "").split(/,|;/) : [];
-    for (let i = 0; i < types.length; i++) {
-      if (types[i] in NetworkHelper.mimeCategoryMap) {
-        contentType = types[i];
-        break;
-      }
-    }
-
-    if (contentType) {
-      this._contentType = contentType;
-      return contentType;
-    }
-
-    // Try to get the content type from the request file extension.
-    let uri = NetUtil.newURI(request.url);
-    if ((uri instanceof Ci.nsIURL) && uri.fileExtension) {
-      try {
-         contentType = mimeService.getTypeFromExtension(uri.fileExtension);
-      }
-      catch(ex) {
-        // Added to prevent failures on OS X 64. No Flash?
-        Cu.reportError(ex);
-      }
-    }
-
-    this._contentType = contentType;
-    return contentType;
-  },
-
-  /**
-   *
-   * @returns boolean
-   *          True if the response is an image, false otherwise.
-   */
-  get _responseIsImage()
-  {
-    return this.contentType &&
-           NetworkHelper.mimeCategoryMap[this.contentType] == "image";
-  },
-
-  /**
-   *
-   * @returns boolean
-   *          True if the response body contains text, false otherwise.
-   */
-  get _isResponseBodyTextData()
-  {
-    return this.contentType ?
-           NetworkHelper.isTextMimeType(this.contentType) : false;
-  },
-
-  /**
-   * Tells if the server response is cached.
-   *
-   * @returns boolean
-   *          Returns true if the server responded that the request is already
-   *          in the browser's cache, false otherwise.
-   */
-  get _isResponseCached()
-  {
-    return this.httpActivity.response.status == 304;
-  },
-
-  /**
-   * Tells if the request body includes form data.
-   *
-   * @returns boolean
-   *          Returns true if the posted body contains form data.
-   */
-  get _isRequestBodyFormData()
-  {
-    let requestBody = this.httpActivity.request.postData.text;
-    if (typeof requestBody == "object" && requestBody.type == "longString") {
-      requestBody = requestBody.initial;
-    }
-    return this._fromDataRegExp.test(requestBody);
-  },
-
-  /**
-   * Appends the node with id=aId by the text aValue.
-   *
-   * @private
-   * @param string aId
-   * @param string aValue
-   * @return nsIDOMElement
-   *         The DOM element with id=aId.
-   */
-  _appendTextNode: function NP__appendTextNode(aId, aValue)
-  {
-    let textNode = this.document.createTextNode(aValue);
-    let elem = this.document.getElementById(aId);
-    elem.appendChild(textNode);
-    return elem;
-  },
-
-  /**
-   * Generates some HTML to display the key-value pair of the aList data. The
-   * generated HTML is added to node with id=aParentId.
-   *
-   * @param string aParentId
-   *        Id of the parent node to append the list to.
-   * @oaram array aList
-   *        Array that holds the objects you want to display. Each object must
-   *        have two properties: name and value.
-   * @param boolean aIgnoreCookie
-   *        If true, the key-value named "Cookie" is not added to the list.
-   * @returns void
-   */
-  _appendList: function NP_appendList(aParentId, aList, aIgnoreCookie)
-  {
-    let parent = this.document.getElementById(aParentId);
-    let doc = this.document;
-
-    aList.sort(function(a, b) {
-      return a.name.toLowerCase() < b.name.toLowerCase();
-    });
-
-    aList.forEach((aItem) => {
-      let name = aItem.name;
-      if (aIgnoreCookie && (name == "Cookie" || name == "Set-Cookie")) {
-        return;
-      }
-
-      let value = aItem.value;
-      let longString = null;
-      if (typeof value == "object" && value.type == "longString") {
-        value = value.initial;
-        longString = true;
-      }
-
-      /**
-       * The following code creates the HTML:
-       * <tr>
-       * <th scope="row" class="property-name">${line}:</th>
-       * <td class="property-value">${aList[line]}</td>
-       * </tr>
-       * and adds it to parent.
-       */
-      let row = doc.createElement("tr");
-      let textNode = doc.createTextNode(name + ":");
-      let th = doc.createElement("th");
-      th.setAttribute("scope", "row");
-      th.setAttribute("class", "property-name");
-      th.appendChild(textNode);
-      row.appendChild(th);
-
-      textNode = doc.createTextNode(value);
-      let td = doc.createElement("td");
-      td.setAttribute("class", "property-value");
-      td.appendChild(textNode);
-
-      if (longString) {
-        let a = doc.createElement("a");
-        a.href = "#";
-        a.className = "longStringEllipsis";
-        a.addEventListener("mousedown", this._longStringClick.bind(this, aItem));
-        a.textContent = l10n.getStr("longStringEllipsis");
-        td.appendChild(a);
-      }
-
-      row.appendChild(td);
-
-      parent.appendChild(row);
-    });
-  },
-
-  /**
-   * The click event handler for the ellipsis which allows the user to retrieve
-   * the full header value.
-   *
-   * @private
-   * @param object aHeader
-   *        The header object with the |name| and |value| properties.
-   * @param nsIDOMEvent aEvent
-   *        The DOM click event object.
-   */
-  _longStringClick: function NP__longStringClick(aHeader, aEvent)
-  {
-    aEvent.preventDefault();
-
-    let longString = this.webconsole.webConsoleClient.longString(aHeader.value);
-
-    longString.substring(longString.initial.length, longString.length,
-      function NP__onLongStringSubstring(aResponse)
-      {
-        if (aResponse.error) {
-          Cu.reportError("NP__onLongStringSubstring error: " + aResponse.error);
-          return;
-        }
-
-        aHeader.value = aHeader.value.initial + aResponse.substring;
-
-        let textNode = aEvent.target.previousSibling;
-        textNode.textContent += aResponse.substring;
-        textNode.parentNode.removeChild(aEvent.target);
-      });
-  },
-
-  /**
-   * Displays the node with id=aId.
-   *
-   * @private
-   * @param string aId
-   * @return nsIDOMElement
-   *         The element with id=aId.
-   */
-  _displayNode: function NP__displayNode(aId)
-  {
-    let elem = this.document.getElementById(aId);
-    elem.style.display = "block";
-  },
-
-  /**
-   * Sets the request URL, request method, the timing information when the
-   * request started and the request header content on the NetworkPanel.
-   * If the request header contains cookie data, a list of sent cookies is
-   * generated and a special sent cookie section is displayed + the cookie list
-   * added to it.
-   *
-   * @returns void
-   */
-  _displayRequestHeader: function NP__displayRequestHeader()
-  {
-    let request = this.httpActivity.request;
-    let requestTime = new Date(this.httpActivity.startedDateTime);
-
-    this._appendTextNode("headUrl", request.url);
-    this._appendTextNode("headMethod", request.method);
-    this._appendTextNode("requestHeadersInfo",
-                         l10n.timestampString(requestTime));
-
-    this._appendList("requestHeadersContent", request.headers, true);
-
-    if (request.cookies.length > 0) {
-      this._displayNode("requestCookie");
-      this._appendList("requestCookieContent", request.cookies);
-    }
-  },
-
-  /**
-   * Displays the request body section of the NetworkPanel and set the request
-   * body content on the NetworkPanel.
-   *
-   * @returns void
-   */
-  _displayRequestBody: function NP__displayRequestBody()
-  {
-    let postData = this.httpActivity.request.postData;
-    this._displayNode("requestBody");
-    this._appendTextNode("requestBodyContent", postData.text);
-  },
-
-  /*
-   * Displays the `sent form data` section. Parses the request header for the
-   * submitted form data displays it inside of the `sent form data` section.
-   *
-   * @returns void
-   */
-  _displayRequestForm: function NP__processRequestForm()
-  {
-    let postData = this.httpActivity.request.postData.text;
-    let requestBodyLines = postData.split("\n");
-    let formData = requestBodyLines[requestBodyLines.length - 1].
-                      replace(/\+/g, " ").split("&");
-
-    function unescapeText(aText)
-    {
-      try {
-        return decodeURIComponent(aText);
-      }
-      catch (ex) {
-        return decodeURIComponent(unescape(aText));
-      }
-    }
-
-    let formDataArray = [];
-    for (let i = 0; i < formData.length; i++) {
-      let data = formData[i];
-      let idx = data.indexOf("=");
-      let key = data.substring(0, idx);
-      let value = data.substring(idx + 1);
-      formDataArray.push({
-        name: unescapeText(key),
-        value: unescapeText(value)
-      });
-    }
-
-    this._appendList("requestFormDataContent", formDataArray);
-    this._displayNode("requestFormData");
-  },
-
-  /**
-   * Displays the response section of the NetworkPanel, sets the response status,
-   * the duration between the start of the request and the receiving of the
-   * response header as well as the response header content on the the NetworkPanel.
-   *
-   * @returns void
-   */
-  _displayResponseHeader: function NP__displayResponseHeader()
-  {
-    let timing = this.httpActivity.timings;
-    let response = this.httpActivity.response;
-
-    this._appendTextNode("headStatus",
-                         [response.httpVersion, response.status,
-                          response.statusText].join(" "));
-
-    // Calculate how much time it took from the request start, until the
-    // response started to be received.
-    let deltaDuration = 0;
-    ["dns", "connect", "send", "wait"].forEach(function (aValue) {
-      let ms = timing[aValue];
-      if (ms > -1) {
-        deltaDuration += ms;
-      }
-    });
-
-    this._appendTextNode("responseHeadersInfo",
-      this._format("durationMS", [deltaDuration]));
-
-    this._displayNode("responseContainer");
-    this._appendList("responseHeadersContent", response.headers, true);
-
-    if (response.cookies.length > 0) {
-      this._displayNode("responseCookie");
-      this._appendList("responseCookieContent", response.cookies);
-    }
-  },
-
-  /**
-   * Displays the respones image section, sets the source of the image displayed
-   * in the image response section to the request URL and the duration between
-   * the receiving of the response header and the end of the request. Once the
-   * image is loaded, the size of the requested image is set.
-   *
-   * @returns void
-   */
-  _displayResponseImage: function NP__displayResponseImage()
-  {
-    let self = this;
-    let timing = this.httpActivity.timings;
-    let request = this.httpActivity.request;
-    let response = this.httpActivity.response;
-    let cached = "";
-
-    if (this._isResponseCached) {
-      cached = "Cached";
-    }
-
-    let imageNode = this.document.getElementById("responseImage" +
-                                                 cached + "Node");
-
-    let text = response.content.text;
-    if (typeof text == "object" && text.type == "longString") {
-      this._showResponseBodyFetchLink();
-    }
-    else {
-      imageNode.setAttribute("src",
-        "data:" + this.contentType + ";base64," + text);
-    }
-
-    // This function is called to set the imageInfo.
-    function setImageInfo() {
-      self._appendTextNode("responseImage" + cached + "Info",
-        self._format("imageSizeDeltaDurationMS",
-          [ imageNode.width, imageNode.height, timing.receive ]
-        )
-      );
-    }
-
-    // Check if the image is already loaded.
-    if (imageNode.width != 0) {
-      setImageInfo();
-    }
-    else {
-      // Image is not loaded yet therefore add a load event.
-      imageNode.addEventListener("load", function imageNodeLoad() {
-        imageNode.removeEventListener("load", imageNodeLoad, false);
-        setImageInfo();
-      }, false);
-    }
-
-    this._displayNode("responseImage" + cached);
-  },
-
-  /**
-   * Displays the response body section, sets the the duration between
-   * the receiving of the response header and the end of the request as well as
-   * the content of the response body on the NetworkPanel.
-   *
-   * @returns void
-   */
-  _displayResponseBody: function NP__displayResponseBody()
-  {
-    let timing = this.httpActivity.timings;
-    let response = this.httpActivity.response;
-    let cached =  this._isResponseCached ? "Cached" : "";
-
-    this._appendTextNode("responseBody" + cached + "Info",
-      this._format("durationMS", [timing.receive]));
-
-    this._displayNode("responseBody" + cached);
-
-    let text = response.content.text;
-    if (typeof text == "object") {
-      text = text.initial;
-      this._showResponseBodyFetchLink();
-    }
-
-    this._appendTextNode("responseBody" + cached + "Content", text);
-  },
-
-  /**
-   * Show the "fetch response body" link.
-   * @private
-   */
-  _showResponseBodyFetchLink: function NP__showResponseBodyFetchLink()
-  {
-    let content = this.httpActivity.response.content;
-
-    let elem = this._appendTextNode("responseBodyFetchLink",
-      this._format("fetchRemainingResponseContentLink",
-                   [content.text.length - content.text.initial.length]));
-
-    elem.style.display = "block";
-    elem.addEventListener("mousedown", this._responseBodyFetch);
-  },
-
-  /**
-   * Click event handler for the link that allows users to fetch the remaining
-   * response body.
-   *
-   * @private
-   * @param nsIDOMEvent aEvent
-   */
-  _responseBodyFetch: function NP__responseBodyFetch(aEvent)
-  {
-    aEvent.target.style.display = "none";
-    aEvent.target.removeEventListener("mousedown", this._responseBodyFetch);
-
-    let content = this.httpActivity.response.content;
-    let longString = this.webconsole.webConsoleClient.longString(content.text);
-    longString.substring(longString.initial.length, longString.length,
-      (aResponse) =>
-      {
-        if (aResponse.error) {
-          Cu.reportError("NP__onLongStringSubstring error: " + aResponse.error);
-          return;
-        }
-
-        content.text = content.text.initial + aResponse.substring;
-        let cached =  this._isResponseCached ? "Cached" : "";
-
-        if (this._responseIsImage) {
-          let imageNode = this.document.getElementById("responseImage" +
-                                                       cached + "Node");
-          imageNode.src =
-            "data:" + this.contentType + ";base64," + content.text;
-        }
-        else {
-          this._appendTextNode("responseBody" + cached + "Content",
-                               aResponse.substring);
-        }
-      });
-  },
-
-  /**
-   * Displays the `Unknown Content-Type hint` and sets the duration between the
-   * receiving of the response header on the NetworkPanel.
-   *
-   * @returns void
-   */
-  _displayResponseBodyUnknownType: function NP__displayResponseBodyUnknownType()
-  {
-    let timing = this.httpActivity.timings;
-
-    this._displayNode("responseBodyUnknownType");
-    this._appendTextNode("responseBodyUnknownTypeInfo",
-      this._format("durationMS", [timing.receive]));
-
-    this._appendTextNode("responseBodyUnknownTypeContent",
-      this._format("responseBodyUnableToDisplay.content", [this.contentType]));
-  },
-
-  /**
-   * Displays the `no response body` section and sets the the duration between
-   * the receiving of the response header and the end of the request.
-   *
-   * @returns void
-   */
-  _displayNoResponseBody: function NP_displayNoResponseBody()
-  {
-    let timing = this.httpActivity.timings;
-
-    this._displayNode("responseNoBody");
-    this._appendTextNode("responseNoBodyInfo",
-      this._format("durationMS", [timing.receive]));
-  },
-
-  /**
-   * Updates the content of the NetworkPanel's iframe.
-   *
-   * @returns void
-   */
-  update: function NP_update()
-  {
-    if (!this.document || this.document.readyState != "complete") {
-      return;
-    }
-
-    let updates = this.httpActivity.updates;
-    let timing = this.httpActivity.timings;
-    let request = this.httpActivity.request;
-    let response = this.httpActivity.response;
-
-    switch (this._state) {
-      case this._INIT:
-        this._displayRequestHeader();
-        this._state = this._DISPLAYED_REQUEST_HEADER;
-        // FALL THROUGH
-
-      case this._DISPLAYED_REQUEST_HEADER:
-        // Process the request body if there is one.
-        if (!this.httpActivity.discardRequestBody && request.postData.text) {
-          this._updateRequestBody();
-          this._state = this._DISPLAYED_REQUEST_BODY;
-        }
-        // FALL THROUGH
-
-      case this._DISPLAYED_REQUEST_BODY:
-        if (!response.headers.length || !Object.keys(timing).length) {
-          break;
-        }
-        this._displayResponseHeader();
-        this._state = this._DISPLAYED_RESPONSE_HEADER;
-        // FALL THROUGH
-
-      case this._DISPLAYED_RESPONSE_HEADER:
-        if (updates.indexOf("responseContent") == -1 ||
-            updates.indexOf("eventTimings") == -1) {
-          break;
-        }
-
-        this._state = this._TRANSITION_CLOSED;
-        if (this.httpActivity.discardResponseBody) {
-          break;
-        }
-
-        if (!response.content || !response.content.text) {
-          this._displayNoResponseBody();
-        }
-        else if (this._responseIsImage) {
-          this._displayResponseImage();
-        }
-        else if (!this._isResponseBodyTextData) {
-          this._displayResponseBodyUnknownType();
-        }
-        else if (response.content.text) {
-          this._displayResponseBody();
-        }
-        break;
-    }
-
-    if (this._onUpdate) {
-      this._onUpdate();
-    }
-  },
-
-  /**
-   * Update the panel to hold the current information we have about the request
-   * body.
-   * @private
-   */
-  _updateRequestBody: function NP__updateRequestBody()
-  {
-    let postData = this.httpActivity.request.postData;
-    if (typeof postData.text == "object" && postData.text.type == "longString") {
-      let elem = this._appendTextNode("requestBodyFetchLink",
-        this._format("fetchRemainingRequestContentLink",
-                     [postData.text.length - postData.text.initial.length]));
-
-      elem.style.display = "block";
-      elem.addEventListener("mousedown", this._requestBodyFetch);
-      return;
-    }
-
-    // Check if we send some form data. If so, display the form data special.
-    if (this._isRequestBodyFormData) {
-      this._displayRequestForm();
-    }
-    else {
-      this._displayRequestBody();
-    }
-  },
-
-  /**
-   * Click event handler for the link that allows users to fetch the remaining
-   * request body.
-   *
-   * @private
-   * @param nsIDOMEvent aEvent
-   */
-  _requestBodyFetch: function NP__requestBodyFetch(aEvent)
-  {
-    aEvent.target.style.display = "none";
-    aEvent.target.removeEventListener("mousedown", this._responseBodyFetch);
-
-    let postData = this.httpActivity.request.postData;
-    let longString = this.webconsole.webConsoleClient.longString(postData.text);
-    longString.substring(longString.initial.length, longString.length,
-       (aResponse) =>
-      {
-        if (aResponse.error) {
-          Cu.reportError("NP__onLongStringSubstring error: " + aResponse.error);
-          return;
-        }
-
-        postData.text = postData.text.initial + aResponse.substring;
-        this._updateRequestBody();
-      });
-  },
-};
-
-/**
- * Creates a DOMNode and sets all the attributes of aAttributes on the created
- * element.
- *
- * @param nsIDOMDocument aDocument
- *        Document to create the new DOMNode.
- * @param string aTag
- *        Name of the tag for the DOMNode.
- * @param object aAttributes
- *        Attributes set on the created DOMNode.
- *
- * @returns nsIDOMNode
- */
-function createElement(aDocument, aTag, aAttributes)
-{
-  let node = aDocument.createElement(aTag);
-  if (aAttributes) {
-    for (let attr in aAttributes) {
-      node.setAttribute(attr, aAttributes[attr]);
-    }
-  }
-  return node;
-}
-
-/**
- * Creates a new DOMNode and appends it to aParent.
- *
- * @param nsIDOMNode aParent
- *        A parent node to append the created element.
- * @param string aTag
- *        Name of the tag for the DOMNode.
- * @param object aAttributes
- *        Attributes set on the created DOMNode.
- *
- * @returns nsIDOMNode
- */
-function createAndAppendElement(aParent, aTag, aAttributes)
-{
-  let node = createElement(aParent.ownerDocument, aTag, aAttributes);
-  aParent.appendChild(node);
-  return node;
-}
--- a/browser/devtools/webconsole/test/browser.ini
+++ b/browser/devtools/webconsole/test/browser.ini
@@ -184,18 +184,16 @@ skip-if = buildapp == 'mulet'
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
 [browser_console_variables_view_while_debugging_and_inspecting.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
 [browser_eval_in_debugger_stackframe.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
 [browser_eval_in_debugger_stackframe2.js]
 [browser_jsterm_inspect.js]
 [browser_longstring_hang.js]
-[browser_netpanel_longstring_expand.js]
-skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
 [browser_output_breaks_after_console_dir_uninspectable.js]
 [browser_output_longstring_expand.js]
 [browser_repeated_messages_accuracy.js]
 skip-if = buildapp == 'mulet'
 [browser_result_format_as_string.js]
 [browser_warn_user_about_replaced_api.js]
 [browser_webconsole_abbreviate_source_url.js]
 [browser_webconsole_allow_mixedcontent_securityerrors.js]
@@ -222,17 +220,16 @@ skip-if = e10s # Bug 1042253 - webconsol
 [browser_webconsole_bug_588342_document_focus.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
 [browser_webconsole_bug_588730_text_node_insertion.js]
 [browser_webconsole_bug_588967_input_expansion.js]
 [browser_webconsole_bug_589162_css_filter.js]
 [browser_webconsole_bug_592442_closing_brackets.js]
 [browser_webconsole_bug_593003_iframe_wrong_hud.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
-[browser_webconsole_bug_594477_clickable_output.js]
 [browser_webconsole_bug_594497_history_arrow_keys.js]
 [browser_webconsole_bug_595223_file_uri.js]
 [browser_webconsole_bug_595350_multiple_windows_and_tabs.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
 [browser_webconsole_bug_595934_message_categories.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
 [browser_webconsole_bug_597103_deactivateHUDForContext_unfocused_window.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
@@ -240,27 +237,24 @@ skip-if = e10s # Bug 1042253 - webconsol
 [browser_webconsole_bug_597136_network_requests_from_chrome.js]
 [browser_webconsole_bug_597460_filter_scroll.js]
 [browser_webconsole_bug_597756_reopen_closed_tab.js]
 [browser_webconsole_bug_599725_response_headers.js]
 [browser_webconsole_bug_600183_charset.js]
 [browser_webconsole_bug_601177_log_levels.js]
 [browser_webconsole_bug_601352_scroll.js]
 [browser_webconsole_bug_601667_filter_buttons.js]
-[browser_webconsole_bug_602572_log_bodies_checkbox.js]
-skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
 [browser_webconsole_bug_603750_websocket.js]
 [browser_webconsole_bug_611795.js]
 [browser_webconsole_bug_613013_console_api_iframe.js]
 [browser_webconsole_bug_613280_jsterm_copy.js]
 [browser_webconsole_bug_613642_maintain_scroll.js]
 [browser_webconsole_bug_613642_prune_scroll.js]
 [browser_webconsole_bug_614793_jsterm_scroll.js]
 [browser_webconsole_bug_618078_network_exceptions.js]
-[browser_webconsole_bug_618311_close_panels.js]
 [browser_webconsole_bug_621644_jsterm_dollar.js]
 [browser_webconsole_bug_622303_persistent_filters.js]
 [browser_webconsole_bug_623749_ctrl_a_select_all_winnt.js]
 skip-if = os != "win"
 [browser_webconsole_bug_630733_response_redirect_headers.js]
 [browser_webconsole_bug_632275_getters_document_width.js]
 [browser_webconsole_bug_632347_iterators_generators.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
@@ -329,17 +323,16 @@ skip-if = buildapp == 'mulet' || e10s # 
 [browser_webconsole_inspect-parsed-documents.js]
 [browser_webconsole_js_input_expansion.js]
 [browser_webconsole_jsterm.js]
 skip-if = e10s # Bug 1042253 - webconsole e10s tests (Linux debug timeout)
 [browser_webconsole_live_filtering_of_message_types.js]
 [browser_webconsole_live_filtering_on_search_strings.js]
 [browser_webconsole_message_node_id.js]
 [browser_webconsole_netlogging.js]
-[browser_webconsole_network_panel.js]
 [browser_webconsole_notifications.js]
 [browser_webconsole_open-links-without-callback.js]
 [browser_webconsole_promise.js]
 [browser_webconsole_output_copy_newlines.js]
 [browser_webconsole_output_order.js]
 [browser_webconsole_property_provider.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
 [browser_webconsole_scratchpad_panel_link.js]
deleted file mode 100644
--- a/browser/devtools/webconsole/test/browser_netpanel_longstring_expand.js
+++ /dev/null
@@ -1,312 +0,0 @@
-/* vim:set ts=2 sw=2 sts=2 et: */
-/* 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/. */
-
-// Tests that the network panel works with LongStringActors.
-
-"use strict";
-
-const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/" +
-                 "test/test-console.html";
-const TEST_IMG = "http://example.com/browser/browser/devtools/webconsole/" +
-                 "test/test-image.png";
-
-const TEST_IMG_BASE64 =
-  "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAVRJ" +
-  "REFUOI2lk7FLw0AUxr+YpC1CBqcMWfsvCCLdXFzqEJCgDl1EQRGxg9AhSBEJONhFhG52UCuF" +
-  "Djq5dxD8FwoO0qGDOBQkl7vLOeWa2EQDffDBvTu+373Hu1OEEJgntGgxGD6J+7fLXKbt5VNU" +
-  "yhsKAChRBQcPFVFeWskFGH694mZroCQqCLlAwPxcgJBP254CmAD5B7C7dgHLMLF3uzoL4DQE" +
-  "od+Z5sP1FizDxGgyBqfhLID9AahX29J89bwPFgMsSEAQglAf9WobhPpScbPXr4FQHyzIADTs" +
-  "DizDRMPuIOC+zEeTMZo9BwH3EfAMACccbtfGaDKGZZg423yUZrdrg3EqxQlPr0BTdTR7joRE" +
-  "N2uqnlBmCwW1hIJagtev4f3zA16/JvfiigMSYyzqJXlw/XKUyOORMUaBor6YavgdjKa8xGOn" +
-  "idadmwtwsnMu18q83/kHSou+bFNDDr4AAAAASUVORK5CYII=";
-
-let testDriver;
-
-function test() {
-  loadTab(TEST_URI).then(() => {
-    openConsole().then(testNetworkPanel);
-  });
-}
-
-function testNetworkPanel() {
-  testDriver = testGen();
-  testDriver.next();
-}
-
-function checkIsVisible(aPanel, aList) {
-  for (let id in aList) {
-    let node = aPanel.document.getElementById(id);
-    let isVisible = aList[id];
-    is(node.style.display, (isVisible ? "block" : "none"),
-       id + " isVisible=" + isVisible);
-  }
-}
-
-function checkNodeContent(aPanel, aId, aContent) {
-  let node = aPanel.document.getElementById(aId);
-  if (node == null) {
-    ok(false, "Tried to access node " + aId + " that doesn't exist!");
-  } else if (node.textContent.indexOf(aContent) != -1) {
-    ok(true, "checking content of " + aId);
-  } else {
-    ok(false, "Got false value for " + aId + ": " + node.textContent +
-       " doesn't have " + aContent);
-  }
-}
-
-function checkNodeKeyValue(aPanel, aId, aKey, aValue) {
-  let node = aPanel.document.getElementById(aId);
-
-  let headers = node.querySelectorAll("th");
-  for (let i = 0; i < headers.length; i++) {
-    if (headers[i].textContent == (aKey + ":")) {
-      is(headers[i].nextElementSibling.textContent, aValue,
-         "checking content of " + aId + " for key " + aKey);
-      return;
-    }
-  }
-
-  ok(false, "content check failed for " + aId + ", key " + aKey);
-}
-
-function* testGen() {
-  let hud = HUDService.getHudByWindow(content);
-  let filterBox = hud.ui.filterBox;
-
-  let headerValue = (new Array(456)).join("fooz bar");
-  let headerValueGrip = {
-    type: "longString",
-    initial: headerValue.substr(0, 123),
-    length: headerValue.length,
-    actor: "faktor",
-    _fullString: headerValue,
-  };
-
-  let imageContentGrip = {
-    type: "longString",
-    initial: TEST_IMG_BASE64.substr(0, 143),
-    length: TEST_IMG_BASE64.length,
-    actor: "faktor2",
-    _fullString: TEST_IMG_BASE64,
-  };
-
-  let postDataValue = (new Array(123)).join("post me");
-  let postDataGrip = {
-    type: "longString",
-    initial: postDataValue.substr(0, 172),
-    length: postDataValue.length,
-    actor: "faktor3",
-    _fullString: postDataValue,
-  };
-
-  let httpActivity = {
-    updates: ["responseContent", "eventTimings"],
-    discardRequestBody: false,
-    discardResponseBody: false,
-    startedDateTime: (new Date()).toISOString(),
-    request: {
-      url: TEST_IMG,
-      method: "GET",
-      cookies: [],
-      headers: [
-        { name: "foo", value: "bar" },
-        { name: "loongstring", value: headerValueGrip },
-      ],
-      postData: { text: postDataGrip },
-    },
-    response: {
-      httpVersion: "HTTP/3.14",
-      status: 2012,
-      statusText: "ddahl likes tacos :)",
-      headers: [
-        { name: "Content-Type", value: "image/png" },
-      ],
-      content: { mimeType: "image/png", text: imageContentGrip },
-      cookies: [],
-    },
-    timings: { wait: 15, receive: 23 },
-  };
-
-  let networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
-
-  is(filterBox._netPanel, networkPanel,
-     "Network panel stored on the anchor object");
-
-  networkPanel._onUpdate = function() {
-    networkPanel._onUpdate = null;
-    executeSoon(function() {
-      testDriver.next();
-    });
-  };
-
-  yield undefined;
-
-  info("test 1: check if a header value is expandable");
-
-  checkIsVisible(networkPanel, {
-    requestCookie: false,
-    requestFormData: false,
-    requestBody: false,
-    requestBodyFetchLink: true,
-    responseContainer: true,
-    responseBody: false,
-    responseNoBody: false,
-    responseImage: true,
-    responseImageCached: false,
-    responseBodyFetchLink: true,
-  });
-
-  checkNodeKeyValue(networkPanel, "requestHeadersContent", "foo", "bar");
-  checkNodeKeyValue(networkPanel, "requestHeadersContent", "loongstring",
-                    headerValueGrip.initial + "[\u2026]");
-
-  let webConsoleClient = networkPanel.webconsole.webConsoleClient;
-  let longStringFn = webConsoleClient.longString;
-
-  let expectedGrip = headerValueGrip;
-
-  function longStringClientProvider(aLongString) {
-    is(aLongString, expectedGrip,
-       "longString grip is correct");
-
-    return {
-      initial: expectedGrip.initial,
-      length: expectedGrip.length,
-      substring: function(aStart, aEnd, aCallback) {
-        is(aStart, expectedGrip.initial.length,
-           "substring start is correct");
-        is(aEnd, expectedGrip.length,
-           "substring end is correct");
-
-        executeSoon(function() {
-          aCallback({
-            substring: expectedGrip._fullString.substring(aStart, aEnd),
-          });
-
-          executeSoon(function() {
-            testDriver.next();
-          });
-        });
-      },
-    };
-  }
-
-  webConsoleClient.longString = longStringClientProvider;
-
-  let clickable = networkPanel.document
-                  .querySelector("#requestHeadersContent .longStringEllipsis");
-  ok(clickable, "long string ellipsis is shown");
-
-  EventUtils.sendMouseEvent({ type: "mousedown"}, clickable,
-                             networkPanel.document.defaultView);
-
-  yield undefined;
-
-  clickable = networkPanel.document
-              .querySelector("#requestHeadersContent .longStringEllipsis");
-  ok(!clickable, "long string ellipsis is not shown");
-
-  checkNodeKeyValue(networkPanel, "requestHeadersContent", "loongstring",
-                    expectedGrip._fullString);
-
-  info("test 2: check that response body image fetching works");
-  expectedGrip = imageContentGrip;
-
-  let imgNode = networkPanel.document.getElementById("responseImageNode");
-  ok(!imgNode.getAttribute("src"), "no image is displayed");
-
-  clickable = networkPanel.document.querySelector("#responseBodyFetchLink");
-  EventUtils.sendMouseEvent({ type: "mousedown"}, clickable,
-                             networkPanel.document.defaultView);
-
-  yield undefined;
-
-  imgNode = networkPanel.document.getElementById("responseImageNode");
-  is(imgNode.getAttribute("src"), "data:image/png;base64," + TEST_IMG_BASE64,
-     "displayed image is correct");
-  is(clickable.style.display, "none", "#responseBodyFetchLink is not visible");
-
-  info("test 3: expand the request body");
-
-  expectedGrip = postDataGrip;
-
-  clickable = networkPanel.document.querySelector("#requestBodyFetchLink");
-  EventUtils.sendMouseEvent({ type: "mousedown"}, clickable,
-                             networkPanel.document.defaultView);
-  yield undefined;
-
-  is(clickable.style.display, "none", "#requestBodyFetchLink is not visible");
-
-  checkIsVisible(networkPanel, {
-    requestBody: true,
-    requestBodyFetchLink: false,
-  });
-
-  checkNodeContent(networkPanel, "requestBodyContent",
-                   expectedGrip._fullString);
-
-  webConsoleClient.longString = longStringFn;
-
-  networkPanel.panel.hidePopup();
-
-  info("test 4: reponse body long text");
-
-  httpActivity.response.content.mimeType = "text/plain";
-  httpActivity.response.headers[0].value = "text/plain";
-
-  expectedGrip = imageContentGrip;
-
-  // Reset response.content.text to avoid caching of the full string.
-  httpActivity.response.content.text = expectedGrip;
-
-  networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
-  is(filterBox._netPanel, networkPanel,
-     "Network panel stored on httpActivity object");
-
-  networkPanel._onUpdate = function() {
-    networkPanel._onUpdate = null;
-    executeSoon(function() {
-      testDriver.next();
-    });
-  };
-
-  yield undefined;
-
-  checkIsVisible(networkPanel, {
-    requestCookie: false,
-    requestFormData: false,
-    requestBody: true,
-    requestBodyFetchLink: false,
-    responseContainer: true,
-    responseBody: true,
-    responseNoBody: false,
-    responseImage: false,
-    responseImageCached: false,
-    responseBodyFetchLink: true,
-  });
-
-  checkNodeContent(networkPanel, "responseBodyContent", expectedGrip.initial);
-
-  webConsoleClient.longString = longStringClientProvider;
-
-  clickable = networkPanel.document.querySelector("#responseBodyFetchLink");
-  EventUtils.sendMouseEvent({ type: "mousedown"}, clickable,
-                             networkPanel.document.defaultView);
-
-  yield undefined;
-
-  webConsoleClient.longString = longStringFn;
-  is(clickable.style.display, "none", "#responseBodyFetchLink is not visible");
-  checkNodeContent(networkPanel, "responseBodyContent",
-                   expectedGrip._fullString);
-
-  networkPanel.panel.hidePopup();
-
-  // All done!
-  testDriver = null;
-  executeSoon(finishTest);
-
-  yield undefined;
-}
deleted file mode 100644
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_594477_clickable_output.js
+++ /dev/null
@@ -1,132 +0,0 @@
-/* vim:set ts=2 sw=2 sts=2 et: */
-/* ***** BEGIN LICENSE BLOCK *****
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/
- *
- * Contributor(s):
- *  Mihai Șucan <mihai.sucan@gmail.com>
- *
- * ***** END LICENSE BLOCK ***** */
-
-"use strict";
-
-const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/" +
-                 "test/test-console.html";
-let HUD;
-let outputItem;
-let outputNode;
-
-let test = asyncTest(function* () {
-  yield loadTab(TEST_URI);
-
-  HUD = yield openConsole();
-  outputNode = HUD.outputNode;
-
-  // reload the tab
-  BrowserReload();
-  yield loadBrowser(gBrowser.selectedBrowser);
-
-  let event = yield clickEvents();
-  yield testClickAgain(event);
-  yield networkPanelHidden();
-
-  HUD = outputItem = outputNode = null;
-});
-
-function clickEvents() {
-  let deferred = promise.defer();
-
-  waitForMessages({
-    webconsole: HUD,
-    messages: [{
-      text: "test-console.html",
-      category: CATEGORY_NETWORK,
-      severity: SEVERITY_LOG,
-    }],
-  }).then(([result]) => {
-    let msg = [...result.matched][0];
-    outputItem = msg.querySelector(".message-body .url");
-    ok(outputItem, "found a network message");
-    document.addEventListener("popupshown", function onPanelShown(event) {
-      document.removeEventListener("popupshown", onPanelShown, false);
-      deferred.resolve(event);
-    }, false);
-
-    // Send the mousedown and click events such that the network panel opens.
-    EventUtils.sendMouseEvent({type: "mousedown"}, outputItem);
-    EventUtils.sendMouseEvent({type: "click"}, outputItem);
-  });
-
-  return deferred.promise;
-}
-
-function testClickAgain(event) {
-  info("testClickAgain");
-
-  let deferred = promise.defer();
-
-  document.addEventListener("popupshown", networkPanelShowFailure, false);
-
-  // The network panel should not open for the second time.
-  EventUtils.sendMouseEvent({type: "mousedown"}, outputItem);
-  EventUtils.sendMouseEvent({type: "click"}, outputItem);
-
-  executeSoon(function() {
-    document.addEventListener("popuphidden", function onHidden() {
-      document.removeEventListener("popuphidden", onHidden, false);
-      deferred.resolve();
-    }, false);
-    event.target.hidePopup();
-  });
-
-  return deferred.promise;
-}
-
-function networkPanelShowFailure() {
-  ok(false, "the network panel should not show");
-}
-
-function networkPanelHidden() {
-  let deferred = promise.defer();
-
-  info("networkPanelHidden");
-
-  // The network panel should not show because this is a mouse event that starts
-  // in a position and ends in another.
-  EventUtils.sendMouseEvent({type: "mousedown", clientX: 3, clientY: 4},
-    outputItem);
-  EventUtils.sendMouseEvent({type: "click", clientX: 5, clientY: 6},
-    outputItem);
-
-  // The network panel should not show because this is a middle-click.
-  EventUtils.sendMouseEvent({type: "mousedown", button: 1},
-    outputItem);
-  EventUtils.sendMouseEvent({type: "click", button: 1},
-    outputItem);
-
-  // The network panel should not show because this is a right-click.
-  EventUtils.sendMouseEvent({type: "mousedown", button: 2},
-    outputItem);
-  EventUtils.sendMouseEvent({type: "click", button: 2},
-    outputItem);
-
-  executeSoon(function() {
-    document.removeEventListener("popupshown", networkPanelShowFailure, false);
-
-    // Done with the network output. Now test the jsterm output and the property
-    // panel.
-    HUD.jsterm.execute("document").then((msg) => {
-      info("jsterm execute 'document' callback");
-
-      HUD.jsterm.once("variablesview-open", deferred.resolve);
-      outputItem = msg.querySelector(".message-body a");
-      ok(outputItem, "jsterm output message found");
-
-      // Send the mousedown and click events such that the property panel opens.
-      EventUtils.sendMouseEvent({type: "mousedown"}, outputItem);
-      EventUtils.sendMouseEvent({type: "click"}, outputItem);
-    });
-  });
-
-  return deferred.promise;
-}
deleted file mode 100644
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_602572_log_bodies_checkbox.js
+++ /dev/null
@@ -1,186 +0,0 @@
-/* vim:set ts=2 sw=2 sts=2 et: */
-/* ***** BEGIN LICENSE BLOCK *****
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/
- *
- * Contributor(s):
- *   Mihai Șucan <mihai.sucan@gmail.com>
- *
- * ***** END LICENSE BLOCK ***** */
-
-"use strict";
-
-let menuitems = [];
-let menupopups = [];
-let huds = [];
-let tabs = [];
-let runCount = 0;
-
-const TEST_URI1 = "data:text/html;charset=utf-8,Web Console test for " +
-                  "bug 602572: log bodies checkbox. tab 1";
-const TEST_URI2 = "data:text/html;charset=utf-8,Web Console test for " +
-                  "bug 602572: log bodies checkbox. tab 2";
-
-function test() {
-  if (runCount == 0) {
-    requestLongerTimeout(2);
-  }
-
-  // open tab 2
-  function openTab() {
-    loadTab(TEST_URI2).then((tab) => {
-      tabs.push(tab.tab);
-      openConsole().then((hud) => {
-        hud.iframeWindow.requestAnimationFrame(startTest);
-      });
-    });
-  }
-
-  // open tab 1
-  loadTab(TEST_URI1).then((tab) => {
-    tabs.push(tab.tab);
-    openConsole().then((hud) => {
-      hud.iframeWindow.requestAnimationFrame(() => {
-        info("iframe1 root height " + hud.ui.rootElement.clientHeight);
-
-        openTab();
-      });
-    });
-  });
-}
-
-function startTest() {
-  // Find the relevant elements in the Web Console of tab 2.
-  let win2 = tabs[runCount * 2 + 1].linkedBrowser.contentWindow;
-  huds[1] = HUDService.getHudByWindow(win2);
-  info("startTest: iframe2 root height " + huds[1].ui.rootElement.clientHeight);
-
-  if (runCount == 0) {
-    menuitems[1] = huds[1].ui.rootElement.querySelector("#saveBodies");
-  } else {
-    menuitems[1] = huds[1].ui.rootElement
-                             .querySelector("#saveBodiesContextMenu");
-  }
-  menupopups[1] = menuitems[1].parentNode;
-
-  // Open the context menu from tab 2.
-  menupopups[1].addEventListener("popupshown", onpopupshown2, false);
-  executeSoon(function() {
-    menupopups[1].openPopup();
-  });
-}
-
-function onpopupshown2(evt) {
-  menupopups[1].removeEventListener(evt.type, onpopupshown2, false);
-
-  // By default bodies are not logged.
-  isnot(menuitems[1].getAttribute("checked"), "true",
-        "menuitems[1] is not checked");
-
-  ok(!huds[1].ui._saveRequestAndResponseBodies, "bodies are not logged");
-
-  // Enable body logging.
-  huds[1].ui.setSaveRequestAndResponseBodies(true).then(() => {
-    menupopups[1].hidePopup();
-  });
-
-  menupopups[1].addEventListener("popuphidden", function _onhidden(evtPopup) {
-    menupopups[1].removeEventListener(evtPopup.type, _onhidden, false);
-
-    info("menupopups[1] hidden");
-
-    // Reopen the context menu.
-    huds[1].ui.once("save-bodies-ui-toggled", () => testpopup2b(evtPopup));
-    menupopups[1].openPopup();
-  }, false);
-}
-
-function testpopup2b() {
-  is(menuitems[1].getAttribute("checked"), "true", "menuitems[1] is checked");
-
-  menupopups[1].addEventListener("popuphidden", function _onhidden(evtPopup) {
-    menupopups[1].removeEventListener(evtPopup.type, _onhidden, false);
-
-    info("menupopups[1] hidden");
-
-    // Switch to tab 1 and open the Web Console context menu from there.
-    gBrowser.selectedTab = tabs[runCount * 2];
-    waitForFocus(function() {
-      // Find the relevant elements in the Web Console of tab 1.
-      let win1 = tabs[runCount * 2].linkedBrowser.contentWindow;
-      huds[0] = HUDService.getHudByWindow(win1);
-
-      info("iframe1 root height " + huds[0].ui.rootElement.clientHeight);
-
-      menuitems[0] = huds[0].ui.rootElement.querySelector("#saveBodies");
-      menupopups[0] = huds[0].ui.rootElement.querySelector("menupopup");
-
-      menupopups[0].addEventListener("popupshown", onpopupshown1, false);
-      executeSoon(() => menupopups[0].openPopup());
-    }, tabs[runCount * 2].linkedBrowser.contentWindow);
-  }, false);
-
-  executeSoon(function() {
-    menupopups[1].hidePopup();
-  });
-}
-
-function onpopupshown1(evt) {
-  menupopups[0].removeEventListener(evt.type, onpopupshown1, false);
-
-  // The menuitem checkbox must not be in sync with the other tabs.
-  isnot(menuitems[0].getAttribute("checked"), "true",
-        "menuitems[0] is not checked");
-
-  // Enable body logging for tab 1 as well.
-  huds[0].ui.setSaveRequestAndResponseBodies(true).then(() => {
-    menupopups[0].hidePopup();
-  });
-
-  // Close the menu, and switch back to tab 2.
-  menupopups[0].addEventListener("popuphidden", function _onhidden(evtPopup) {
-    menupopups[0].removeEventListener(evtPopup.type, _onhidden, false);
-
-    info("menupopups[0] hidden");
-
-    gBrowser.selectedTab = tabs[runCount * 2 + 1];
-    waitForFocus(function() {
-      // Reopen the context menu from tab 2.
-      huds[1].ui.once("save-bodies-ui-toggled", () => testpopup2c(evtPopup));
-      menupopups[1].openPopup();
-    }, tabs[runCount * 2 + 1].linkedBrowser.contentWindow);
-  }, false);
-}
-
-function testpopup2c() {
-  is(menuitems[1].getAttribute("checked"), "true", "menuitems[1] is checked");
-
-  menupopups[1].addEventListener("popuphidden", function _onhidden(evtPopup) {
-    menupopups[1].removeEventListener(evtPopup.type, _onhidden, false);
-
-    info("menupopups[1] hidden");
-
-    // Done if on second run
-    closeConsole(gBrowser.selectedTab).then(function() {
-      if (runCount == 0) {
-        runCount++;
-        info("start second run");
-        executeSoon(test);
-      } else {
-        gBrowser.removeCurrentTab();
-        gBrowser.selectedTab = tabs[2];
-        gBrowser.removeCurrentTab();
-        gBrowser.selectedTab = tabs[1];
-        gBrowser.removeCurrentTab();
-        gBrowser.selectedTab = tabs[0];
-        gBrowser.removeCurrentTab();
-        huds = menuitems = menupopups = tabs = null;
-        executeSoon(finishTest);
-      }
-    });
-  }, false);
-
-  executeSoon(function() {
-    menupopups[1].hidePopup();
-  });
-}
deleted file mode 100644
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_618311_close_panels.js
+++ /dev/null
@@ -1,93 +0,0 @@
-/* vim:set ts=2 sw=2 sts=2 et: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/" +
-                 "test/test-console.html";
-
-let test = asyncTest(function* () {
-  yield loadTab(TEST_URI);
-
-  let hud = yield openConsole();
-
-  BrowserReload();
-
-  let results = yield waitForMessages({
-    webconsole: hud,
-    messages: [{
-      text: "test-console.html",
-      category: CATEGORY_NETWORK,
-      severity: SEVERITY_LOG,
-    }],
-  });
-
-  yield performTest(hud, results);
-});
-
-function performTest(HUD, results) {
-  let deferred = promise.defer();
-
-  let networkMessage = [...results[0].matched][0];
-  ok(networkMessage, "network message element");
-
-  let networkLink = networkMessage.querySelector(".url");
-  ok(networkLink, "found network message link");
-
-  let popupset = document.getElementById("mainPopupSet");
-  ok(popupset, "found #mainPopupSet");
-
-  let popupsShown = 0;
-  let hiddenPopups = 0;
-
-  let onpopupshown = function() {
-    document.removeEventListener("popupshown", onpopupshown, false);
-    popupsShown++;
-
-    executeSoon(function() {
-      let popups = popupset.querySelectorAll("panel[hudId=" + HUD.hudId + "]");
-      is(popups.length, 1, "found one popup");
-
-      document.addEventListener("popuphidden", onpopuphidden, false);
-
-      registerCleanupFunction(function() {
-        is(hiddenPopups, 1, "correct number of popups hidden");
-        if (hiddenPopups != 1) {
-          document.removeEventListener("popuphidden", onpopuphidden, false);
-        }
-      });
-
-      executeSoon(closeConsole);
-    });
-  };
-
-  let onpopuphidden = function() {
-    document.removeEventListener("popuphidden", onpopuphidden, false);
-    hiddenPopups++;
-
-    executeSoon(function() {
-      let popups = popupset.querySelectorAll("panel[hudId=" + HUD.hudId + "]");
-      is(popups.length, 0, "no popups found");
-
-      executeSoon(deferred.resolve);
-    });
-  };
-
-  document.addEventListener("popupshown", onpopupshown, false);
-
-  registerCleanupFunction(function() {
-    is(popupsShown, 1, "correct number of popups shown");
-    if (popupsShown != 1) {
-      document.removeEventListener("popupshown", onpopupshown, false);
-    }
-  });
-
-  EventUtils.sendMouseEvent({ type: "mousedown" }, networkLink,
-                              HUD.iframeWindow);
-  EventUtils.sendMouseEvent({ type: "mouseup" }, networkLink, HUD.iframeWindow);
-  EventUtils.sendMouseEvent({ type: "click" }, networkLink, HUD.iframeWindow);
-
-  return deferred.promise;
-}
--- a/browser/devtools/webconsole/test/browser_webconsole_netlogging.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_netlogging.js
@@ -186,25 +186,27 @@ function testFormSubmission() {
     let form = content.document.querySelector("form");
     form.submit();
   }`);
 }
 
 function testNetworkPanel() {
   // Open the NetworkPanel. The functionality of the NetworkPanel is tested
   // within separate test files.
-  let networkPanel = hud.ui.openNetworkPanel(hud.ui.filterBox, lastRequest);
-
-  networkPanel.panel.addEventListener("popupshown", function onPopupShown() {
-    networkPanel.panel.removeEventListener("popupshown", onPopupShown, true);
-
-    is(hud.ui.filterBox._netPanel, networkPanel,
-       "Network panel stored on anchor node");
-    ok(true, "NetworkPanel was opened");
+  hud.ui.openNetworkPanel(lastRequest.actor).then(() => {
+    let toolbox = gDevTools.getToolbox(hud.target);
+    is(toolbox.currentToolId, "netmonitor", "Network panel was opened");
+    let panel = toolbox.getCurrentPanel();
+    let selected = panel.panelWin.NetMonitorView.RequestsMenu.selectedItem;
+    is(selected.attachment.method, lastRequest.request.method,
+       "The correct request is selected");
+    is(selected.attachment.url, lastRequest.request.url,
+       "The correct request is definitely selected");
 
     // All tests are done. Shutdown.
-    networkPanel.panel.hidePopup();
     lastRequest = null;
     HUDService.lastFinishedRequest.callback = null;
     browser = requestCallback = hud = null;
     executeSoon(finishTest);
-  }, true);
+  }).then(null, error => {
+    ok(false, "Got an error: " + error.message + "\n" + error.stack);
+  });
 }
deleted file mode 100644
--- a/browser/devtools/webconsole/test/browser_webconsole_network_panel.js
+++ /dev/null
@@ -1,551 +0,0 @@
-/* vim:set ts=2 sw=2 sts=2 et: */
-/* 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/. */
-
-// Tests that the network panel works.
-
-"use strict";
-
-const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/" +
-                 "test/test-console.html";
-const TEST_IMG = "http://example.com/browser/browser/devtools/webconsole/" +
-                 "test/test-image.png";
-const TEST_ENCODING_ISO_8859_1 = "http://example.com/browser/browser/" +
-                                 "devtools/webconsole/test/" +
-                                 "test-encoding-ISO-8859-1.html";
-
-const TEST_IMG_BASE64 =
-  "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAVRJ" +
-  "REFUOI2lk7FLw0AUxr+YpC1CBqcMWfsvCCLdXFzqEJCgDl1EQRGxg9AhSBEJONhFhG52UCuF" +
-  "Djq5dxD8FwoO0qGDOBQkl7vLOeWa2EQDffDBvTu+373Hu1OEEJgntGgxGD6J+7fLXKbt5VNU" +
-  "yhsKAChRBQcPFVFeWskFGH694mZroCQqCLlAwPxcgJBP254CmAD5B7C7dgHLMLF3uzoL4DQE" +
-  "od+Z5sP1FizDxGgyBqfhLID9AahX29J89bwPFgMsSEAQglAf9WobhPpScbPXr4FQHyzIADTs" +
-  "DizDRMPuIOC+zEeTMZo9BwH3EfAMACccbtfGaDKGZZg423yUZrdrg3EqxQlPr0BTdTR7joRE" +
-  "N2uqnlBmCwW1hIJagtev4f3zA16/JvfiigMSYyzqJXlw/XKUyOORMUaBor6YavgdjKa8xGOn" +
-  "idadmwtwsnMu18q83/kHSou+bFNDDr4AAAAASUVORK5CYII=";
-
-let testDriver, hud;
-
-function test() {
-  loadTab(TEST_URI).then(() => {
-    openConsole().then(testNetworkPanel);
-  });
-}
-
-function testNetworkPanel(aHud) {
-  hud = aHud;
-  testDriver = testGen();
-  testDriver.next();
-}
-
-function checkIsVisible(aPanel, aList) {
-  for (let id in aList) {
-    let node = aPanel.document.getElementById(id);
-    let isVisible = aList[id];
-    is(node.style.display, (isVisible ? "block" : "none"),
-       id + " isVisible=" + isVisible);
-  }
-}
-
-function checkNodeContent(aPanel, aId, aContent) {
-  let node = aPanel.document.getElementById(aId);
-  if (node == null) {
-    ok(false, "Tried to access node " + aId + " that doesn't exist!");
-  } else if (node.textContent.indexOf(aContent) != -1) {
-    ok(true, "checking content of " + aId);
-  } else {
-    ok(false, "Got false value for " + aId + ": " + node.textContent +
-              " doesn't have " + aContent);
-  }
-}
-
-function checkNodeKeyValue(aPanel, aId, aKey, aValue) {
-  let node = aPanel.document.getElementById(aId);
-
-  let headers = node.querySelectorAll("th");
-  for (let i = 0; i < headers.length; i++) {
-    if (headers[i].textContent == (aKey + ":")) {
-      is(headers[i].nextElementSibling.textContent, aValue,
-         "checking content of " + aId + " for key " + aKey);
-      return;
-    }
-  }
-
-  ok(false, "content check failed for " + aId + ", key " + aKey);
-}
-
-function* testGen() {
-  let filterBox = hud.ui.filterBox;
-
-  let httpActivity = {
-    updates: [],
-    discardRequestBody: true,
-    discardResponseBody: true,
-    startedDateTime: (new Date()).toISOString(),
-    request: {
-      url: "http://www.testpage.com",
-      method: "GET",
-      cookies: [],
-      headers: [
-        { name: "foo", value: "bar" },
-      ],
-    },
-    response: {
-      headers: [],
-      content: {},
-      cookies: [],
-    },
-    timings: {},
-  };
-
-  let networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
-
-  is(filterBox._netPanel, networkPanel,
-     "Network panel stored on the anchor object");
-
-  networkPanel._onUpdate = function() {
-    networkPanel._onUpdate = null;
-    executeSoon(function() {
-      testDriver.next();
-    });
-  };
-
-  yield undefined;
-
-  info("test 1");
-
-  checkIsVisible(networkPanel, {
-    requestCookie: false,
-    requestFormData: false,
-    requestBody: false,
-    responseContainer: false,
-    responseBody: false,
-    responseNoBody: false,
-    responseImage: false,
-    responseImageCached: false
-  });
-
-  checkNodeContent(networkPanel, "header", "http://www.testpage.com");
-  checkNodeContent(networkPanel, "header", "GET");
-  checkNodeKeyValue(networkPanel, "requestHeadersContent", "foo", "bar");
-
-  // Test request body.
-  info("test 2: request body");
-  httpActivity.discardRequestBody = false;
-  httpActivity.request.postData = { text: "hello world" };
-  networkPanel.update();
-
-  checkIsVisible(networkPanel, {
-    requestBody: true,
-    requestFormData: false,
-    requestCookie: false,
-    responseContainer: false,
-    responseBody: false,
-    responseNoBody: false,
-    responseImage: false,
-    responseImageCached: false
-  });
-  checkNodeContent(networkPanel, "requestBodyContent", "hello world");
-
-  // Test response header.
-  info("test 3: response header");
-  httpActivity.timings.wait = 10;
-  httpActivity.response.httpVersion = "HTTP/3.14";
-  httpActivity.response.status = 999;
-  httpActivity.response.statusText = "earthquake win";
-  httpActivity.response.content.mimeType = "text/html";
-  httpActivity.response.headers.push(
-    { name: "Content-Type", value: "text/html" },
-    { name: "leaveHouses", value: "true" }
-  );
-
-  networkPanel.update();
-
-  checkIsVisible(networkPanel, {
-    requestBody: true,
-    requestFormData: false,
-    requestCookie: false,
-    responseContainer: true,
-    responseBody: false,
-    responseNoBody: false,
-    responseImage: false,
-    responseImageCached: false
-  });
-
-  checkNodeContent(networkPanel, "header", "HTTP/3.14 999 earthquake win");
-  checkNodeKeyValue(networkPanel, "responseHeadersContent", "leaveHouses",
-                    "true");
-  checkNodeContent(networkPanel, "responseHeadersInfo", "10ms");
-
-  info("test 4");
-
-  httpActivity.discardResponseBody = false;
-  httpActivity.timings.receive = 2;
-  networkPanel.update();
-
-  checkIsVisible(networkPanel, {
-    requestBody: true,
-    requestCookie: false,
-    requestFormData: false,
-    responseContainer: true,
-    responseBody: false,
-    responseNoBody: false,
-    responseImage: false,
-    responseImageCached: false
-  });
-
-  info("test 5");
-
-  httpActivity.updates.push("responseContent", "eventTimings");
-  networkPanel.update();
-
-  checkNodeContent(networkPanel, "responseNoBodyInfo", "2ms");
-  checkIsVisible(networkPanel, {
-    requestBody: true,
-    requestCookie: false,
-    responseContainer: true,
-    responseBody: false,
-    responseNoBody: true,
-    responseImage: false,
-    responseImageCached: false
-  });
-
-  networkPanel.panel.hidePopup();
-
-  // Second run: Test for cookies and response body.
-  info("test 6: cookies and response body");
-  httpActivity.request.cookies.push(
-    { name: "foo", value: "bar" },
-    { name: "hello", value: "world" }
-  );
-  httpActivity.response.content.text = "get out here";
-
-  networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
-  is(filterBox._netPanel, networkPanel,
-     "Network panel stored on httpActivity object");
-
-  networkPanel._onUpdate = function() {
-    networkPanel._onUpdate = null;
-    executeSoon(function() {
-      testDriver.next();
-    });
-  };
-
-  yield undefined;
-
-  checkIsVisible(networkPanel, {
-    requestBody: true,
-    requestFormData: false,
-    requestCookie: true,
-    responseContainer: true,
-    responseCookie: false,
-    responseBody: true,
-    responseNoBody: false,
-    responseImage: false,
-    responseImageCached: false
-  });
-
-  checkNodeKeyValue(networkPanel, "requestCookieContent", "foo", "bar");
-  checkNodeKeyValue(networkPanel, "requestCookieContent", "hello", "world");
-  checkNodeContent(networkPanel, "responseBodyContent", "get out here");
-  checkNodeContent(networkPanel, "responseBodyInfo", "2ms");
-
-  networkPanel.panel.hidePopup();
-
-  // Third run: Test for response cookies.
-  info("test 6b: response cookies");
-  httpActivity.response.cookies.push(
-    { name: "foobar", value: "boom" },
-    { name: "foobaz", value: "omg" }
-  );
-
-  networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
-  is(filterBox._netPanel, networkPanel,
-     "Network panel stored on httpActivity object");
-
-  networkPanel._onUpdate = function() {
-    networkPanel._onUpdate = null;
-    executeSoon(function() {
-      testDriver.next();
-    });
-  };
-
-  yield undefined;
-
-  checkIsVisible(networkPanel, {
-    requestBody: true,
-    requestFormData: false,
-    requestCookie: true,
-    responseContainer: true,
-    responseCookie: true,
-    responseBody: true,
-    responseNoBody: false,
-    responseImage: false,
-    responseImageCached: false,
-    responseBodyFetchLink: false,
-  });
-
-  checkNodeKeyValue(networkPanel, "responseCookieContent", "foobar", "boom");
-  checkNodeKeyValue(networkPanel, "responseCookieContent", "foobaz", "omg");
-
-  networkPanel.panel.hidePopup();
-
-  // Check image request.
-  info("test 7: image request");
-  httpActivity.response.headers[1].value = "image/png";
-  httpActivity.response.content.mimeType = "image/png";
-  httpActivity.response.content.text = TEST_IMG_BASE64;
-  httpActivity.request.url = TEST_IMG;
-
-  networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
-  networkPanel._onUpdate = function() {
-    networkPanel._onUpdate = null;
-    executeSoon(function() {
-      testDriver.next();
-    });
-  };
-
-  yield undefined;
-
-  checkIsVisible(networkPanel, {
-    requestBody: true,
-    requestFormData: false,
-    requestCookie: true,
-    responseContainer: true,
-    responseBody: false,
-    responseNoBody: false,
-    responseImage: true,
-    responseImageCached: false,
-    responseBodyFetchLink: false,
-  });
-
-  let imgNode = networkPanel.document.getElementById("responseImageNode");
-  is(imgNode.getAttribute("src"), "data:image/png;base64," + TEST_IMG_BASE64,
-      "Displayed image is correct");
-
-  function checkImageResponseInfo() {
-    checkNodeContent(networkPanel, "responseImageInfo", "2ms");
-    checkNodeContent(networkPanel, "responseImageInfo", "16x16px");
-  }
-
-  // Check if the image is loaded already.
-  imgNode.addEventListener("load", function onLoad() {
-    imgNode.removeEventListener("load", onLoad, false);
-    checkImageResponseInfo();
-    networkPanel.panel.hidePopup();
-    testDriver.next();
-  }, false);
-  yield undefined;
-
-  // Check cached image request.
-  info("test 8: cached image request");
-  httpActivity.response.httpVersion = "HTTP/1.1";
-  httpActivity.response.status = 304;
-  httpActivity.response.statusText = "Not Modified";
-
-  networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
-  networkPanel._onUpdate = function() {
-    networkPanel._onUpdate = null;
-    executeSoon(function() {
-      testDriver.next();
-    });
-  };
-
-  yield undefined;
-
-  checkIsVisible(networkPanel, {
-    requestBody: true,
-    requestFormData: false,
-    requestCookie: true,
-    responseContainer: true,
-    responseBody: false,
-    responseNoBody: false,
-    responseImage: false,
-    responseImageCached: true
-  });
-
-  imgNode = networkPanel.document.getElementById("responseImageCachedNode");
-  is(imgNode.getAttribute("src"), "data:image/png;base64," + TEST_IMG_BASE64,
-     "Displayed image is correct");
-
-  networkPanel.panel.hidePopup();
-
-  // Test sent form data.
-  info("test 9: sent form data");
-  httpActivity.request.postData.text = [
-    "Content-Type:      application/x-www-form-urlencoded",
-    "Content-Length: 59",
-    "name=rob&age=20"
-  ].join("\n");
-
-  networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
-  networkPanel._onUpdate = function() {
-    networkPanel._onUpdate = null;
-    executeSoon(function() {
-      testDriver.next();
-    });
-  };
-
-  yield undefined;
-
-  checkIsVisible(networkPanel, {
-    requestBody: false,
-    requestFormData: true,
-    requestCookie: true,
-    responseContainer: true,
-    responseBody: false,
-    responseNoBody: false,
-    responseImage: false,
-    responseImageCached: true
-  });
-
-  checkNodeKeyValue(networkPanel, "requestFormDataContent", "name", "rob");
-  checkNodeKeyValue(networkPanel, "requestFormDataContent", "age", "20");
-  networkPanel.panel.hidePopup();
-
-  // Test no space after Content-Type:
-  info("test 10: no space after Content-Type header in post data");
-  httpActivity.request.postData.text = "Content-Type:application/x-www-" +
-                                       "form-urlencoded\n";
-
-  networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
-  networkPanel._onUpdate = function() {
-    networkPanel._onUpdate = null;
-    executeSoon(function() {
-      testDriver.next();
-    });
-  };
-
-  yield undefined;
-
-  checkIsVisible(networkPanel, {
-    requestBody: false,
-    requestFormData: true,
-    requestCookie: true,
-    responseContainer: true,
-    responseBody: false,
-    responseNoBody: false,
-    responseImage: false,
-    responseImageCached: true
-  });
-
-  networkPanel.panel.hidePopup();
-
-  // Test cached data.
-
-  info("test 11: cached data");
-
-  httpActivity.request.url = TEST_ENCODING_ISO_8859_1;
-  httpActivity.response.headers[1].value = "application/json";
-  httpActivity.response.content.mimeType = "application/json";
-  httpActivity.response.content.text = "my cached data is here!";
-
-  networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
-  networkPanel._onUpdate = function() {
-    networkPanel._onUpdate = null;
-    executeSoon(function() {
-      testDriver.next();
-    });
-  };
-
-  yield undefined;
-
-  checkIsVisible(networkPanel, {
-    requestBody: false,
-    requestFormData: true,
-    requestCookie: true,
-    responseContainer: true,
-    responseBody: false,
-    responseBodyCached: true,
-    responseNoBody: false,
-    responseImage: false,
-    responseImageCached: false
-  });
-
-  checkNodeContent(networkPanel, "responseBodyCachedContent",
-                   "my cached data is here!");
-
-  networkPanel.panel.hidePopup();
-
-  // Test a response with a content type that can't be displayed in the
-  // NetworkPanel.
-  info("test 12: unknown content type");
-  httpActivity.response.headers[1].value = "application/x-shockwave-flash";
-  httpActivity.response.content.mimeType = "application/x-shockwave-flash";
-
-  networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
-  networkPanel._onUpdate = function() {
-    networkPanel._onUpdate = null;
-    executeSoon(function() {
-      testDriver.next();
-    });
-  };
-
-  yield undefined;
-
-  checkIsVisible(networkPanel, {
-    requestBody: false,
-    requestFormData: true,
-    requestCookie: true,
-    responseContainer: true,
-    responseBody: false,
-    responseBodyCached: false,
-    responseBodyUnknownType: true,
-    responseNoBody: false,
-    responseImage: false,
-    responseImageCached: false
-  });
-
-  let responseString =
-    WCUL10n.getFormatStr("NetworkPanel.responseBodyUnableToDisplay.content",
-                      ["application/x-shockwave-flash"]);
-  checkNodeContent(networkPanel,
-                   "responseBodyUnknownTypeContent",
-                   responseString);
-  networkPanel.panel.hidePopup();
-
-  /*
-
-  // This test disabled. See bug 603620.
-
-  // Test if the NetworkPanel figures out the content type based on an URL as
-  // well.
-  delete httpActivity.response.header["Content-Type"];
-  httpActivity.url = "http://www.test.com/someCrazyFile.swf?done=right&ending=txt";
-
-  networkPanel = hud.ui.openNetworkPanel(filterBox, httpActivity);
-  networkPanel.isDoneCallback = function NP_doneCallback() {
-    networkPanel.isDoneCallback = null;
-    testDriver.next();
-  }
-
-  yield undefined;
-
-  checkIsVisible(networkPanel, {
-    requestBody: false,
-    requestFormData: true,
-    requestCookie: true,
-    responseContainer: true,
-    responseBody: false,
-    responseBodyCached: false,
-    responseBodyUnknownType: true,
-    responseNoBody: false,
-    responseImage: false,
-    responseImageCached: false
-  });
-
-  // Systems without Flash installed will return an empty string here. Ignore.
-  if (networkPanel.document.getElementById("responseBodyUnknownTypeContent").textContent !== "")
-    checkNodeContent(networkPanel, "responseBodyUnknownTypeContent", responseString);
-  else
-    ok(true, "Flash not installed");
-
-  networkPanel.panel.hidePopup(); */
-
-  // All done!
-  testDriver = hud = null;
-  executeSoon(finishTest);
-
-  yield undefined;
-}
--- a/browser/devtools/webconsole/webconsole.js
+++ b/browser/devtools/webconsole/webconsole.js
@@ -15,18 +15,16 @@ loader.lazyServiceGetter(this, "clipboar
                          "@mozilla.org/widget/clipboardhelper;1",
                          "nsIClipboardHelper");
 loader.lazyImporter(this, "Services", "resource://gre/modules/Services.jsm");
 loader.lazyGetter(this, "EventEmitter", () => require("devtools/toolkit/event-emitter"));
 loader.lazyGetter(this, "AutocompletePopup",
                   () => require("devtools/shared/autocomplete-popup").AutocompletePopup);
 loader.lazyGetter(this, "ToolSidebar",
                   () => require("devtools/framework/sidebar").ToolSidebar);
-loader.lazyGetter(this, "NetworkPanel",
-                  () => require("devtools/webconsole/network-panel").NetworkPanel);
 loader.lazyGetter(this, "ConsoleOutput",
                   () => require("devtools/webconsole/console-output").ConsoleOutput);
 loader.lazyGetter(this, "Messages",
                   () => require("devtools/webconsole/console-output").Messages);
 loader.lazyGetter(this, "asyncStorage",
                   () => require("devtools/toolkit/shared/async-storage"));
 loader.lazyRequireGetter(this, "EnvironmentClient", "devtools/toolkit/client/main", true);
 loader.lazyRequireGetter(this, "ObjectClient", "devtools/toolkit/client/main", true);
@@ -1668,21 +1666,17 @@ WebConsoleFrame.prototype = {
       messageNode.classList.add("mixed-content");
       this.makeMixedContentNode(body);
     }
 
     let statusNode = this.document.createElementNS(XHTML_NS, "a");
     statusNode.className = "status";
     body.appendChild(statusNode);
 
-    let onClick = () => {
-      if (!messageNode._panelOpen) {
-        this.openNetworkPanel(messageNode, networkInfo);
-      }
-    };
+    let onClick = () => this.openNetworkPanel(networkInfo.actor);
 
     this._addMessageLinkCallback(urlNode, onClick);
     this._addMessageLinkCallback(statusNode, onClick);
 
     networkInfo.node = messageNode;
 
     this._updateNetMessage(actorId);
 
@@ -1964,144 +1958,27 @@ WebConsoleFrame.prototype = {
     if (messageNode._netPanel) {
       messageNode._netPanel.update();
     }
 
     return updated;
   },
 
   /**
-   * Opens a NetworkPanel.
+   * Opens the network monitor and highlights the specified request.
    *
-   * @param nsIDOMNode aNode
-   *        The message node you want the panel to be anchored to.
-   * @param object aHttpActivity
-   *        The HTTP activity object that holds network request and response
-   *        information. This object is given to the NetworkPanel constructor.
-   * @return object
-   *         The new NetworkPanel instance.
+   * @param string requestId
+   *        The actor ID of the network request.
    */
-  openNetworkPanel: function WCF_openNetworkPanel(aNode, aHttpActivity)
+  openNetworkPanel: function WCF_openNetworkPanel(requestId)
   {
-    let actor = aHttpActivity.actor;
-
-    if (actor) {
-      this.webConsoleClient.getRequestHeaders(actor, (aResponse) => {
-        if (aResponse.error) {
-          Cu.reportError("WCF_openNetworkPanel getRequestHeaders:" +
-                         aResponse.error);
-          return;
-        }
-
-        aHttpActivity.request.headers = aResponse.headers;
-
-        this.webConsoleClient.getRequestCookies(actor, onRequestCookies);
-      });
-    }
-
-    let onRequestCookies = (aResponse) => {
-      if (aResponse.error) {
-        Cu.reportError("WCF_openNetworkPanel getRequestCookies:" +
-                       aResponse.error);
-        return;
-      }
-
-      aHttpActivity.request.cookies = aResponse.cookies;
-
-      this.webConsoleClient.getResponseHeaders(actor, onResponseHeaders);
-    };
-
-    let onResponseHeaders = (aResponse) => {
-      if (aResponse.error) {
-        Cu.reportError("WCF_openNetworkPanel getResponseHeaders:" +
-                       aResponse.error);
-        return;
-      }
-
-      aHttpActivity.response.headers = aResponse.headers;
-
-      this.webConsoleClient.getResponseCookies(actor, onResponseCookies);
-    };
-
-    let onResponseCookies = (aResponse) => {
-      if (aResponse.error) {
-        Cu.reportError("WCF_openNetworkPanel getResponseCookies:" +
-                       aResponse.error);
-        return;
-      }
-
-      aHttpActivity.response.cookies = aResponse.cookies;
-
-      this.webConsoleClient.getRequestPostData(actor, onRequestPostData);
-    };
-
-    let onRequestPostData = (aResponse) => {
-      if (aResponse.error) {
-        Cu.reportError("WCF_openNetworkPanel getRequestPostData:" +
-                       aResponse.error);
-        return;
-      }
-
-      aHttpActivity.request.postData = aResponse.postData;
-      aHttpActivity.discardRequestBody = aResponse.postDataDiscarded;
-
-      this.webConsoleClient.getResponseContent(actor, onResponseContent);
-    };
-
-    let onResponseContent = (aResponse) => {
-      if (aResponse.error) {
-        Cu.reportError("WCF_openNetworkPanel getResponseContent:" +
-                       aResponse.error);
-        return;
-      }
-
-      aHttpActivity.response.content = aResponse.content;
-      aHttpActivity.discardResponseBody = aResponse.contentDiscarded;
-
-      this.webConsoleClient.getEventTimings(actor, onEventTimings);
-    };
-
-    let onEventTimings = (aResponse) => {
-      if (aResponse.error) {
-        Cu.reportError("WCF_openNetworkPanel getEventTimings:" +
-                       aResponse.error);
-        return;
-      }
-
-      aHttpActivity.timings = aResponse.timings;
-
-      openPanel();
-    };
-
-    let openPanel = () => {
-      aNode._netPanel = netPanel;
-
-      let panel = netPanel.panel;
-      panel.openPopup(aNode, "after_pointer", 0, 0, false, false);
-      panel.sizeTo(450, 500);
-      panel.setAttribute("hudId", this.hudId);
-
-      panel.addEventListener("popuphiding", function WCF_netPanel_onHide() {
-        panel.removeEventListener("popuphiding", WCF_netPanel_onHide);
-
-        aNode._panelOpen = false;
-        aNode._netPanel = null;
-      });
-
-      aNode._panelOpen = true;
-    };
-
-    let netPanel = new NetworkPanel(this.popupset, aHttpActivity, this);
-    netPanel.linkNode = aNode;
-
-    if (!actor) {
-      openPanel();
-    }
-
-    return netPanel;
+    let toolbox = gDevTools.getToolbox(this.owner.target);
+    return toolbox.selectTool("netmonitor").then(panel => {
+      return panel.panelWin.NetMonitorController.inspectRequest(requestId);
+    });
   },
 
   /**
    * Handler for page location changes.
    *
    * @param string aURI
    *        New page location.
    * @param string aTitle
--- a/browser/locales/en-US/chrome/browser/devtools/markers.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/markers.properties
@@ -13,16 +13,17 @@
 
 # LOCALIZATION NOTE (marker.label.*):
 # These strings are displayed in the Performance Tool waterfall, identifying markers.
 # We want to use the same wording as Google Chrome when appropriate.
 marker.label.styles=Recalculate Style
 marker.label.reflow=Layout
 marker.label.paint=Paint
 marker.label.composite=Composite Layers
+marker.label.compositeForwardTransaction=Composite Request Sent
 marker.label.javascript=Function Call
 marker.label.parseHTML=Parse HTML
 marker.label.parseXML=Parse XML
 marker.label.domevent=DOM Event
 marker.label.consoleTime=Console
 marker.label.garbageCollection2=Garbage Collection
 marker.label.garbageCollection.incremental=Incremental GC
 marker.label.garbageCollection.nonIncremental=Non-incremental GC
--- a/browser/locales/en-US/chrome/browser/devtools/webConsole.dtd
+++ b/browser/locales/en-US/chrome/browser/devtools/webConsole.dtd
@@ -6,34 +6,16 @@
   - keep it in English, or another language commonly spoken among web developers.
   - You want to make that choice consistent across the developer tools.
   - A good criteria is the language in which you'd find the best
   - documentation on web development on the web. -->
 
 <!ENTITY window.title "Web Console">
 <!ENTITY browserConsole.title "Browser Console">
 
-<!ENTITY networkPanel.requestURLColon             "Request URL:">
-<!ENTITY networkPanel.requestMethodColon          "Request Method:">
-<!ENTITY networkPanel.statusCodeColon             "Status Code:">
-
-<!ENTITY networkPanel.requestHeaders              "Request Headers">
-<!ENTITY networkPanel.requestCookie               "Sent Cookie">
-<!ENTITY networkPanel.requestBody                 "Request Body">
-<!ENTITY networkPanel.requestFormData             "Sent Form Data">
-
-<!ENTITY networkPanel.responseHeaders             "Response Headers">
-<!ENTITY networkPanel.responseCookie              "Received Cookie">
-<!ENTITY networkPanel.responseBody                "Response Body">
-<!ENTITY networkPanel.responseBodyCached          "Cached Data">
-<!ENTITY networkPanel.responseBodyUnknownType     "Unknown Content Type">
-<!ENTITY networkPanel.responseNoBody              "No Response Body">
-<!ENTITY networkPanel.responseImage               "Received Image">
-<!ENTITY networkPanel.responseImageCached         "Cached Image">
-
 <!-- LOCALIZATION NOTE (saveBodies.label): You can see this string in the Web
    - Console context menu. -->
 <!ENTITY saveBodies.label     "Log Request and Response Bodies">
 <!ENTITY saveBodies.accesskey "L">
 
 <!-- LOCALIZATION NOTE (openURL.label): You can see this string in the Web
    - Console context menu. -->
 <!ENTITY openURL.label     "Open URL in New Tab">
--- a/browser/locales/en-US/chrome/browser/devtools/webconsole.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/webconsole.properties
@@ -35,39 +35,22 @@ update.accesskey=U
 cmd.commandkey=K
 webConsoleCmd.accesskey=W
 
 # LOCALIZATION NOTE (timestampFormat): %1$02S = hours (24-hour clock),
 # %2$02S = minutes, %3$02S = seconds, %4$03S = milliseconds.
 timestampFormat=%02S:%02S:%02S.%03S
 
 helperFuncUnsupportedTypeError=Can't call pprint on this type of object.
-NetworkPanel.label=Inspect Network Request
 
 # LOCALIZATION NOTE (NetworkPanel.deltaDurationMS): this string is used to
 # show the duration between two network events (e.g request and response
 # header or response header and response body). Parameters: %S is the duration.
 NetworkPanel.durationMS=%Sms
 
-# LOCALIZATION NOTE (NetworkPanel.imageSizeDeltaDurationMS): this string is
-# used to show the duration between the response header and the response body
-# event. It also shows the size of the received or cached image. Parameters:
-# %1$S is the width of the inspected image, %2$S is the height of the
-# inspected image, %3$S is the duration between the response header and the
-# response body event. Example: 150x100px, Δ50ms.
-NetworkPanel.imageSizeDeltaDurationMS=%1$Sx%2$Spx, Δ%3$Sms
-
-# LOCALIZATION NOTE (NetworkPanel.responseBodyUnableToDisplay.content): this
-# string is displayed within the response body section of the NetworkPanel if
-# the content type of the network request can't be displayed. E.g. any kind of
-# text is easy to display, but some audio or flash data received from the
-# server can't be displayed. Parameters: %S is the content type that can't be
-# displayed, examples are application/x-shockwave-flash, music/crescendo.
-NetworkPanel.responseBodyUnableToDisplay.content=Unable to display responses of type "%S"
-
 ConsoleAPIDisabled=The Web Console logging API (console.log, console.info, console.warn, console.error) has been disabled by a script on this page.
 
 # LOCALIZATION NOTE (webConsoleWindowTitleAndURL): the Web Console floating
 # panel title. For RTL languages you need to set the LRM in the string to give
 # the URL the correct direction. Parameters: %S is the web page URL.
 webConsoleWindowTitleAndURL=Web Console - %S
 
 # LOCALIZATION NOTE (webConsoleXhrIndicator): the indicator displayed before
--- a/browser/locales/en-US/chrome/browser/loop/loop.properties
+++ b/browser/locales/en-US/chrome/browser/loop/loop.properties
@@ -132,22 +132,22 @@ import_contacts_success_message={{total}
 ## importing_contacts_button once contacts have been imported once.
 sync_contacts_button=Sync Contacts
 ## LOCALIZATION NOTE(no_contacts_message_heading2): Title shown when user has no
 ## contacts in his address book
 no_contacts_message_heading2=No contacts yet.
 ## LOCALIZATION NOTE(no_contacts_import_or_add2): Subheading inviting the user
 ## to add people to his contact list
 no_contacts_import_or_add2=Add someone!
-## LOCALIZATION NOTE(no_conversations_message_heading): Title shown when user
+## LOCALIZATION NOTE(no_conversations_message_heading2): Title shown when user
 ## has no conversations available.
-no_conversations_message_heading=There are no conversations yet
-## LOCALIZATION NOTE(no_converastions_start_message): Subheading inviting the
+no_conversations_message_heading2=No conversations yet.
+## LOCALIZATION NOTE(no_conversations_start_message2): Subheading inviting the
 ## user to start a new conversation.
-no_conversations_start_message=start a new conversation!
+no_conversations_start_message2=Start a new one!
 ## LOCALIZATION NOTE(contacts_no_search_results): Message shown when contacts
 ## search returned no matching results.
 contacts_no_search_results=No matching results.
 
 ## LOCALIZATION NOTE(import_failed_description simple): Displayed when an import of
 ## contacts fails. This is displayed in the error field.
 import_failed_description_simple=Sorry, contact import failed
 import_failed_description_some=Some contacts could not be imported
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -325,17 +325,16 @@ browser.jar:
   skin/classic/browser/devtools/command-eyedropper.png        (../shared/devtools/images/command-eyedropper.png)
   skin/classic/browser/devtools/command-eyedropper@2x.png     (../shared/devtools/images/command-eyedropper@2x.png)
   skin/classic/browser/devtools/command-rulers.png            (../shared/devtools/images/command-rulers.png)
   skin/classic/browser/devtools/command-rulers@2x.png         (../shared/devtools/images/command-rulers@2x.png)
   skin/classic/browser/devtools/alerticon-warning.png (../shared/devtools/images/alerticon-warning.png)
   skin/classic/browser/devtools/alerticon-warning@2x.png      (../shared/devtools/images/alerticon-warning@2x.png)
 * skin/classic/browser/devtools/ruleview.css          (../shared/devtools/ruleview.css)
 * skin/classic/browser/devtools/webconsole.css                  (../shared/devtools/webconsole.css)
-  skin/classic/browser/devtools/webconsole_networkpanel.css     (../shared/devtools/webconsole_networkpanel.css)
   skin/classic/browser/devtools/webconsole.svg                  (../shared/devtools/images/webconsole.svg)
   skin/classic/browser/devtools/commandline.css              (../shared/devtools/commandline.css)
   skin/classic/browser/devtools/markup-view.css       (../shared/devtools/markup-view.css)
   skin/classic/browser/devtools/editor-error.png       (../shared/devtools/images/editor-error.png)
   skin/classic/browser/devtools/editor-breakpoint.png  (../shared/devtools/images/editor-breakpoint.png)
   skin/classic/browser/devtools/editor-debug-location.png (../shared/devtools/images/editor-debug-location.png)
   skin/classic/browser/devtools/editor-debug-location@2x.png (../shared/devtools/images/editor-debug-location@2x.png)
   skin/classic/browser/devtools/breadcrumbs-divider@2x.png      (../shared/devtools/images/breadcrumbs-divider@2x.png)
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -427,17 +427,16 @@ browser.jar:
   skin/classic/browser/devtools/commandline.css             (../shared/devtools/commandline.css)
   skin/classic/browser/devtools/markup-view.css             (../shared/devtools/markup-view.css)
   skin/classic/browser/devtools/editor-error.png             (../shared/devtools/images/editor-error.png)
   skin/classic/browser/devtools/editor-breakpoint.png        (../shared/devtools/images/editor-breakpoint.png)
   skin/classic/browser/devtools/editor-breakpoint@2x.png        (../shared/devtools/images/editor-breakpoint@2x.png)
   skin/classic/browser/devtools/editor-debug-location.png    (../shared/devtools/images/editor-debug-location.png)
   skin/classic/browser/devtools/editor-debug-location@2x.png    (../shared/devtools/images/editor-debug-location@2x.png)
 * skin/classic/browser/devtools/webconsole.css                  (../shared/devtools/webconsole.css)
-  skin/classic/browser/devtools/webconsole_networkpanel.css     (../shared/devtools/webconsole_networkpanel.css)
   skin/classic/browser/devtools/webconsole.svg                  (../shared/devtools/images/webconsole.svg)
   skin/classic/browser/devtools/breadcrumbs-divider@2x.png      (../shared/devtools/images/breadcrumbs-divider@2x.png)
   skin/classic/browser/devtools/breadcrumbs-scrollbutton.png    (../shared/devtools/images/breadcrumbs-scrollbutton.png)
   skin/classic/browser/devtools/breadcrumbs-scrollbutton@2x.png (../shared/devtools/images/breadcrumbs-scrollbutton@2x.png)
   skin/classic/browser/devtools/animationinspector.css          (../shared/devtools/animationinspector.css)
 * skin/classic/browser/devtools/canvasdebugger.css          (../shared/devtools/canvasdebugger.css)
   skin/classic/browser/devtools/debugger.css                (../shared/devtools/debugger.css)
   skin/classic/browser/devtools/eyedropper.css              (../shared/devtools/eyedropper.css)
--- a/browser/themes/shared/devtools/dark-theme.css
+++ b/browser/themes/shared/devtools/dark-theme.css
@@ -33,16 +33,17 @@
   --theme-highlight-lightorange: #d99b28;
   --theme-highlight-orange: #d96629;
   --theme-highlight-red: #eb5368;
   --theme-highlight-pink: #df80ff;
 
   /* Colors used in Graphs, like performance tools. Mostly similar to some "highlight-*" colors. */
   --theme-graphs-green: #70bf53;
   --theme-graphs-blue: #46afe3;
+  --theme-graphs-bluegrey: #5e88b0;
   --theme-graphs-purple: #df80ff;
   --theme-graphs-yellow: #d99b28;
   --theme-graphs-red: #eb5368;
   --theme-graphs-grey: #757873;
 }
 
 .theme-body {
   background: var(--theme-body-background);
--- a/browser/themes/shared/devtools/light-theme.css
+++ b/browser/themes/shared/devtools/light-theme.css
@@ -33,16 +33,17 @@
   --theme-highlight-lightorange: #d97e00;
   --theme-highlight-orange: #f13c00;
   --theme-highlight-red: #ed2655;
   --theme-highlight-pink: #b82ee5;
 
   /* Colors used in Graphs, like performance tools. Similar colors to Chrome's timeline. */
   --theme-graphs-green: #85d175;
   --theme-graphs-blue: #83b7f6;
+  --theme-graphs-bluegrey: #0072ab;
   --theme-graphs-purple: #b693eb;
   --theme-graphs-yellow: #efc052;
   --theme-graphs-red: #e57180;
   --theme-graphs-grey: #cccccc;
 }
 
 .theme-body {
   background: var(--theme-body-background);
--- a/browser/themes/shared/devtools/performance.css
+++ b/browser/themes/shared/devtools/performance.css
@@ -544,39 +544,43 @@
   padding: 2px 5px;
   border-width: 1px;
 }
 
 /**
  * Marker colors
  */
 
+menuitem.marker-color-graphs-green:before,
+.marker-color-graphs-green {
+  background-color: var(--theme-graphs-green);
+}
+menuitem.marker-color-graphs-blue:before,
+.marker-color-graphs-blue {
+  background-color: var(--theme-graphs-blue);
+}
+menuitem.marker-color-graphs-bluegrey:before,
+.marker-color-graphs-bluegrey {
+  background-color: var(--theme-graphs-bluegrey);
+}
 menuitem.marker-color-graphs-purple:before,
 .marker-color-graphs-purple {
   background-color: var(--theme-graphs-purple);
 }
-menuitem.marker-color-graphs-grey:before,
-.marker-color-graphs-grey{
-  background-color: var(--theme-graphs-grey);
-}
-menuitem.marker-color-graphs-green:before,
-.marker-color-graphs-green {
-  background-color: var(--theme-graphs-green);
-}
 menuitem.marker-color-graphs-yellow:before,
 .marker-color-graphs-yellow {
   background-color: var(--theme-graphs-yellow);
 }
 menuitem.marker-color-graphs-red:before,
 .marker-color-graphs-red {
   background-color: var(--theme-graphs-red);
 }
-menuitem.marker-color-graphs-blue:before,
-.marker-color-graphs-blue {
-  background-color: var(--theme-graphs-blue);
+menuitem.marker-color-graphs-grey:before,
+.marker-color-graphs-grey{
+  background-color: var(--theme-graphs-grey);
 }
 
 /**
  * JIT View
  */
 
 #jit-optimizations-view {
   width: 350px;
deleted file mode 100644
--- a/browser/themes/shared/devtools/webconsole_networkpanel.css
+++ /dev/null
@@ -1,100 +0,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/. */
-
-body {
-  font-family: sans-serif;
-  font-size: 11px;
-  background: #EEE;
-  color: #000;
-}
-
-#header {
-  padding: 5px;
-  overflow-x:auto;
-  display: block;
-}
-
-h1 {
-  font-size: 13px;
-  line-height: 15px;
-  padding: 3px 10px;
-  vertical-align: bottom;
-  margin: 0px;
-  background: linear-gradient(#BBB, #999);
-  border-radius: 2px;
-  text-shadow: #FFF 0px 1px 0px;
-}
-
-h1 .info {
-  font-size: 11px;
-  line-height: 15px;
-  vertical-align: bottom;
-  float: right;
-  color: #333;
-  padding-right: 3px;
-}
-
-.property-table {
-  padding: 2px 5px;
-  background: linear-gradient(#FFF, #F8F8F8);
-  color: #333;
-  width: 100%;
-  max-height: 330px;
-  overflow: auto;
-  display: block;
-}
-
-.property-name {
-  font-size: 11px;
-  font-weight: bold;
-  padding-right: 4px;
-  color: #000;
-  white-space: nowrap;
-  text-align: end;
-  vertical-align: top;
-  width: 10%;
-}
-
-.property-value {
-  padding-right: 5px;
-  font-size: 11px;
-  word-wrap: break-word;
-  width: 90%;
-}
-
-div.group {
-  margin-top: 10px;
-}
-
-div.group,
-#header {
-  background: #FFF;
-  border-color: #E1E1E1;
-  border-style: solid;
-  border-width: 1px;
-  box-shadow: 0 1px 1.5px rgba(0, 0, 0, 0.2);
-  border-radius: 4px 4px 4px 4px;
-}
-
-img#responseImageNode {
-  box-shadow: rgba(0,0,0,0.2) 0px 3px 3.5px;
-  max-width: 100%;
-}
-
-#responseImageNodeDiv {
-  padding: 5px;
-}
-
-#responseBodyFetchLink, #requestBodyFetchLink {
-  padding: 5px;
-  margin: 0;
-  cursor: pointer;
-  font-weight: bold;
-  font-size: 1.1em;
-  text-decoration: underline;
-}
-
-.longStringEllipsis {
-  margin-left: 0.6em;
-}
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -20,25 +20,25 @@
 :root {
   --space-above-tabbar: 15px;
 
   --backbutton-urlbar-overlap: 5px;
 
   --toolbarbutton-vertical-inner-padding: 2px;
   --toolbarbutton-vertical-outer-padding: 8px;
 
-  --toolbarbutton-hover-background: hsla(210,4%,10%,.08);
-  --toolbarbutton-hover-bordercolor: hsla(210,4%,10%,.1);
+  --toolbarbutton-hover-background: rgba(0,0,0,.1);
+  --toolbarbutton-hover-bordercolor: rgba(0,0,0,.1);
   --toolbarbutton-hover-boxshadow: none;
 
-  --toolbarbutton-active-background: hsla(210,4%,10%,.12);
-  --toolbarbutton-active-bordercolor: hsla(210,4%,10%,.2) transparent transparent;
-  --toolbarbutton-active-boxshadow: 0 1px 0 0 hsla(210,4%,10%,.1) inset;
-
-  --toolbarbutton-checkedhover-backgroundcolor: hsla(210,4%,10%,.12);
+  --toolbarbutton-active-background: rgba(0,0,0,.15);
+  --toolbarbutton-active-bordercolor: rgba(0,0,0,.15);
+  --toolbarbutton-active-boxshadow: 0 0 0 1px rgba(0,0,0,.15) inset;
+
+  --toolbarbutton-checkedhover-backgroundcolor: rgba(0,0,0,.15);
 
   --identity-box-verified-background-color: #fff;
 
   --urlbar-dropmarker-url: url("chrome://browser/skin/urlbar-history-dropmarker.png");
   --urlbar-dropmarker-region: rect(0px, 11px, 14px, 0px);
   --urlbar-dropmarker-hover-region: rect(0px, 22px, 14px, 11px);
   --urlbar-dropmarker-active-region: rect(0px, 33px, 14px, 22px);
   --urlbar-dropmarker-2x-url: url("chrome://browser/skin/urlbar-history-dropmarker@2x.png");
@@ -46,16 +46,26 @@
   --urlbar-dropmarker-hover-2x-region: rect(0, 44px, 28px, 22px);
   --urlbar-dropmarker-active-2x-region: rect(0, 66px, 28px, 44px);
 
   --panel-separator-color: ThreeDLightShadow;
 
   --urlbar-separator-color: hsla(0,0%,16%,.2);
 }
 
+#nav-bar[brighttext] {
+  --toolbarbutton-hover-background: rgba(255,255,255,.1);
+  --toolbarbutton-hover-bordercolor: rgba(255,255,255,.1);
+  --toolbarbutton-hover-boxshadow: none;
+
+  --toolbarbutton-active-background: rgba(255,255,255,.15);
+  --toolbarbutton-active-bordercolor: rgba(255,255,255,.15);
+  --toolbarbutton-active-boxshadow: 0 0 0 1px rgba(255,255,255,.15) inset;
+}
+
 #menubar-items {
   -moz-box-orient: vertical; /* for flex hack */
 }
 
 #main-menubar {
   -moz-box-flex: 1; /* make menu items expand to fill toolbar height */
 }
 
@@ -715,18 +725,18 @@ toolbar[brighttext] .toolbarbutton-1 > .
 .findbar-button > .toolbarbutton-text,
 #nav-bar .toolbarbutton-1 > .toolbarbutton-icon,
 #nav-bar .toolbarbutton-1 > .toolbarbutton-text,
 #nav-bar .toolbarbutton-1 > .toolbarbutton-badge-stack,
 #nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
 #nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
 @conditionalForwardWithUrlbar@ > .toolbarbutton-1:-moz-any([disabled],:not([open]):not([disabled]):not(:active)) > .toolbarbutton-icon {
   padding: var(--toolbarbutton-vertical-inner-padding) 6px;
-  border: 1px solid;
-  border-color: transparent;
+  border: 1px solid transparent;
+  border-radius: 1px;
   transition-property: background-color, border-color;
   transition-duration: 150ms;
 }
 
 toolbaritem[cui-areatype="toolbar"] > :-moz-any(@nestedButtons@) > .toolbarbutton-icon,
 :-moz-any(@primaryToolbarButtons@):-moz-any([cui-areatype="toolbar"],:not([cui-areatype])):not(:-moz-any(@nestedButtons@)) > .toolbarbutton-icon,
 :-moz-any(@primaryToolbarButtons@):-moz-any([cui-areatype="toolbar"],:not([cui-areatype])) > .toolbarbutton-badge-stack > .toolbarbutton-icon,
 :-moz-any(@primaryToolbarButtons@):-moz-any([cui-areatype="toolbar"],:not([cui-areatype])) > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
@@ -776,16 +786,32 @@ toolbaritem[cui-areatype="toolbar"] > :-
     box-shadow: 0 1px hsla(0,0%,100%,0) inset,
                 0 1px hsla(210,54%,20%,0),
                 0 0 2px hsla(210,54%,20%,0);
     transition-property: background-color, border-color, box-shadow;
     transition-duration: 150ms;
   }
 }
 
+#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon:-moz-locale-dir(ltr),
+#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon:-moz-locale-dir(rtl) {
+  border-top-right-radius: 0;
+  border-bottom-right-radius: 0;
+}
+
+#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon:-moz-locale-dir(rtl),
+#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon:-moz-locale-dir(ltr) {
+  border-top-left-radius: 0;
+  border-bottom-left-radius: 0;
+}
+
+#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
+  border-inline-end-style: none;
+}
+
 #nav-bar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-icon,
 #nav-bar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-badge-stack,
 #nav-bar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
   padding: calc(var(--toolbarbutton-vertical-inner-padding) + 1px) 7px;
 }
 
 /* Help SDK icons fit: */
 toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-icon,
@@ -805,20 +831,16 @@ toolbarbutton[constrain-size="true"][cui
 #nav-bar .toolbarbutton-1[type=menu] > .toolbarbutton-text /* hack for add-ons that forcefully display the label */ {
   -moz-padding-end: 17px;
 }
 
 #nav-bar .toolbarbutton-1 > .toolbarbutton-menu-dropmarker {
   -moz-margin-start: -15px;
 }
 
-#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
-  -moz-border-end: none transparent;
-}
-
 #nav-bar #bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
   /* horizontal padding + border + actual icon width */
   width: 31px;
 }
 
 #nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
   padding-top: 8px;
   padding-bottom: 8px;
@@ -876,28 +898,16 @@ toolbarbutton[constrain-size="true"][cui
        (-moz-os-version: windows-win7) {
   /* < Win8 */
   #nav-bar .toolbarbutton-1:not(:hover):not(:active):not([open]) > .toolbarbutton-menubutton-dropmarker::before,
   #nav-bar .toolbaritem-combined-buttons > .toolbarbutton-1:-moz-any(:not(:hover):not([open]),[disabled]) + .toolbarbutton-1:-moz-any(:not(:hover):not([open]),[disabled])::before {
     height: 18px;
     background-size: 1px 18px;
   }
 
-  #nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon:-moz-locale-dir(ltr),
-  #nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon:-moz-locale-dir(rtl) {
-    border-top-right-radius: 0;
-    border-bottom-right-radius: 0;
-  }
-
-  #nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon:-moz-locale-dir(rtl),
-  #nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon:-moz-locale-dir(ltr) {
-    border-top-left-radius: 0;
-    border-bottom-left-radius: 0;
-  }
-
   #nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled]):not([open]):not(:active):hover > .toolbarbutton-icon,
   #nav-bar .toolbarbutton-1:not([buttonover]):not([open]):not(:active):hover > .toolbarbutton-menubutton-dropmarker:not([disabled]) > .dropmarker-icon,
   @conditionalForwardWithUrlbar@ > #forward-button:not([open]):not(:active):not([disabled]):hover > .toolbarbutton-icon {
     border-color: hsla(210,54%,20%,.3) hsla(210,54%,20%,.35) hsla(210,54%,20%,.4);
     background-color: hsla(210,48%,96%,.75);
     box-shadow: 0 0 1px hsla(210,54%,20%,.03),
                 0 0 2px hsla(210,54%,20%,.1);
   }
--- a/browser/themes/windows/devedition.css
+++ b/browser/themes/windows/devedition.css
@@ -245,16 +245,27 @@
 
 #navigator-toolbox {
   /* The side borders on the toolbox also look out-of-place because we don't paint over
    * the native background color at all, and these are !important for the same reason as above. */
   border-left: none !important;
   border-right: none !important;
 }
 
+@media (-moz-os-version: windows-vista),
+       (-moz-os-version: windows-win7),
+       (-moz-os-version: windows-win8) {
+  /* And then we add them back on toolbars so that they don't look borderless: */
+  #main-window:not([customizing])[sizemode=normal] #navigator-toolbox::after,
+  #main-window:not([customizing])[sizemode=normal] #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar) {
+    border-left: 1px solid hsla(209,67%,12%,0.35);
+    border-right: 1px solid hsla(209,67%,12%,0.35);
+  }
+}
+
 @media (-moz-os-version: windows-win10) {
   /* Always keep draggable space on the sides of tabs since there is no top margin on Win10 */
   #main-window .tabbrowser-arrowscrollbox > .arrowscrollbox-scrollbox {
     padding-left: 15px;
     padding-right: 15px;
   }
 
   /* Force white caption buttons for the dark theme on Windows 10 */
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -452,17 +452,16 @@ browser.jar:
         skin/classic/browser/devtools/command-rulers@2x.png         (../shared/devtools/images/command-rulers@2x.png)
         skin/classic/browser/devtools/markup-view.css               (../shared/devtools/markup-view.css)
         skin/classic/browser/devtools/editor-error.png              (../shared/devtools/images/editor-error.png)
         skin/classic/browser/devtools/editor-breakpoint.png         (../shared/devtools/images/editor-breakpoint.png)
         skin/classic/browser/devtools/editor-breakpoint@2x.png         (../shared/devtools/images/editor-breakpoint@2x.png)
         skin/classic/browser/devtools/editor-debug-location.png     (../shared/devtools/images/editor-debug-location.png)
         skin/classic/browser/devtools/editor-debug-location@2x.png     (../shared/devtools/images/editor-debug-location@2x.png)
 *       skin/classic/browser/devtools/webconsole.css                (../shared/devtools/webconsole.css)
-        skin/classic/browser/devtools/webconsole_networkpanel.css   (../shared/devtools/webconsole_networkpanel.css)
         skin/classic/browser/devtools/webconsole.svg                (../shared/devtools/images/webconsole.svg)
         skin/classic/browser/devtools/breadcrumbs-divider@2x.png    (../shared/devtools/images/breadcrumbs-divider@2x.png)
         skin/classic/browser/devtools/breadcrumbs-scrollbutton.png  (../shared/devtools/images/breadcrumbs-scrollbutton.png)
         skin/classic/browser/devtools/breadcrumbs-scrollbutton@2x.png (../shared/devtools/images/breadcrumbs-scrollbutton@2x.png)
         skin/classic/browser/devtools/animationinspector.css        (../shared/devtools/animationinspector.css)
         skin/classic/browser/devtools/eyedropper.css                (../shared/devtools/eyedropper.css)
 *       skin/classic/browser/devtools/canvasdebugger.css            (../shared/devtools/canvasdebugger.css)
         skin/classic/browser/devtools/debugger.css                  (../shared/devtools/debugger.css)
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -277,17 +277,19 @@ private:
   // is stored on docshells directly.
   friend void mozilla::TimelineConsumers::AddConsumer(nsDocShell*);
   friend void mozilla::TimelineConsumers::RemoveConsumer(nsDocShell*);
   friend void mozilla::TimelineConsumers::AddMarkerForDocShell(
     nsDocShell*, const char*, MarkerTracingType);
   friend void mozilla::TimelineConsumers::AddMarkerForDocShell(
     nsDocShell*, const char*, const TimeStamp&, MarkerTracingType);
   friend void mozilla::TimelineConsumers::AddMarkerForDocShell(
-    nsDocShell*, UniquePtr<TimelineMarker>&&);
+    nsDocShell*, UniquePtr<AbstractTimelineMarker>&&);
+  friend void mozilla::TimelineConsumers::AddOTMTMarkerForDocShell(
+    nsDocShell*, UniquePtr<AbstractTimelineMarker>&);
 
 public:
   // Tell the favicon service that aNewURI has the same favicon as aOldURI.
   static void CopyFavicon(nsIURI* aOldURI,
                           nsIURI* aNewURI,
                           bool aInPrivateBrowsing);
 
 protected:
--- a/docshell/base/timeline/AbstractTimelineMarker.cpp
+++ b/docshell/base/timeline/AbstractTimelineMarker.cpp
@@ -23,16 +23,23 @@ AbstractTimelineMarker::AbstractTimeline
                                                MarkerTracingType aTracingType)
   : mName(aName)
   , mTracingType(aTracingType)
 {
   MOZ_COUNT_CTOR(AbstractTimelineMarker);
   SetCustomTime(aTime);
 }
 
+UniquePtr<AbstractTimelineMarker>
+AbstractTimelineMarker::Clone()
+{
+  MOZ_ASSERT(false, "Clone method not yet implemented on this marker type.");
+  return nullptr;
+}
+
 AbstractTimelineMarker::~AbstractTimelineMarker()
 {
   MOZ_COUNT_DTOR(AbstractTimelineMarker);
 }
 
 void
 AbstractTimelineMarker::SetCurrentTime()
 {
--- a/docshell/base/timeline/AbstractTimelineMarker.h
+++ b/docshell/base/timeline/AbstractTimelineMarker.h
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_AbstractTimelineMarker_h_
 #define mozilla_AbstractTimelineMarker_h_
 
 #include "TimelineMarkerEnums.h" // for MarkerTracingType
 #include "nsDOMNavigationTiming.h" // for DOMHighResTimeStamp
+#include "mozilla/UniquePtr.h"
 
 struct JSContext;
 
 namespace mozilla {
 class TimeStamp;
 
 namespace dom {
 struct ProfileTimelineMarker;
@@ -31,18 +32,21 @@ public:
                          MarkerTracingType aTracingType);
 
   AbstractTimelineMarker(const char* aName,
                          const TimeStamp& aTime,
                          MarkerTracingType aTracingType);
 
   virtual ~AbstractTimelineMarker();
 
+  virtual UniquePtr<AbstractTimelineMarker> Clone();
+
   virtual bool Equals(const AbstractTimelineMarker& aOther) = 0;
   virtual void AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker) = 0;
+  virtual JSObject* GetStack() = 0;
 
   const char* GetName() const { return mName; }
   DOMHighResTimeStamp GetTime() const { return mTime; }
   MarkerTracingType GetTracingType() const { return mTracingType; }
 
 private:
   const char* mName;
   DOMHighResTimeStamp mTime;
new file mode 100644
--- /dev/null
+++ b/docshell/base/timeline/OTMTMarkerReceiver.h
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_OTMTMarkerObserver_h_
+#define mozilla_OTMTMarkerObserver_h_
+
+#include "mozilla/Mutex.h"
+
+namespace mozilla {
+class AbstractTimelineMarker;
+
+class OTMTMarkerReceiver
+{
+private:
+  OTMTMarkerReceiver() = delete;
+  OTMTMarkerReceiver(const OTMTMarkerReceiver& aOther) = delete;
+  void operator=(const OTMTMarkerReceiver& aOther) = delete;
+
+public:
+  explicit OTMTMarkerReceiver(const char* aMutexName)
+    : mLock(aMutexName)
+  {
+  }
+
+  virtual ~OTMTMarkerReceiver() {}
+  virtual void AddOTMTMarkerClone(UniquePtr<AbstractTimelineMarker>& aMarker) = 0;
+
+protected:
+  Mutex& GetLock() { return mLock; };
+
+private:
+  Mutex mLock;
+};
+
+} // namespace mozilla
+
+#endif /* mozilla_OTMTMarkerObserver_h_ */
--- a/docshell/base/timeline/ObservedDocShell.cpp
+++ b/docshell/base/timeline/ObservedDocShell.cpp
@@ -1,48 +1,65 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ObservedDocShell.h"
 
-#include "TimelineMarker.h"
+#include "AbstractTimelineMarker.h"
 #include "LayerTimelineMarker.h"
+#include "MainThreadUtils.h"
 #include "mozilla/Move.h"
 
 namespace mozilla {
 
 ObservedDocShell::ObservedDocShell(nsDocShell* aDocShell)
-  : mDocShell(aDocShell)
-{}
+  : OTMTMarkerReceiver("ObservedDocShellMutex")
+  , mDocShell(aDocShell)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+}
 
 void
-ObservedDocShell::AddMarker(UniquePtr<TimelineMarker>&& aMarker)
+ObservedDocShell::AddMarker(UniquePtr<AbstractTimelineMarker>&& aMarker)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   mTimelineMarkers.AppendElement(Move(aMarker));
 }
 
 void
+ObservedDocShell::AddOTMTMarkerClone(UniquePtr<AbstractTimelineMarker>& aMarker)
+{
+  MOZ_ASSERT(!NS_IsMainThread());
+  MutexAutoLock lock(GetLock());
+  UniquePtr<AbstractTimelineMarker> cloned = aMarker->Clone();
+  mTimelineMarkers.AppendElement(Move(cloned));
+}
+
+void
 ObservedDocShell::ClearMarkers()
 {
+  MOZ_ASSERT(NS_IsMainThread());
   mTimelineMarkers.Clear();
 }
 
 void
 ObservedDocShell::PopMarkers(JSContext* aCx,
                              nsTArray<dom::ProfileTimelineMarker>& aStore)
 {
+  MOZ_ASSERT(NS_IsMainThread());
+
   // If we see an unpaired START, we keep it around for the next call
   // to ObservedDocShell::PopMarkers. We store the kept START objects here.
-  nsTArray<UniquePtr<TimelineMarker>> keptStartMarkers;
+  nsTArray<UniquePtr<AbstractTimelineMarker>> keptStartMarkers;
 
   for (uint32_t i = 0; i < mTimelineMarkers.Length(); ++i) {
-    UniquePtr<TimelineMarker>& startPayload = mTimelineMarkers[i];
+    UniquePtr<AbstractTimelineMarker>& startPayload = mTimelineMarkers[i];
 
     // If this is a TIMESTAMP marker, there's no corresponding END,
     // as it's a single unit of time, not a duration.
     if (startPayload->GetTracingType() == MarkerTracingType::TIMESTAMP) {
       dom::ProfileTimelineMarker* marker = aStore.AppendElement();
       marker->mName = NS_ConvertUTF8toUTF16(startPayload->GetName());
       marker->mStart = startPayload->GetTime();
       marker->mEnd = startPayload->GetTime();
@@ -71,17 +88,17 @@ ObservedDocShell::PopMarkers(JSContext* 
       // for the matching end. It doesn't hurt to apply this logic to
       // all event types.
       uint32_t markerDepth = 0;
 
       // The assumption is that the devtools timeline flushes markers frequently
       // enough for the amount of markers to always be small enough that the
       // nested for loop isn't going to be a performance problem.
       for (uint32_t j = i + 1; j < mTimelineMarkers.Length(); ++j) {
-        UniquePtr<TimelineMarker>& endPayload = mTimelineMarkers[j];
+        UniquePtr<AbstractTimelineMarker>& endPayload = mTimelineMarkers[j];
         bool endIsLayerType = strcmp(endPayload->GetName(), "Layer") == 0;
 
         // Look for "Layer" markers to stream out "Paint" markers.
         if (startIsPaintType && endIsLayerType) {
           LayerTimelineMarker* layerPayload = static_cast<LayerTimelineMarker*>(endPayload.get());
           layerPayload->AddLayerRectangles(layerRectangles);
           hasSeenLayerType = true;
         }
--- a/docshell/base/timeline/ObservedDocShell.h
+++ b/docshell/base/timeline/ObservedDocShell.h
@@ -2,42 +2,46 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_ObservedDocShell_h_
 #define mozilla_ObservedDocShell_h_
 
+#include "OTMTMarkerReceiver.h"
 #include "nsTArray.h"
 #include "mozilla/nsRefPtr.h"
 
 class nsDocShell;
 
 namespace mozilla {
-class TimelineMarker;
+class AbstractTimelineMarker;
 
 namespace dom {
 struct ProfileTimelineMarker;
 }
 
 // # ObservedDocShell
 //
 // A wrapper around a docshell for which docshell-specific markers are
 // allowed to exist. See TimelineConsumers for register/unregister logic.
-class ObservedDocShell : public LinkedListElement<ObservedDocShell>
+class ObservedDocShell : public LinkedListElement<ObservedDocShell>,
+                         public OTMTMarkerReceiver
 {
 private:
   nsRefPtr<nsDocShell> mDocShell;
-  nsTArray<UniquePtr<TimelineMarker>> mTimelineMarkers;
+  nsTArray<UniquePtr<AbstractTimelineMarker>> mTimelineMarkers;
 
 public:
   explicit ObservedDocShell(nsDocShell* aDocShell);
   nsDocShell* operator*() const { return mDocShell.get(); }
 
-  void AddMarker(UniquePtr<TimelineMarker>&& aMarker);
+  void AddMarker(UniquePtr<AbstractTimelineMarker>&& aMarker);
+  void AddOTMTMarkerClone(UniquePtr<AbstractTimelineMarker>& aMarker) override;
+
   void ClearMarkers();
   void PopMarkers(JSContext* aCx, nsTArray<dom::ProfileTimelineMarker>& aStore);
 };
 
 } // namespace mozilla
 
 #endif /* mozilla_ObservedDocShell_h_ */
--- a/docshell/base/timeline/TimelineConsumers.cpp
+++ b/docshell/base/timeline/TimelineConsumers.cpp
@@ -5,58 +5,72 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/TimelineConsumers.h"
 
 namespace mozilla {
 
 unsigned long TimelineConsumers::sActiveConsumers = 0;
 LinkedList<ObservedDocShell>* TimelineConsumers::sObservedDocShells = nullptr;
+Mutex* TimelineConsumers::sLock = nullptr;
 
 LinkedList<ObservedDocShell>&
 TimelineConsumers::GetOrCreateObservedDocShellsList()
 {
   if (!sObservedDocShells) {
     sObservedDocShells = new LinkedList<ObservedDocShell>();
   }
   return *sObservedDocShells;
 }
 
+Mutex&
+TimelineConsumers::GetLock()
+{
+  if (!sLock) {
+    sLock = new Mutex("TimelineConsumersMutex");
+  }
+  return *sLock;
+}
+
 void
 TimelineConsumers::AddConsumer(nsDocShell* aDocShell)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   UniquePtr<ObservedDocShell>& observed = aDocShell->mObserved;
 
   MOZ_ASSERT(!observed);
   sActiveConsumers++;
   observed.reset(new ObservedDocShell(aDocShell));
   GetOrCreateObservedDocShellsList().insertFront(observed.get());
 }
 
 void
 TimelineConsumers::RemoveConsumer(nsDocShell* aDocShell)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   UniquePtr<ObservedDocShell>& observed = aDocShell->mObserved;
 
   MOZ_ASSERT(observed);
   sActiveConsumers--;
   observed.get()->ClearMarkers();
   observed.get()->remove();
   observed.reset(nullptr);
 }
 
 bool
 TimelineConsumers::IsEmpty()
 {
+  MOZ_ASSERT(NS_IsMainThread());
   return sActiveConsumers == 0;
 }
 
 bool
 TimelineConsumers::GetKnownDocShells(Vector<nsRefPtr<nsDocShell>>& aStore)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   const LinkedList<ObservedDocShell>& docShells = GetOrCreateObservedDocShellsList();
 
   for (const ObservedDocShell* rds = docShells.getFirst();
        rds != nullptr;
        rds = rds->getNext()) {
     if (!aStore.append(**rds)) {
       return false;
     }
@@ -65,84 +79,181 @@ TimelineConsumers::GetKnownDocShells(Vec
   return true;
 }
 
 void
 TimelineConsumers::AddMarkerForDocShell(nsDocShell* aDocShell,
                                         const char* aName,
                                         MarkerTracingType aTracingType)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   if (aDocShell->IsObserved()) {
     aDocShell->mObserved->AddMarker(Move(MakeUnique<TimelineMarker>(aName, aTracingType)));
   }
 }
 
 void
 TimelineConsumers::AddMarkerForDocShell(nsDocShell* aDocShell,
                                         const char* aName,
                                         const TimeStamp& aTime,
                                         MarkerTracingType aTracingType)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   if (aDocShell->IsObserved()) {
     aDocShell->mObserved->AddMarker(Move(MakeUnique<TimelineMarker>(aName, aTime, aTracingType)));
   }
 }
 
 void
 TimelineConsumers::AddMarkerForDocShell(nsDocShell* aDocShell,
-                                        UniquePtr<TimelineMarker>&& aMarker)
+                                        UniquePtr<AbstractTimelineMarker>&& aMarker)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   if (aDocShell->IsObserved()) {
     aDocShell->mObserved->AddMarker(Move(aMarker));
   }
 }
 
 void
+TimelineConsumers::AddOTMTMarkerForDocShell(nsDocShell* aDocShell,
+                                            UniquePtr<AbstractTimelineMarker>& aMarker)
+{
+  MOZ_ASSERT(!NS_IsMainThread());
+  GetLock().AssertCurrentThreadOwns();
+  if (aDocShell->IsObserved()) {
+    aDocShell->mObserved->AddOTMTMarkerClone(aMarker);
+  }
+}
+
+void
 TimelineConsumers::AddMarkerForDocShell(nsIDocShell* aDocShell,
                                         const char* aName,
                                         MarkerTracingType aTracingType)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   AddMarkerForDocShell(static_cast<nsDocShell*>(aDocShell), aName, aTracingType);
 }
 
 void
 TimelineConsumers::AddMarkerForDocShell(nsIDocShell* aDocShell,
                                         const char* aName,
                                         const TimeStamp& aTime,
                                         MarkerTracingType aTracingType)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   AddMarkerForDocShell(static_cast<nsDocShell*>(aDocShell), aName, aTime, aTracingType);
 }
 
 void
 TimelineConsumers::AddMarkerForDocShell(nsIDocShell* aDocShell,
-                                        UniquePtr<TimelineMarker>&& aMarker)
+                                        UniquePtr<AbstractTimelineMarker>&& aMarker)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   AddMarkerForDocShell(static_cast<nsDocShell*>(aDocShell), Move(aMarker));
 }
 
 void
+TimelineConsumers::AddOTMTMarkerForDocShell(nsIDocShell* aDocShell,
+                                            UniquePtr<AbstractTimelineMarker>& aMarker)
+{
+  MOZ_ASSERT(!NS_IsMainThread());
+  GetLock().AssertCurrentThreadOwns();
+  AddOTMTMarkerForDocShell(static_cast<nsDocShell*>(aDocShell), aMarker);
+}
+
+void
 TimelineConsumers::AddMarkerForDocShellsList(Vector<nsRefPtr<nsDocShell>>& aDocShells,
                                              const char* aName,
                                              MarkerTracingType aTracingType)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   for (Vector<nsRefPtr<nsDocShell>>::Range range = aDocShells.all();
        !range.empty();
        range.popFront()) {
     AddMarkerForDocShell(range.front(), aName, aTracingType);
   }
 }
 
 void
+TimelineConsumers::AddMarkerForDocShellsList(Vector<nsRefPtr<nsDocShell>>& aDocShells,
+                                             const char* aName,
+                                             const TimeStamp& aTime,
+                                             MarkerTracingType aTracingType)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  for (Vector<nsRefPtr<nsDocShell>>::Range range = aDocShells.all();
+       !range.empty();
+       range.popFront()) {
+    AddMarkerForDocShell(range.front(), aName, aTime, aTracingType);
+  }
+}
+
+void
+TimelineConsumers::AddMarkerForDocShellsList(Vector<nsRefPtr<nsDocShell>>& aDocShells,
+                                             UniquePtr<AbstractTimelineMarker>& aMarker)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  for (Vector<nsRefPtr<nsDocShell>>::Range range = aDocShells.all();
+       !range.empty();
+       range.popFront()) {
+    UniquePtr<AbstractTimelineMarker> cloned = aMarker->Clone();
+    AddMarkerForDocShell(range.front(), Move(cloned));
+  }
+}
+
+void
+TimelineConsumers::AddOTMTMarkerForDocShellsList(Vector<nsRefPtr<nsDocShell>>& aDocShells,
+                                                 UniquePtr<AbstractTimelineMarker>& aMarker)
+{
+  MOZ_ASSERT(!NS_IsMainThread());
+  GetLock().AssertCurrentThreadOwns();
+  for (Vector<nsRefPtr<nsDocShell>>::Range range = aDocShells.all();
+       !range.empty();
+       range.popFront()) {
+    AddOTMTMarkerForDocShell(range.front(), aMarker);
+  }
+}
+
+void
 TimelineConsumers::AddMarkerForAllObservedDocShells(const char* aName,
                                                     MarkerTracingType aTracingType)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   Vector<nsRefPtr<nsDocShell>> docShells;
-  if (!GetKnownDocShells(docShells)) {
-    // If we don't successfully populate our vector with *all* docshells being
-    // observed, don't add the marker to *any* of them.
-    return;
+  if (GetKnownDocShells(docShells)) {
+    AddMarkerForDocShellsList(docShells, aName, aTracingType);
+  }
+}
+
+void
+TimelineConsumers::AddMarkerForAllObservedDocShells(const char* aName,
+                                                    const TimeStamp& aTime,
+                                                    MarkerTracingType aTracingType)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  Vector<nsRefPtr<nsDocShell>> docShells;
+  if (GetKnownDocShells(docShells)) {
+    AddMarkerForDocShellsList(docShells, aName, aTime, aTracingType);
   }
+}
 
-  AddMarkerForDocShellsList(docShells, aName, aTracingType);
+void
+TimelineConsumers::AddMarkerForAllObservedDocShells(UniquePtr<AbstractTimelineMarker>& aMarker)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  Vector<nsRefPtr<nsDocShell>> docShells;
+  if (GetKnownDocShells(docShells)) {
+    AddMarkerForDocShellsList(docShells, aMarker);
+  }
+}
+
+void
+TimelineConsumers::AddOTMTMarkerForAllObservedDocShells(UniquePtr<AbstractTimelineMarker>& aMarker)
+{
+  MOZ_ASSERT(!NS_IsMainThread());
+  GetLock().AssertCurrentThreadOwns();
+  Vector<nsRefPtr<nsDocShell>> docShells;
+  if (GetKnownDocShells(docShells)) {
+    AddOTMTMarkerForDocShellsList(docShells, aMarker);
+  }
 }
 
 } // namespace mozilla
--- a/docshell/base/timeline/TimelineConsumers.h
+++ b/docshell/base/timeline/TimelineConsumers.h
@@ -6,35 +6,41 @@
 
 #ifndef mozilla_TimelineConsumers_h_
 #define mozilla_TimelineConsumers_h_
 
 #include "mozilla/UniquePtr.h"
 #include "mozilla/LinkedList.h"
 #include "mozilla/Vector.h"
 #include "mozilla/TimeStamp.h"
+#include "mozilla/Mutex.h"
 
 #include "TimelineMarkerEnums.h"
 
 class nsDocShell;
 class nsIDocShell;
 
 namespace mozilla {
 class ObservedDocShell;
-class TimelineMarker;
+class AbstractTimelineMarker;
 
 class TimelineConsumers
 {
 private:
   // Counter for how many timelines are currently interested in markers.
   static unsigned long sActiveConsumers;
   static LinkedList<ObservedDocShell>* sObservedDocShells;
   static LinkedList<ObservedDocShell>& GetOrCreateObservedDocShellsList();
 
+  // Lock used when adding off-the-main-thread markers.
+  static Mutex* sLock;
+
 public:
+  static Mutex& GetLock();
+
   static void AddConsumer(nsDocShell* aDocShell);
   static void RemoveConsumer(nsDocShell* aDocShell);
   static bool IsEmpty();
   static bool GetKnownDocShells(Vector<nsRefPtr<nsDocShell>>& aStore);
 
   // Methods for adding markers relevant for particular docshells, or generic
   // (meaning that they either can't be tied to a particular docshell, or one
   // wasn't accessible in the part of the codebase where they're instantiated).
@@ -60,26 +66,47 @@ public:
   static void AddMarkerForDocShell(nsIDocShell* aDocShell,
                                    const char* aName,
                                    const TimeStamp& aTime,
                                    MarkerTracingType aTracingType);
 
   // These methods register and receive ownership of an already created marker,
   // relevant for a specific docshell.
   static void AddMarkerForDocShell(nsDocShell* aDocShell,
-                                   UniquePtr<TimelineMarker>&& aMarker);
+                                   UniquePtr<AbstractTimelineMarker>&& aMarker);
   static void AddMarkerForDocShell(nsIDocShell* aDocShell,
-                                   UniquePtr<TimelineMarker>&& aMarker);
+                                   UniquePtr<AbstractTimelineMarker>&& aMarker);
 
-  // This method creates custom markers, relevant for a list of docshells.
+  // These methods create or clone markers relevant for a list of docshells.
   static void AddMarkerForDocShellsList(Vector<nsRefPtr<nsDocShell>>& aDocShells,
                                         const char* aName,
                                         MarkerTracingType aTracingType);
+  static void AddMarkerForDocShellsList(Vector<nsRefPtr<nsDocShell>>& aDocShells,
+                                        const char* aName,
+                                        const TimeStamp& aTime,
+                                        MarkerTracingType aTracingType);
+  static void AddMarkerForDocShellsList(Vector<nsRefPtr<nsDocShell>>& aDocShells,
+                                        UniquePtr<AbstractTimelineMarker>& aMarker);
 
-  // This method creates custom markers, none of which have to be tied to a
-  // particular docshell.
+  // These methods create or clone markers, none of which have to be tied to
+  // a particular docshell.
   static void AddMarkerForAllObservedDocShells(const char* aName,
                                                MarkerTracingType aTracingType);
+  static void AddMarkerForAllObservedDocShells(const char* aName,
+                                               const TimeStamp& aTime,
+                                               MarkerTracingType aTracingType);
+  static void AddMarkerForAllObservedDocShells(UniquePtr<AbstractTimelineMarker>& aMarker);
+
+  // Thread-safe versions of the above methods. Need to lock first using
+  // the mutex returned by `TimelineConsumers::GetLock()`.
+  static void AddOTMTMarkerForDocShell(nsDocShell* aDocShell,
+                                       UniquePtr<AbstractTimelineMarker>& aMarker);
+  static void AddOTMTMarkerForDocShell(nsIDocShell* aDocShell,
+                                       UniquePtr<AbstractTimelineMarker>& aMarker);
+  static void AddOTMTMarkerForDocShellsList(Vector<nsRefPtr<nsDocShell>>& aDocShells,
+                                            UniquePtr<AbstractTimelineMarker>& aMarker);
+  static void AddOTMTMarkerForAllObservedDocShells(UniquePtr<AbstractTimelineMarker>& aMarker);
+
 };
 
 } // namespace mozilla
 
 #endif /* mozilla_TimelineConsumers_h_ */
--- a/docshell/base/timeline/TimelineMarker.h
+++ b/docshell/base/timeline/TimelineMarker.h
@@ -2,17 +2,16 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_TimelineMarker_h_
 #define mozilla_TimelineMarker_h_
 
-#include "nsContentUtils.h"
 #include "AbstractTimelineMarker.h"
 
 namespace mozilla {
 
 // Objects of this type can be added to the timeline if there is an interested
 // consumer. The class can also be subclassed to let a given marker creator
 // provide custom details.
 class TimelineMarker : public AbstractTimelineMarker
@@ -24,18 +23,17 @@ public:
 
   TimelineMarker(const char* aName,
                  const TimeStamp& aTime,
                  MarkerTracingType aTracingType,
                  MarkerStackRequest aStackRequest = MarkerStackRequest::STACK);
 
   virtual bool Equals(const AbstractTimelineMarker& aOther) override;
   virtual void AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker) override;
-
-  JSObject* GetStack();
+  virtual JSObject* GetStack() override;
 
 protected:
   void CaptureStack();
 
 private:
   // While normally it is not a good idea to make a persistent root,
   // in this case changing nsDocShell to participate in cycle
   // collection was deemed too invasive, and the markers are only held
--- a/docshell/base/timeline/moz.build
+++ b/docshell/base/timeline/moz.build
@@ -8,16 +8,17 @@ EXPORTS.mozilla += [
     'AbstractTimelineMarker.h',
     'AutoGlobalTimelineMarker.h',
     'AutoTimelineMarker.h',
     'ConsoleTimelineMarker.h',
     'EventTimelineMarker.h',
     'JavascriptTimelineMarker.h',
     'LayerTimelineMarker.h',
     'ObservedDocShell.h',
+    'OTMTMarkerReceiver.h',
     'RestyleTimelineMarker.h',
     'TimelineConsumers.h',
     'TimelineMarker.h',
     'TimelineMarkerEnums.h',
     'TimestampTimelineMarker.h',
 ]
 
 UNIFIED_SOURCES += [
--- a/dom/base/Console.cpp
+++ b/dom/base/Console.cpp
@@ -1502,16 +1502,22 @@ Console::ProcessArguments(JSContext* aCx
           return false;
         }
 
         break;
       }
 
       case 'c':
       {
+        // If there isn't any output but there's already a style, then
+        // discard the previous style and use the next one instead.
+        if (output.IsEmpty() && !aStyles.IsEmpty()) {
+          aStyles.TruncateLength(aStyles.Length() - 1);
+        }
+
         if (!FlushOutput(aCx, aSequence, output)) {
           return false;
         }
 
         if (index < aData.Length()) {
           JS::Rooted<JS::Value> v(aCx, aData[index++]);
           JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, v));
           if (!jsString) {
--- a/dom/base/nsTreeSanitizer.cpp
+++ b/dom/base/nsTreeSanitizer.cpp
@@ -279,20 +279,16 @@ nsIAtom** const kURLAttributesHTML[] = {
   nullptr
 };
 
 nsIAtom** const kElementsSVG[] = {
   &nsGkAtoms::a, // a
   &nsGkAtoms::altGlyph, // altGlyph
   &nsGkAtoms::altGlyphDef, // altGlyphDef
   &nsGkAtoms::altGlyphItem, // altGlyphItem
-  &nsGkAtoms::animate, // animate
-  &nsGkAtoms::animateColor, // animateColor
-  &nsGkAtoms::animateMotion, // animateMotion
-  &nsGkAtoms::animateTransform, // animateTransform
   &nsGkAtoms::circle, // circle
   &nsGkAtoms::clipPath, // clipPath
   &nsGkAtoms::colorProfile, // color-profile
   &nsGkAtoms::cursor, // cursor
   &nsGkAtoms::defs, // defs
   &nsGkAtoms::desc, // desc
   &nsGkAtoms::ellipse, // ellipse
   &nsGkAtoms::elevation, // elevation
@@ -346,17 +342,16 @@ nsIAtom** const kElementsSVG[] = {
   &nsGkAtoms::missingGlyph, // missingGlyph
   &nsGkAtoms::mpath, // mpath
   &nsGkAtoms::path, // path
   &nsGkAtoms::pattern, // pattern
   &nsGkAtoms::polygon, // polygon
   &nsGkAtoms::polyline, // polyline
   &nsGkAtoms::radialGradient, // radialGradient
   &nsGkAtoms::rect, // rect
-  &nsGkAtoms::set, // set
   &nsGkAtoms::stop, // stop
   &nsGkAtoms::svg, // svg
   &nsGkAtoms::svgSwitch, // switch
   &nsGkAtoms::symbol, // symbol
   &nsGkAtoms::text, // text
   &nsGkAtoms::textPath, // textPath
   &nsGkAtoms::title, // title
   &nsGkAtoms::tref, // tref
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -2956,16 +2956,31 @@ TabChild::DidComposite(uint64_t aTransac
 
   ClientLayerManager *manager =
     static_cast<ClientLayerManager*>(mPuppetWidget->GetLayerManager());
 
   manager->DidComposite(aTransactionId, aCompositeStart, aCompositeEnd);
 }
 
 void
+TabChild::DidRequestComposite(const TimeStamp& aCompositeReqStart,
+                              const TimeStamp& aCompositeReqEnd)
+{
+  nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
+  if (!docShell) {
+    return;
+  }
+
+  TimelineConsumers::AddMarkerForDocShell(docShell.get(),
+    "CompositeForwardTransaction", aCompositeReqStart, MarkerTracingType::START);
+  TimelineConsumers::AddMarkerForDocShell(docShell.get(),
+    "CompositeForwardTransaction", aCompositeReqEnd, MarkerTracingType::END);
+}
+
+void
 TabChild::ClearCachedResources()
 {
   MOZ_ASSERT(mPuppetWidget);
   MOZ_ASSERT(mPuppetWidget->GetLayerManager());
   MOZ_ASSERT(mPuppetWidget->GetLayerManager()->GetBackendType() ==
                LayersBackend::LAYERS_CLIENT);
 
   ClientLayerManager *manager =
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -458,16 +458,18 @@ public:
     }
 
     static TabChild* GetFrom(nsIPresShell* aPresShell);
     static TabChild* GetFrom(uint64_t aLayersId);
 
     void DidComposite(uint64_t aTransactionId,
                       const TimeStamp& aCompositeStart,
                       const TimeStamp& aCompositeEnd);
+    void DidRequestComposite(const TimeStamp& aCompositeReqStart,
+                             const TimeStamp& aCompositeReqEnd);
 
     void ClearCachedResources();
 
     static inline TabChild*
     GetFrom(nsIDOMWindow* aWindow)
     {
       nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(aWindow);
       nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(webNav);
--- a/dom/presentation/provider/PresentationDeviceProviderModule.cpp
+++ b/dom/presentation/provider/PresentationDeviceProviderModule.cpp
@@ -23,18 +23,17 @@ static const mozilla::Module::CIDEntry k
 };
 
 static const mozilla::Module::ContractIDEntry kPresentationDeviceProviderContracts[] = {
   { MULTICAST_DNS_PROVIDER_CONTRACT_ID, &kMULTICAST_DNS_PROVIDER_CID },
   { nullptr }
 };
 
 static const mozilla::Module::CategoryEntry kPresentationDeviceProviderCategories[] = {
-#if (defined(MOZ_WIDGET_ANDROID) && ANDROID_VERSION >= 21) || \
-    (defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 16)
+#if defined(MOZ_WIDGET_ANDROID) || (defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 16)
   { PRESENTATION_DEVICE_PROVIDER_CATEGORY, "MulticastDNSDeviceProvider", MULTICAST_DNS_PROVIDER_CONTRACT_ID },
 #endif
   { nullptr }
 };
 
 static const mozilla::Module kPresentationDeviceProviderModule = {
   mozilla::Module::kVersion,
   kPresentationDeviceProviderCIDs,
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -566,16 +566,18 @@ ClientLayerManager::StopFrameTimeRecordi
   if (renderer) {
     renderer->SendStopFrameTimeRecording(aStartIndex, &aFrameIntervals);
   }
 }
 
 void
 ClientLayerManager::ForwardTransaction(bool aScheduleComposite)
 {
+  TimeStamp start = TimeStamp::Now();
+
   if (mForwarder->GetSyncObject()) {
     mForwarder->GetSyncObject()->FinalizeFrame();
   }
 
   mPhase = PHASE_FORWARD;
 
   mLatestTransactionId = mTransactionIdAllocator->GetTransactionId();
   TimeStamp transactionStart;
@@ -631,16 +633,22 @@ ClientLayerManager::ForwardTransaction(b
 
   mForwarder->RemoveTexturesIfNecessary();
   mForwarder->SendPendingAsyncMessges();
   mPhase = PHASE_NONE;
 
   // this may result in Layers being deleted, which results in
   // PLayer::Send__delete__() and DeallocShmem()
   mKeepAlive.Clear();
+
+  TabChild* window = mWidget->GetOwningTabChild();
+  if (window) {
+    TimeStamp end = TimeStamp::Now();
+    window->DidRequestComposite(start, end);
+  }
 }
 
 ShadowableLayer*
 ClientLayerManager::Hold(Layer* aLayer)
 {
   MOZ_ASSERT(HasShadowManager(),
              "top-level tree, no shadow tree to remote to");
 
--- a/mobile/android/base/mdns/MulticastDNSManager.java
+++ b/mobile/android/base/mdns/MulticastDNSManager.java
@@ -7,29 +7,32 @@ package org.mozilla.gecko.mdns;
 
 import org.mozilla.gecko.AppConstants.Versions;
 import org.mozilla.gecko.EventDispatcher;
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.util.EventCallback;
 import org.mozilla.gecko.util.GeckoRequest;
 import org.mozilla.gecko.util.NativeEventListener;
 import org.mozilla.gecko.util.NativeJSObject;
+import org.mozilla.gecko.util.ThreadUtils;
 
 import org.json.JSONException;
 import org.json.JSONObject;
 
 import android.annotation.TargetApi;
 import android.content.Context;
 import android.net.nsd.NsdManager;
 import android.net.nsd.NsdServiceInfo;
+import android.support.annotation.UiThread;
 import android.util.Log;
 
 import java.net.InetAddress;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * This class is the bridge between XPCOM mDNS module and NsdManager.
  *
  * @See nsIDNSServiceDiscovery.idl
  */
 public abstract class MulticastDNSManager {
     protected static final String LOGTAG = "GeckoMDNSManager";
@@ -46,95 +49,145 @@ public abstract class MulticastDNSManage
         }
         return instance;
     }
 
     public abstract void init();
     public abstract void tearDown();
 }
 
-class NsdMulticastDNSManager extends MulticastDNSManager implements NativeEventListener {
-    private final NsdManager nsdManager;
-    private DiscoveryListener mDiscoveryListener = null;
-    private RegistrationListener mRegistrationListener = null;
+/**
+ * Mix-in class for MulticastDNSManagers to call EventDispatcher.
+ */
+class MulticastDNSEventManager {
+    private NativeEventListener mListener = null;
+    private boolean mEventsRegistered = false;
 
-    @TargetApi(16)
-    public NsdMulticastDNSManager(final Context context) {
-        nsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
+    MulticastDNSEventManager(NativeEventListener listener) {
+        mListener = listener;
     }
 
-    @Override
+    @UiThread
     public void init() {
+        ThreadUtils.assertOnUiThread();
+
+        if (mEventsRegistered || mListener == null) {
+            return;
+        }
+
         registerEvents();
+        mEventsRegistered = true;
     }
 
-    @Override
+    @UiThread
     public void tearDown() {
+        ThreadUtils.assertOnUiThread();
+
+        if (!mEventsRegistered || mListener == null) {
+            return;
+        }
+
         unregisterEvents();
+        mEventsRegistered = false;
     }
 
     private void registerEvents() {
-        EventDispatcher.getInstance().registerGeckoThreadListener(this,
+        EventDispatcher.getInstance().registerGeckoThreadListener(mListener,
                 "NsdManager:DiscoverServices",
                 "NsdManager:StopServiceDiscovery",
                 "NsdManager:RegisterService",
                 "NsdManager:UnregisterService",
                 "NsdManager:ResolveService");
     }
 
     private void unregisterEvents() {
-        EventDispatcher.getInstance().unregisterGeckoThreadListener(this,
+        EventDispatcher.getInstance().unregisterGeckoThreadListener(mListener,
                 "NsdManager:DiscoverServices",
                 "NsdManager:StopServiceDiscovery",
                 "NsdManager:RegisterService",
                 "NsdManager:UnregisterService",
                 "NsdManager:ResolveService");
     }
+}
+
+class NsdMulticastDNSManager extends MulticastDNSManager implements NativeEventListener {
+    private final NsdManager nsdManager;
+    private final MulticastDNSEventManager mEventManager;
+    private Map<String, DiscoveryListener> mDiscoveryListeners = null;
+    private Map<String, RegistrationListener> mRegistrationListeners = null;
+
+    @TargetApi(16)
+    public NsdMulticastDNSManager(final Context context) {
+        nsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
+        mEventManager = new MulticastDNSEventManager(this);
+        mDiscoveryListeners = new ConcurrentHashMap<String, DiscoveryListener>();
+        mRegistrationListeners = new ConcurrentHashMap<String, RegistrationListener>();
+    }
+
+    @Override
+    public void init() {
+        mEventManager.init();
+    }
+
+    @Override
+    public void tearDown() {
+        mDiscoveryListeners.clear();
+        mRegistrationListeners.clear();
+
+        mEventManager.tearDown();
+    }
 
     @Override
     public void handleMessage(final String event, final NativeJSObject message, final EventCallback callback) {
         Log.v(LOGTAG, "handleMessage: " + event);
 
         switch (event) {
-            case "NsdManager:DiscoverServices":
-                if (mDiscoveryListener != null) {
-                    mDiscoveryListener.stopServiceDiscovery(null);
-                }
-                mDiscoveryListener = new DiscoveryListener(nsdManager);
-                mDiscoveryListener.discoverServices(message.getString("serviceType"), callback);
+            case "NsdManager:DiscoverServices": {
+                DiscoveryListener listener = new DiscoveryListener(nsdManager);
+                listener.discoverServices(message.getString("serviceType"), callback);
+                mDiscoveryListeners.put(message.getString("uniqueId"), listener);
                 break;
-            case "NsdManager:StopServiceDiscovery":
-                if (mDiscoveryListener != null) {
-                    mDiscoveryListener.stopServiceDiscovery(callback);
-                    mDiscoveryListener = null;
+            }
+            case "NsdManager:StopServiceDiscovery": {
+                String uuid = message.getString("uniqueId");
+                DiscoveryListener listener = mDiscoveryListeners.remove(uuid);
+                if (listener == null) {
+                    Log.e(LOGTAG, "DiscoveryListener " + uuid + " was not found.");
+                    return;
                 }
+                listener.stopServiceDiscovery(callback);
                 break;
-            case "NsdManager:RegisterService":
-                if (mRegistrationListener != null) {
-                    mRegistrationListener.unregisterService(null);
-                }
-                mRegistrationListener = new RegistrationListener(nsdManager);
-                mRegistrationListener.registerService(message.getInt("port"),
+            }
+            case "NsdManager:RegisterService": {
+                RegistrationListener listener = new RegistrationListener(nsdManager);
+                listener.registerService(message.getInt("port"),
                         message.optString("serviceName", android.os.Build.MODEL),
                         message.getString("serviceType"),
                         parseAttributes(message.optObjectArray("attributes", null)),
                         callback);
+                mRegistrationListeners.put(message.getString("uniqueId"), listener);
                 break;
-            case "NsdManager:UnregisterService":
-                if (mRegistrationListener != null) {
-                    mRegistrationListener.unregisterService(callback);
-                    mRegistrationListener = null;
+            }
+            case "NsdManager:UnregisterService": {
+                String uuid = message.getString("uniqueId");
+                RegistrationListener listener = mRegistrationListeners.remove(uuid);
+                if (listener == null) {
+                    Log.e(LOGTAG, "RegistrationListener " + uuid + " was not found.");
+                    return;
                 }
+                listener.unregisterService(callback);
                 break;
-            case "NsdManager:ResolveService":
+            }
+            case "NsdManager:ResolveService": {
                 (new ResolveListener(nsdManager)).resolveService(message.getString("serviceName"),
                         message.getString("serviceType"),
                         callback);
                 break;
-        };
+            }
+        }
     }
 
     private Map<String, String> parseAttributes(final NativeJSObject[] jsobjs) {
         if (jsobjs == null || jsobjs.length == 0 || !Versions.feature21Plus) {
             return null;
         }
 
         Map<String, String> attributes = new HashMap<String, String>(jsobjs.length);
@@ -168,26 +221,38 @@ class NsdMulticastDNSManager extends Mul
         if (serviceType != null) {
             obj.put("serviceType", serviceType);
         }
 
         return obj;
     }
 }
 
-class DummyMulticastDNSManager extends MulticastDNSManager {
+class DummyMulticastDNSManager extends MulticastDNSManager implements NativeEventListener {
+    static final int FAILURE_UNSUPPORTED = -65544;
+    private final MulticastDNSEventManager mEventManager;
+
     public DummyMulticastDNSManager() {
+        mEventManager = new MulticastDNSEventManager(this);
     }
 
     @Override
     public void init() {
+        mEventManager.init();
     }
 
     @Override
     public void tearDown() {
+        mEventManager.tearDown();
+    }
+
+    @Override
+    public void handleMessage(final String event, final NativeJSObject message, final EventCallback callback) {
+        Log.v(LOGTAG, "handleMessage: " + event);
+        callback.sendError(FAILURE_UNSUPPORTED);
     }
 }
 
 @TargetApi(16)
 class DiscoveryListener implements NsdManager.DiscoveryListener {
     private static final String LOGTAG = "GeckoMDNSManager";
     private final NsdManager nsdManager;
 
@@ -196,95 +261,109 @@ class DiscoveryListener implements NsdMa
     private EventCallback mStopCallback = null;
 
     DiscoveryListener(final NsdManager nsdManager) {
         this.nsdManager = nsdManager;
     }
 
     public void discoverServices(final String serviceType, final EventCallback callback) {
         synchronized (this) {
-            if (mStartCallback != null) {
-                throw new RuntimeException("Previous operation is not finished");
-            }
             mStartCallback = callback;
         }
         nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD, this);
     }
 
     public void stopServiceDiscovery(final EventCallback callback) {
         synchronized (this) {
-            if (mStopCallback != null) {
-                throw new RuntimeException("Previous operation is not finished");
-            }
             mStopCallback = callback;
         }
         nsdManager.stopServiceDiscovery(this);
     }
 
     @Override
     public synchronized void onDiscoveryStarted(final String serviceType) {
         Log.d(LOGTAG, "onDiscoveryStarted: " + serviceType);
-        if (mStartCallback == null) {
+
+        EventCallback callback;
+        synchronized (this) {
+            callback = mStartCallback;
+        }
+
+        if (callback == null) {
             return;
         }
-        mStartCallback.sendSuccess(serviceType);
-        mStartCallback = null;
+
+        callback.sendSuccess(serviceType);
     }
 
     @Override
     public synchronized void onStartDiscoveryFailed(final String serviceType, final int errorCode) {
         Log.e(LOGTAG, "onStartDiscoveryFailed: " + serviceType + "(" + errorCode + ")");
-        if (mStartCallback == null) {
-            return;
+
+        EventCallback callback;
+        synchronized (this) {
+            callback = mStartCallback;
         }
-        mStartCallback.sendError(errorCode);
-        mStartCallback = null;
+
+        callback.sendError(errorCode);
     }
 
     @Override
     public synchronized void onDiscoveryStopped(final String serviceType) {
         Log.d(LOGTAG, "onDiscoveryStopped: " + serviceType);
-        if (mStopCallback == null) {
+
+        EventCallback callback;
+        synchronized (this) {
+            callback = mStopCallback;
+        }
+
+        if (callback == null) {
             return;
         }
-        mStopCallback.sendSuccess(serviceType);
-        mStopCallback = null;
+
+        callback.sendSuccess(serviceType);
     }
 
     @Override
     public synchronized void onStopDiscoveryFailed(final String serviceType, final int errorCode) {
         Log.e(LOGTAG, "onStopDiscoveryFailed: " + serviceType + "(" + errorCode + ")");
-        if (mStopCallback == null) {
+
+        EventCallback callback;
+        synchronized (this) {
+            callback = mStopCallback;
+        }
+
+        if (callback == null) {
             return;
         }
-        mStopCallback.sendError(errorCode);
-        mStopCallback = null;
+
+        callback.sendError(errorCode);
     }
 
     @Override
     public void onServiceFound(final NsdServiceInfo serviceInfo) {
         Log.d(LOGTAG, "onServiceFound: " + serviceInfo.getServiceName());
-        JSONObject json = null;
+        JSONObject json;
         try {
             json = NsdMulticastDNSManager.toJSON(serviceInfo);
         } catch (JSONException e) {
             throw new RuntimeException(e);
         }
         GeckoAppShell.sendRequestToGecko(new GeckoRequest("NsdManager:ServiceFound", json) {
             @Override
             public void onResponse(NativeJSObject nativeJSObject) {
                 // don't care return value.
             }
         });
     }
 
     @Override
     public void onServiceLost(final NsdServiceInfo serviceInfo) {
         Log.d(LOGTAG, "onServiceLost: " + serviceInfo.getServiceName());
-        JSONObject json = null;
+        JSONObject json;
         try {
             json = NsdMulticastDNSManager.toJSON(serviceInfo);
         } catch (JSONException e) {
             throw new RuntimeException(e);
         }
         GeckoAppShell.sendRequestToGecko(new GeckoRequest("NsdManager:ServiceLost", json) {
             @Override
             public void onResponse(NativeJSObject nativeJSObject) {
@@ -304,28 +383,26 @@ class RegistrationListener implements Ns
     private EventCallback mStopCallback = null;
 
     RegistrationListener(final NsdManager nsdManager) {
         this.nsdManager = nsdManager;
     }
 
     public void registerService(final int port, final String serviceName, final String serviceType, final Map<String, String> attributes, final EventCallback callback) {
         Log.d(LOGTAG, "registerService: " + serviceName + "." + serviceType + ":" + port);
-        synchronized (this) {
-            if (mStartCallback != null) {
-                throw new RuntimeException("Previous operation is not finished");
-            }
-            mStartCallback = callback;
-        }
 
         NsdServiceInfo serviceInfo = new NsdServiceInfo();
         serviceInfo.setPort(port);
         serviceInfo.setServiceName(serviceName);
         serviceInfo.setServiceType(serviceType);
         setAttributes(serviceInfo, attributes);
+
+        synchronized (this) {
+            mStartCallback = callback;
+        }
         nsdManager.registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, this);
     }
 
     @TargetApi(21)
     private void setAttributes(final NsdServiceInfo serviceInfo, final Map<String, String> attributes) {
         if (attributes == null || !Versions.feature21Plus) {
             return;
         }
@@ -333,120 +410,130 @@ class RegistrationListener implements Ns
         for (Map.Entry<String, String> entry : attributes.entrySet()) {
             serviceInfo.setAttribute(entry.getKey(), entry.getValue());
         }
     }
 
     public void unregisterService(final EventCallback callback) {
         Log.d(LOGTAG, "unregisterService");
         synchronized (this) {
-            if (mStopCallback != null) {
-                throw new RuntimeException("Previous operation is not finished");
-            }
             mStopCallback = callback;
         }
+
         nsdManager.unregisterService(this);
     }
 
     @Override
     public synchronized void onServiceRegistered(final NsdServiceInfo serviceInfo) {
         Log.d(LOGTAG, "onServiceRegistered: " + serviceInfo.getServiceName());
 
-        if (mStartCallback == null) {
+        EventCallback callback;
+        synchronized (this) {
+            callback = mStartCallback;
+        }
+
+        if (callback == null) {
             return;
         }
 
         try {
-            mStartCallback.sendSuccess(NsdMulticastDNSManager.toJSON(serviceInfo));
+            callback.sendSuccess(NsdMulticastDNSManager.toJSON(serviceInfo));
         } catch (JSONException e) {
             throw new RuntimeException(e);
         }
-        mStartCallback = null;
     }
 
     @Override
     public synchronized void onRegistrationFailed(final NsdServiceInfo serviceInfo, final int errorCode) {
         Log.e(LOGTAG, "onRegistrationFailed: " + serviceInfo.getServiceName() + "(" + errorCode + ")");
-        if (mStartCallback == null) {
-            return;
+
+        EventCallback callback;
+        synchronized (this) {
+            callback = mStartCallback;
         }
-        mStartCallback.sendError(errorCode);
-        mStartCallback = null;
+
+        callback.sendError(errorCode);
     }
 
     @Override
     public synchronized void onServiceUnregistered(final NsdServiceInfo serviceInfo) {
         Log.d(LOGTAG, "onServiceUnregistered: " + serviceInfo.getServiceName());
-        if (mStopCallback == null) {
+
+        EventCallback callback;
+        synchronized (this) {
+            callback = mStopCallback;
+        }
+
+        if (callback == null) {
             return;
         }
+
         try {
-            mStopCallback.sendSuccess(NsdMulticastDNSManager.toJSON(serviceInfo));
+            callback.sendSuccess(NsdMulticastDNSManager.toJSON(serviceInfo));
         } catch (JSONException e) {
             throw new RuntimeException(e);
-
         }
-        mStopCallback = null;
     }
 
     @Override
     public synchronized void onUnregistrationFailed(final NsdServiceInfo serviceInfo, final int errorCode) {
         Log.e(LOGTAG, "onUnregistrationFailed: " + serviceInfo.getServiceName() + "(" + errorCode + ")");
-        if (mStopCallback == null) {
+
+        EventCallback callback;
+        synchronized (this) {
+            callback = mStopCallback;
+        }
+
+        if (callback == null) {
             return;
         }
-        mStopCallback.sendError(errorCode);
-        mStopCallback = null;
+
+        callback.sendError(errorCode);
     }
 }
 
 @TargetApi(16)
 class ResolveListener implements NsdManager.ResolveListener {
     private static final String LOGTAG = "GeckoMDNSManager";
     private final NsdManager nsdManager;
 
     // Callback is called from different thread, and the callback can be called only once.
     private EventCallback mCallback = null;
 
     public ResolveListener(final NsdManager nsdManager) {
         this.nsdManager = nsdManager;
     }
 
     public void resolveService(final String serviceName, final String serviceType, final EventCallback callback) {
-        synchronized (this) {
-            if (mCallback != null) {
-                throw new RuntimeException("Previous operation is not finished");
-            }
-            mCallback = callback;
-        }
-
         NsdServiceInfo serviceInfo = new NsdServiceInfo();
         serviceInfo.setServiceName(serviceName);
         serviceInfo.setServiceType(serviceType);
+
+        mCallback = callback;
         nsdManager.resolveService(serviceInfo, this);
     }
 
 
     @Override
     public synchronized void onResolveFailed(final NsdServiceInfo serviceInfo, final int errorCode) {
         Log.e(LOGTAG, "onResolveFailed: " + serviceInfo.getServiceName() + "(" + errorCode + ")");
+
         if (mCallback == null) {
             return;
         }
         mCallback.sendError(errorCode);
-        mCallback = null;
     }
 
     @Override
     public synchronized void onServiceResolved(final NsdServiceInfo serviceInfo) {
         Log.d(LOGTAG, "onServiceResolved: " + serviceInfo.getServiceName());
+
         if (mCallback == null) {
             return;
         }
 
         try {
             mCallback.sendSuccess(NsdMulticastDNSManager.toJSON(serviceInfo));
         } catch (JSONException e) {
             throw new RuntimeException(e);
         }
-        mCallback = null;
     }
 }
--- a/mobile/android/components/HelperAppDialog.js
+++ b/mobile/android/components/HelperAppDialog.js
@@ -58,17 +58,18 @@ HelperAppLauncherDialog.prototype = {
         url.schemeIs("ftp")) {
       return true;
     }
 
     // The less-common opposite case.
     if (url.schemeIs("chrome") ||
         url.schemeIs("jar") ||
         url.schemeIs("resource") ||
-        url.schemeIs("wyciwyg")) {
+        url.schemeIs("wyciwyg") ||
+        url.schemeIs("file")) {
       return false;
     }
 
     // For all other URIs, try to resolve them to an inner URI, and check that.
     if (!alreadyResolved) {
       let ioSvc = Cc["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
       let innerURI = ioSvc.newChannelFromURI2(url,
                                               null,      // aLoadingNode
@@ -76,41 +77,16 @@ HelperAppLauncherDialog.prototype = {
                                               null,      // aTriggeringPrincipal
                                               Ci.nsILoadInfo.SEC_NORMAL,
                                               Ci.nsIContentPolicy.TYPE_OTHER).URI;
       if (!url.equals(innerURI)) {
         return this._canDownload(innerURI, true);
       }
     }
 
-    if (url.schemeIs("file")) {
-      // If it's in our app directory or profile directory, we never ever
-      // want to do anything with it, including saving to disk or passing the
-      // file to another application.
-      let file = url.QueryInterface(Ci.nsIFileURL).file;
-
-      // Normalize the nsILocalFile in-place. This will ensure that paths
-      // can be correctly compared via `contains`, below.
-      file.normalize();
-
-      // TODO: pref blacklist?
-
-      let appRoot = FileUtils.getFile("XREExeF", []);
-      if (appRoot.contains(file, true)) {
-        return false;
-      }
-
-      let profileRoot = FileUtils.getFile("ProfD", []);
-      if (profileRoot.contains(file, true)) {
-        return false;
-      }
-
-      return true;
-    }
-
     // Anything else is fine to download.
     return true;
   },
 
   /**
    * Returns true if `launcher` represents a download for which we wish
    * to prompt.
    */
--- a/mobile/android/modules/MulticastDNS.jsm
+++ b/mobile/android/modules/MulticastDNS.jsm
@@ -8,31 +8,34 @@
 this.EXPORTED_SYMBOLS = ["MulticastDNS"];
 
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
 Cu.import("resource://gre/modules/Messaging.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 let log = Cu.import("resource://gre/modules/AndroidLog.jsm", {}).AndroidLog.d.bind(null, "MulticastDNS");
 
+const FAILURE_INTERNAL_ERROR = -65537;
+
 // Helper function for sending commands to Java.
 function send(type, data, callback) {
   let msg = {
     type: type
   };
 
   for (let i in data) {
     try {
       msg[i] = data[i];
     } catch (e) {
     }
   }
 
   Messaging.sendRequestForResult(msg)
-    .then(result => callback(result, null), err => callback(null, err));
+    .then(result => callback(result, null),
+          err => callback(null, typeof err === "number" ? err : FAILURE_INTERNAL_ERROR));
 }
 
 // Receives service found/lost event from NsdManager
 function ServiceManager() {
 }
 
 ServiceManager.prototype = {
   listeners: {},
@@ -75,16 +78,17 @@ ServiceManager.prototype = {
     log("removeListener: " + aServiceType + ", " + aListener);
 
     if (!this.listeners[aServiceType]) {
       log("listener doesn't exist");
       return;
     }
     let index = this.listeners[aServiceType].indexOf(aListener);
     if (index < 0) {
+      log("listener doesn't exist");
       return;
     }
 
     this.listeners[aServiceType].splice(index, 1);
     --this.numListeners;
 
     if (this.numListeners === 0) {
       this.unregisterEvent();
@@ -141,44 +145,54 @@ function parsePropertyBag2(bag) {
 function MulticastDNS() {
   this.serviceManager = new ServiceManager();
 }
 
 MulticastDNS.prototype = {
   startDiscovery: function(aServiceType, aListener) {
     this.serviceManager.addListener(aServiceType, aListener);
 
-    send("NsdManager:DiscoverServices", { serviceType: aServiceType }, (result, err) => {
+    let serviceInfo = {
+      serviceType: aServiceType,
+      uniqueId: aListener.uuid
+    };
+
+    send("NsdManager:DiscoverServices", serviceInfo, (result, err) => {
       if (err) {
         log("onStartDiscoveryFailed: " + aServiceType + " (" + err + ")");
-        this.unregisterEvent();
+        this.serviceManager.removeListener(aServiceType, aListener);
         aListener.onStartDiscoveryFailed(aServiceType, err);
       } else {
         aListener.onDiscoveryStarted(result);
       }
     });
   },
 
   stopDiscovery: function(aServiceType, aListener) {
     this.serviceManager.removeListener(aServiceType, aListener);
 
-    send("NsdManager:StopServiceDiscovery", {}, (result, err) => {
+    let serviceInfo = {
+      uniqueId: aListener.uuid
+    };
+
+    send("NsdManager:StopServiceDiscovery", serviceInfo, (result, err) => {
       if (err) {
         log("onStopDiscoveryFailed: " + aServiceType + " (" + err + ")");
         aListener.onStopDiscoveryFailed(aServiceType, err);
       } else {
         aListener.onDiscoveryStopped(aServiceType);
       }
     });
   },
 
   registerService: function(aServiceInfo, aListener) {
     let serviceInfo = {
       port: aServiceInfo.port,
       serviceType: aServiceInfo.serviceType,
+      uniqueId: aListener.uuid
     };
 
     try {
       serviceInfo.host = aServiceInfo.host;
     } catch(e) {
       // host unspecified
     }
     try {
@@ -198,17 +212,21 @@ MulticastDNS.prototype = {
         aListener.onRegistrationFailed(aServiceInfo, err);
       } else {
         aListener.onServiceRegistered(result);
       }
     });
   },
 
   unregisterService: function(aServiceInfo, aListener) {
-    send("NsdManager:UnregisterService", {}, (result, err) => {
+    let serviceInfo = {
+      uniqueId: aListener.uuid
+    };
+
+    send("NsdManager:UnregisterService", serviceInfo, (result, err) => {
       if (err) {
         log("onUnregistrationFailed: (" + err + ")");
         aListener.onUnregistrationFailed(aServiceInfo, err);
       } else {
         aListener.onServiceUnregistered(aServiceInfo);
       }
     });
   },
--- a/netwerk/dns/mdns/libmdns/moz.build
+++ b/netwerk/dns/mdns/libmdns/moz.build
@@ -1,15 +1,15 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android' and CONFIG['ANDROID_VERSION'] >= '21':
+if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
     EXTRA_COMPONENTS += [
         'nsDNSServiceDiscovery.js',
         'nsDNSServiceDiscovery.manifest',
     ]
 
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and CONFIG['ANDROID_VERSION'] >= '16':
     UNIFIED_SOURCES += [
         'MDNSResponderOperator.cpp',
--- a/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.js
+++ b/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.js
@@ -11,19 +11,34 @@ Cu.import("resource://gre/modules/XPCOMU
 const DNSSERVICEDISCOVERY_CID = Components.ID("{f9346d98-f27a-4e89-b744-493843416480}");
 const DNSSERVICEDISCOVERY_CONTRACT_ID = "@mozilla.org/toolkit/components/mdnsresponder/dns-sd;1";
 const DNSSERVICEINFO_CONTRACT_ID = "@mozilla.org/toolkit/components/mdnsresponder/dns-info;1";
 
 function log(aMsg) {
   dump("-*- nsDNSServiceDiscovery.js : " + aMsg + "\n");
 }
 
+function generateUuid() {
+  var uuidGenerator = Components.classes["@mozilla.org/uuid-generator;1"].
+    getService(Ci.nsIUUIDGenerator);
+  return uuidGenerator.generateUUID().toString();
+}
+
 // Helper class to transform return objects to correct type.
-function ListenerWrapper(aListener) {
+function ListenerWrapper(aListener, aMdns) {
   this.listener = aListener;
+  this.mdns = aMdns;
+
+  this.discoveryStarting = false;
+  this.stopDiscovery = false;
+
+  this.registrationStarting = false;
+  this.stopRegistration = false;
+
+  this.uuid = generateUuid();
 }
 
 ListenerWrapper.prototype = {
   // Helper function for transforming an Object into nsIDNSServiceInfo.
   makeServiceInfo: function (aServiceInfo) {
     let serviceInfo = Cc[DNSSERVICEINFO_CONTRACT_ID].createInstance(Ci.nsIDNSServiceInfo);
 
     for (let name of ['host', 'port', 'serviceName', 'serviceType']) {
@@ -34,88 +49,117 @@ ListenerWrapper.prototype = {
       }
     }
 
     return serviceInfo;
   },
 
   /* transparent types */
   onDiscoveryStarted: function(aServiceType) {
+    this.discoveryStarting = false;
     this.listener.onDiscoveryStarted(aServiceType);
+
+    if (this.stopDiscovery) {
+      this.mdns.stopDiscovery(aServiceType, this);
+    }
   },
   onDiscoveryStopped: function(aServiceType) {
     this.listener.onDiscoveryStopped(aServiceType);
   },
   onStartDiscoveryFailed: function(aServiceType, aErrorCode) {
-    this.listener.onStartDiscoveryFailed(aServiceType);
+    log('onStartDiscoveryFailed: ' + aServiceType + ' (' + aErrorCode + ')');
+    this.discoveryStarting = false;
+    this.stopDiscovery = true;
+    this.listener.onStartDiscoveryFailed(aServiceType, aErrorCode);
   },
   onStopDiscoveryFailed: function(aServiceType, aErrorCode) {
-    this.listener.onStopDiscoveryFailed(aServiceType);
+    log('onStopDiscoveryFailed: ' + aServiceType + ' (' + aErrorCode + ')');
+    this.listener.onStopDiscoveryFailed(aServiceType, aErrorCode);
   },
 
   /* transform types */
   onServiceFound: function(aServiceInfo) {
     this.listener.onServiceFound(this.makeServiceInfo(aServiceInfo));
   },
   onServiceLost: function(aServiceInfo) {
     this.listener.onServiceLost(this.makeServiceInfo(aServiceInfo));
   },
   onServiceRegistered: function(aServiceInfo) {
+    this.registrationStarting = false;
     this.listener.onServiceRegistered(this.makeServiceInfo(aServiceInfo));
+
+    if (this.stopRegistration) {
+      this.mdns.unregisterService(aServiceInfo, this);
+    }
   },
   onServiceUnregistered: function(aServiceInfo) {
     this.listener.onServiceUnregistered(this.makeServiceInfo(aServiceInfo));
   },
   onServiceResolved: function(aServiceInfo) {
     this.listener.onServiceResolved(this.makeServiceInfo(aServiceInfo));
   },
 
   onRegistrationFailed: function(aServiceInfo, aErrorCode) {
+    log('onRegistrationFailed: (' + aErrorCode + ')');
+    this.registrationStarting = false;
+    this.stopRegistration = true;
     this.listener.onRegistrationFailed(this.makeServiceInfo(aServiceInfo), aErrorCode);
   },
   onUnregistrationFailed: function(aServiceInfo, aErrorCode) {
+    log('onUnregistrationFailed: (' + aErrorCode + ')');
     this.listener.onUnregistrationFailed(this.makeServiceInfo(aServiceInfo), aErrorCode);
   },
   onResolveFailed: function(aServiceInfo, aErrorCode) {
+    log('onResolveFailed: (' + aErrorCode + ')');
     this.listener.onResolveFailed(this.makeServiceInfo(aServiceInfo), aErrorCode);
   }
 };
 
 function nsDNSServiceDiscovery() {
   log("nsDNSServiceDiscovery");
   this.mdns = new MulticastDNS();
 }
 
 nsDNSServiceDiscovery.prototype = {
   classID: DNSSERVICEDISCOVERY_CID,
   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference, Ci.nsIDNSServiceDiscovery]),
 
   startDiscovery: function(aServiceType, aListener) {
     log("startDiscovery");
-    let listener = new ListenerWrapper(aListener);
+    let listener = new ListenerWrapper(aListener, this.mdns);
+    listener.discoveryStarting = true;
     this.mdns.startDiscovery(aServiceType, listener);
 
     return {
       QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
       cancel: (function() {
-        this.mdns.stopDiscovery(aServiceType, listener);
-      }).bind(this)
+        if (this.discoveryStarting || this.stopDiscovery) {
+          this.stopDiscovery = true;
+          return;
+        }
+        this.mdns.stopDiscovery(aServiceType, this);
+      }).bind(listener)
     };
   },
 
   registerService: function(aServiceInfo, aListener) {
     log("registerService");
-    let listener = new ListenerWrapper(aListener);
+    let listener = new ListenerWrapper(aListener, this.mdns);
+    listener.registrationStarting = true;
     this.mdns.registerService(aServiceInfo, listener);
 
     return {
       QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
       cancel: (function() {
-        this.mdns.unregisterService(aServiceInfo, listener);
-      }).bind(this)
+        if (this.registrationStarting || this.stopRegistration) {
+          this.stopRegistration = true;
+          return;
+        }
+        this.mdns.unregisterService(aServiceInfo, this);
+      }).bind(listener)
     };
   },
 
   resolveService: function(aServiceInfo, aListener) {
     log("resolveService");
     this.mdns.resolveService(aServiceInfo, new ListenerWrapper(aListener));
   }
 };
--- a/security/manager/ssl/StaticHPKPins.h
+++ b/security/manager/ssl/StaticHPKPins.h
@@ -771,16 +771,17 @@ static const TransportSecurityPreload kP
   { "doubleclick.net", true, false, false, -1, &kPinset_google_root_pems },
   { "drive.google.com", true, false, false, -1, &kPinset_google_root_pems },
   { "dropbox.com", false, false, false, -1, &kPinset_dropbox },
   { "dropboxstatic.com", false, true, false, -1, &kPinset_dropbox },
   { "dropboxusercontent.com", false, true, false, -1, &kPinset_dropbox },
   { "encrypted.google.com", true, false, false, -1, &kPinset_google_root_pems },
   { "exclude-subdomains.pinning.example.com", false, false, false, 0, &kPinset_mozilla_test },
   { "facebook.com", false, false, false, -1, &kPinset_facebook },
+  { "fi.google.com", true, false, false, -1, &kPinset_google_root_pems },
   { "g.co", true, false, false, -1, &kPinset_google_root_pems },
   { "ggpht.com", true, false, false, -1, &kPinset_google_root_pems },
   { "glass.google.com", true, false, false, -1, &kPinset_google_root_pems },
   { "gmail.com", false, false, false, -1, &kPinset_google_root_pems },
   { "goo.gl", true, false, false, -1, &kPinset_google_root_pems },
   { "google", true, false, false, -1, &kPinset_google_root_pems },
   { "google-analytics.com", true, false, false, -1, &kPinset_google_root_pems },
   { "google.ac", true, false, false, -1, &kPinset_google_root_pems },
@@ -1079,19 +1080,20 @@ static const TransportSecurityPreload kP
   { "withyoutube.com", true, false, false, -1, &kPinset_google_root_pems },
   { "www.dropbox.com", true, false, false, -1, &kPinset_dropbox },
   { "www.facebook.com", true, false, false, -1, &kPinset_facebook },
   { "www.gmail.com", false, false, false, -1, &kPinset_google_root_pems },
   { "www.googlemail.com", false, false, false, -1, &kPinset_google_root_pems },
   { "www.torproject.org", true, false, false, -1, &kPinset_tor },
   { "www.twitter.com", true, false, false, -1, &kPinset_twitterCom },
   { "xbrlsuccess.appspot.com", true, false, false, -1, &kPinset_google_root_pems },
+  { "xn--7xa.google.com", true, false, false, -1, &kPinset_google_root_pems },
   { "youtu.be", true, false, false, -1, &kPinset_google_root_pems },
   { "youtube-nocookie.com", true, false, false, -1, &kPinset_google_root_pems },
   { "youtube.com", true, false, false, -1, &kPinset_google_root_pems },
   { "ytimg.com", true, false, false, -1, &kPinset_google_root_pems },
 };
 
-// Pinning Preload List Length = 361;
+// Pinning Preload List Length = 363;
 
 static const int32_t kUnknownId = -1;
 
-static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1449916304292000);
+static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1450521025692000);
--- a/security/manager/ssl/nsSTSPreloadList.errors
+++ b/security/manager/ssl/nsSTSPreloadList.errors
@@ -6,38 +6,35 @@ admin.google.com: did not receive HSTS h
 adsfund.org: could not connect to host
 aes256.ru: could not connect to host
 afp548.tk: could not connect to host
 agrimap.com: did not receive HSTS header
 agrios.de: did not receive HSTS header
 airbnb.com: did not receive HSTS header
 aircomms.com: did not receive HSTS header
 aiticon.de: did not receive HSTS header
-akclinics.org: did not receive HSTS header
 akselimedia.fi: did not receive HSTS header
 al-shami.net: did not receive HSTS header
 alecvannoten.be: did not receive HSTS header
 allinonecyprus.com: did not receive HSTS header
 alpha.irccloud.com: could not connect to host
 alphabit-secure.com: could not connect to host
 altmv.com: max-age too low: 7776000
-amigogeek.net: could not connect to host
-animesharp.com: could not connect to host
-animurecs.com: could not connect to host
+amigogeek.net: did not receive HSTS header
+andreasbreitenlohner.de: could not connect to host
 ankakaak.com: could not connect to host
 annahmeschluss.de: could not connect to host
 api.mega.co.nz: could not connect to host
 api.recurly.com: did not receive HSTS header
 apis.google.com: did not receive HSTS header (error ignored - included regardless)
 apn-einstellungen.de: could not connect to host
 app.manilla.com: could not connect to host
 appengine.google.com: did not receive HSTS header (error ignored - included regardless)
 appseccalifornia.org: did not receive HSTS header
-armory.supplies: could not connect to host
-arrayify.com: did not receive HSTS header
+arrayify.com: could not connect to host
 astaxi.net: did not receive HSTS header
 at.search.yahoo.com: did not receive HSTS header
 atavio.at: could not connect to host
 atavio.ch: could not connect to host
 atavio.de: did not receive HSTS header
 au.search.yahoo.com: did not receive HSTS header
 aurainfosec.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 134"  data: no]
 auraredeye.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 134"  data: no]
@@ -51,17 +48,16 @@ azabani.com: did not receive HSTS header
 azprep.us: could not connect to host
 balcan-underground.net: could not connect to host
 baldwinkoo.com: could not connect to host
 ball.holdings: did not receive HSTS header
 barcodeberlin.com: did not receive HSTS header
 bassh.net: could not connect to host
 bccx.com: could not connect to host
 bcm.com.au: max-age too low: 0
-bcvps.com: could not connect to host
 be.search.yahoo.com: did not receive HSTS header
 beastowner.com: did not receive HSTS header
 belairsewvac.com: did not receive HSTS header
 betnet.fr: could not connect to host
 bhatia.at: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 134"  data: no]
 bi.search.yahoo.com: did not receive HSTS header
 bidon.ca: did not receive HSTS header
 bigdinosaur.org: did not receive HSTS header
@@ -78,21 +74,22 @@ blubbablasen.de: could not connect to ho
 bluetenmeer.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 134"  data: no]
 bochs.info: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 134"  data: no]
 bonigo.de: did not receive HSTS header
 bookingapp.nl: did not receive HSTS header
 br.search.yahoo.com: did not receive HSTS header
 braintreepayments.com: did not receive HSTS header
 brainvation.de: did not receive HSTS header
 bran.cc: could not connect to host
+branchtrack.com: did not receive HSTS header
 brks.xyz: could not connect to host
 browserid.org: did not receive HSTS header
 business.medbank.com.mt: did not receive HSTS header
 buttercoin.com: did not receive HSTS header
-bysymphony.com: did not receive HSTS header
+bysymphony.com: max-age too low: 0
 ca.search.yahoo.com: did not receive HSTS header
 cake.care: could not connect to host
 calibreapp.com: did not receive HSTS header
 calomel.org: could not connect to host
 calyxinstitute.org: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 134"  data: no]
 carbonmade.com: max-age too low: 5184000
 carlolly.co.uk: could not connect to host
 casa-su.casa: did not receive HSTS header
@@ -134,50 +131,50 @@ copperhead.co: max-age too low: 0
 core.mx: could not connect to host
 coursella.com: did not receive HSTS header
 cr.search.yahoo.com: did not receive HSTS header
 crate.io: did not receive HSTS header
 crbug.com: did not receive HSTS header
 crowdcurity.com: did not receive HSTS header
 crowdjuris.com: could not connect to host
 crypto.is: max-age too low: 7776000
+crysadm.com: could not connect to host
 csawctf.poly.edu: could not connect to host
 ct.search.yahoo.com: did not receive HSTS header
 cujanovic.com: did not receive HSTS header
 cyanogenmod.xxx: could not connect to host
 cybershambles.com: could not connect to host
 cyphertite.com: could not connect to host
 dash-board.jp: could not connect to host
 datasnitch.co.uk: could not connect to host
 dateno1.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 134"  data: no]
 daylightcompany.com: did not receive HSTS header
 de.search.yahoo.com: did not receive HSTS header
 decibelios.li: did not receive HSTS header
 dedeo.tk: max-age too low: 0
+derevtsov.com: did not receive HSTS header
 destinationbijoux.fr: max-age too low: 2678400
 diedrich.co: max-age too low: 7776000
 digitaldaddy.net: could not connect to host
 discovery.lookout.com: did not receive HSTS header
 disking.co.uk: could not connect to host
 dk.search.yahoo.com: did not receive HSTS header
 dl.google.com: did not receive HSTS header (error ignored - included regardless)
 do.search.yahoo.com: did not receive HSTS header
 docs.google.com: did not receive HSTS header (error ignored - included regardless)
 domaris.de: did not receive HSTS header
 donmez.uk: could not connect to host
 donmez.ws: could not connect to host
 dotadata.me: did not receive HSTS header
-dotsiam.com: could not connect to host
 download.jitsi.org: did not receive HSTS header
 dragons-of-highlands.cz: could not connect to host
 drive.google.com: did not receive HSTS header (error ignored - included regardless)
 dropcam.com: did not receive HSTS header
 drtroyhendrickson.com: could not connect to host
 dymersion.com: did not receive HSTS header
-dynaloop.net: did not receive HSTS header
 dzlibs.io: could not connect to host
 e-aut.net: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 134"  data: no]
 ebaymotorssucks.com: max-age too low: 0
 ecake.in: could not connect to host
 ecdn.cz: could not connect to host
 edelsteincosmetic.com: did not receive HSTS header
 edmodo.com: did not receive HSTS header
 egit.co: could not connect to host
@@ -215,22 +212,22 @@ fixingdns.com: did not receive HSTS head
 fj.search.yahoo.com: did not receive HSTS header
 floweslawncare.com: did not receive HSTS header
 fm83.nl: did not receive HSTS header
 fonetiq.io: could not connect to host
 foreignexchangeresource.com: did not receive HSTS header
 foro.io: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 134"  data: no]
 fotiu.com: could not connect to host
 fr.search.yahoo.com: did not receive HSTS header
+frusky.net: could not connect to host
 g2g.com: did not receive HSTS header
 gamesdepartment.co.uk: did not receive HSTS header
 gaptek.id: did not receive HSTS header
 geekandi.com: max-age too low: 7776000
 geekcast.co.uk: did not receive HSTS header
-genuxation.com: could not connect to host
 getlantern.org: did not receive HSTS header
 getssl.uz: could not connect to host
 gl.search.yahoo.com: did not receive HSTS header
 glass.google.com: did not receive HSTS header (error ignored - included regardless)
 gm.search.yahoo.com: did not receive HSTS header
 gmail.com: did not receive HSTS header (error ignored - included regardless)
 gmantra.org: could not connect to host
 golfscape.com: max-age too low: 0
@@ -244,60 +241,62 @@ goto.google.com: did not receive HSTS he
 gotowned.org: did not receive HSTS header
 gparent.org: did not receive HSTS header
 gr.search.yahoo.com: did not receive HSTS header
 grandmascookieblog.com: did not receive HSTS header
 greensolid.biz: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 134"  data: no]
 greplin.com: could not connect to host
 groups.google.com: did not receive HSTS header (error ignored - included regardless)
 gtraxapp.com: could not connect to host
+guru-naradi.cz: did not receive HSTS header
 gvt2.com: could not connect to host
 gvt2.com: could not connect to host (error ignored - included regardless)
 gvt3.com: could not connect to host
 gvt3.com: could not connect to host (error ignored - included regardless)
 gwijaya.com: did not receive HSTS header
 haber1903.com: did not receive HSTS header
 happyfabric.me: did not receive HSTS header
 haste.ch: could not connect to host
 hatoko.net: could not connect to host
-heart.ge: could not connect to host
-heftkaufen.de: did not receive HSTS header
+heart.ge: max-age too low: 0
 helpium.de: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 134"  data: no]
 henriknoerr.com: could not connect to host
 hexony.com: did not receive HSTS header
 hicn.gq: could not connect to host
 hk.search.yahoo.com: did not receive HSTS header
 hledejlevne.cz: did not receive HSTS header
 hn.search.yahoo.com: did not receive HSTS header
 hoerbuecher-und-hoerspiele.de: did not receive HSTS header
 homa.website: did not receive HSTS header
 honeytracks.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 134"  data: no]
 hookandloom.com: did not receive HSTS header
 horosho.in: could not connect to host
 horseboners.xxx: did not receive HSTS header
-hoshinplan.com: did not receive HSTS header
 hostedtalkgadget.google.com: did not receive HSTS header (error ignored - included regardless)
+hostingactive.it: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 134"  data: no]
 howrandom.org: could not connect to host
 hstspreload.appspot.com: did not receive HSTS header
 hu.search.yahoo.com: did not receive HSTS header
+ian.sh: could not connect to host
 iban.is: could not connect to host
 icq-project.net: could not connect to host
 id-co.in: could not connect to host
+id-conf.com: did not receive HSTS header
 id.fedoraproject.org: did not receive HSTS header
 id.search.yahoo.com: did not receive HSTS header
 identitylabs.uk: did not receive HSTS header
 ie.search.yahoo.com: did not receive HSTS header
 ilikerainbows.co.uk: could not connect to host
 ilmconpm.de: could not connect to host
 in.search.yahoo.com: did not receive HSTS header
 inb4.us: could not connect to host
 inertianetworks.com: did not receive HSTS header
+inleaked.com: could not connect to host
 inmyarea.com: did not receive HSTS header
-inspiroinc.com: max-age too low: 0
-intarweb.ca: could not connect to host
+inspiroinc.com: did not receive HSTS header
 interasistmen.se: did not receive HSTS header
 intercom.io: did not receive HSTS header
 ionas-law.ro: did not receive HSTS header
 iop.intuit.com: max-age too low: 86400
 iostips.ru: did not receive HSTS header
 ipmimagazine.com: did not receive HSTS header
 irccloud.com: did not receive HSTS header
 isogram.nl: did not receive HSTS header
@@ -307,32 +306,32 @@ izdiwho.com: could not connect to host
 j0s.at: did not receive HSTS header
 jamesdoylephoto.com: did not receive HSTS header
 janoberst.com: could not connect to host
 janus-engineering.de: did not receive HSTS header
 jelmer.co.uk: could not connect to host
 jettshome.org: could not connect to host
 jkb.pics: could not connect to host
 jkbuster.com: could not connect to host
-jmdekker.it: could not connect to host
 johners.me: could not connect to host
 jonathan.ir: did not receive HSTS header
 jottit.com: could not connect to host
 julian-kipka.de: did not receive HSTS header
 justlikethat.hosting: did not receive HSTS header
 k-dev.de: could not connect to host
-kamikano.com: max-age too low: 0
+kamikano.com: did not receive HSTS header
 kdm-online.de: did not receive HSTS header
 keeley.gq: could not connect to host
 keeley.ml: could not connect to host
 keepclean.me: could not connect to host
 keymaster.lookout.com: did not receive HSTS header
+kingmanhall.org: could not connect to host
 kirkforcongress.com: could not connect to host
 kirkforsenate.com: did not receive HSTS header
-kirkpatrickdavis.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 134"  data: no]
+kirkpatrickdavis.com: did not receive HSTS header
 kitsta.com: could not connect to host
 kiwiirc.com: max-age too low: 5256000
 klaxn.com: could not connect to host
 klaxn.org: could not connect to host
 komandakovalchuk.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 134"  data: no]
 koop-bremen.de: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 134"  data: no]
 korni22.org: did not receive HSTS header
 kr.search.yahoo.com: did not receive HSTS header
@@ -343,19 +342,21 @@ labina.com.tr: did not receive HSTS head
 landscape.canonical.com: max-age too low: 2592000
 ldc.com.br: did not receive HSTS header
 ledgerscope.net: max-age too low: 86400
 li.search.yahoo.com: did not receive HSTS header
 library.linode.com: did not receive HSTS header
 libraryfreedomproject.org: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 134"  data: no]
 lifeguard.aecom.com: max-age too low: 86400
 lists.fedoraproject.org: did not receive HSTS header
+lockify.com: could not connect to host
 login.corp.google.com: max-age too low: 7776000 (error ignored - included regardless)
 logotype.se: did not receive HSTS header
 lookzook.com: did not receive HSTS header
+lore.azurewebsites.net: did not receive HSTS header
 lovelycorral.com: did not receive HSTS header
 lt.search.yahoo.com: did not receive HSTS header
 lu.search.yahoo.com: did not receive HSTS header
 lukonet.com: did not receive HSTS header
 lumi.do: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 134"  data: no]
 luxus-russen.de: could not connect to host
 lv.search.yahoo.com: did not receive HSTS header
 m.gparent.org: could not connect to host
@@ -370,29 +371,32 @@ marshut.net: could not connect to host
 maternalsafety.org: did not receive HSTS header
 mebio.us: did not receive HSTS header
 medallia.io: could not connect to host
 mediacru.sh: could not connect to host
 meetingmanage.nl: did not receive HSTS header
 megashur.se: did not receive HSTS header
 megaxchange.com: did not receive HSTS header
 meinebo.it: could not connect to host
+melf.nl: could not connect to host
+members.mayfirst.org: did not receive HSTS header
 micropple.net: could not connect to host
 mijn-email.org: could not connect to host
 mindoktor.se: did not receive HSTS header
 minikneet.nl: could not connect to host
-minora.io: did not receive HSTS header
 mirrorx.com: did not receive HSTS header
 mnemotiv.com: could not connect to host
 mobilethreat.net: could not connect to host
 mobilethreatnetwork.net: could not connect to host
 modemagazines.co.uk: did not receive HSTS header
+mp3juices.is: could not connect to host
 mqas.net: could not connect to host
 msc-seereisen.net: did not receive HSTS header
 mt.search.yahoo.com: did not receive HSTS header
+mtau.com: did not receive HSTS header
 mu.search.yahoo.com: did not receive HSTS header
 mustika.cf: max-age too low: 0
 mutamatic.com: could not connect to host
 mw.search.yahoo.com: did not receive HSTS header
 mx.search.yahoo.com: did not receive HSTS header
 my.alfresco.com: did not receive HSTS header
 mydigipass.com: did not receive HSTS header
 mykolab.com: did not receive HSTS header
@@ -410,89 +414,87 @@ nexth.de: could not connect to host
 nexth.net: could not connect to host
 nexth.us: could not connect to host
 ng-security.com: could not connect to host
 ni.search.yahoo.com: did not receive HSTS header
 nl.search.yahoo.com: did not receive HSTS header
 nmctest.net: could not connect to host
 no.search.yahoo.com: did not receive HSTS header
 noexpect.org: could not connect to host
-noobs-r-us.co.uk: did not receive HSTS header
 np.search.yahoo.com: did not receive HSTS header
 nutsandboltsmedia.com: did not receive HSTS header
 nz.search.yahoo.com: did not receive HSTS header
 nzb.cat: did not receive HSTS header
-okonetwork.org.uk: did not receive HSTS header
 ooonja.de: could not connect to host
 opendesk.cc: did not receive HSTS header
 openshift.redhat.com: did not receive HSTS header
 otakurepublic.com: did not receive HSTS header
 ottospora.nl: could not connect to host
 ourbank.com: max-age too low: 604800
 ownmovies.fr: could not connect to host
 p.linode.com: could not connect to host
 pa.search.yahoo.com: did not receive HSTS header
 parent5446.us: could not connect to host
 partyvan.it: could not connect to host
 partyvan.nl: could not connect to host
 partyvan.se: could not connect to host
+passwd.io: could not connect to host
 passwordbox.com: did not receive HSTS header
 passwords.google.com: did not receive HSTS header (error ignored - included regardless)
 paste.linode.com: could not connect to host
 pastebin.linode.com: could not connect to host
 patterson.mp: could not connect to host
 pcel.com: did not receive HSTS header
 pe.search.yahoo.com: did not receive HSTS header
 ph.search.yahoo.com: did not receive HSTS header
-phongmay24h.com: max-age too low: 0
+phongmay24h.com: could not connect to host
 phurl.de: could not connect to host
 picksin.club: could not connect to host
 piratenlogin.de: could not connect to host
 pisidia.de: did not receive HSTS header
 pk.search.yahoo.com: did not receive HSTS header
 pl.search.yahoo.com: did not receive HSTS header
 platform.lookout.com: could not connect to host
 play.google.com: did not receive HSTS header (error ignored - included regardless)
 plothost.com: did not receive HSTS header
 poiema.com.sg: did not receive HSTS header
 popcorntime.ws: max-age too low: 2592000
-powerplannerapp.com: did not receive HSTS header
 pr.search.yahoo.com: did not receive HSTS header
 pressfreedomfoundation.org: did not receive HSTS header
 prodpad.com: did not receive HSTS header
 promecon-gmbh.de: did not receive HSTS header
 prontolight.com: did not receive HSTS header
 pult.co: could not connect to host
 py.search.yahoo.com: did not receive HSTS header
 qc.search.yahoo.com: did not receive HSTS header
 qvitoo.com: did not receive HSTS header
 raiseyourflag.com: did not receive HSTS header
 rapidresearch.me: could not connect to host
 rasing.me: could not connect to host
 ravchat.com: did not receive HSTS header
+rawstorieslondon.com: could not connect to host
 redlatam.org: did not receive HSTS header
 redports.org: did not receive HSTS header
 reserve-online.net: did not receive HSTS header
 rid-wan.com: could not connect to host
 rika.me: could not connect to host
 rippleunion.com: did not receive HSTS header
 riseup.net: did not receive HSTS header
+rj.gg: could not connect to host
 rme.li: did not receive HSTS header
 ro.search.yahoo.com: did not receive HSTS header
 roan24.pl: did not receive HSTS header
 roddis.net: did not receive HSTS header
 roeper.party: could not connect to host
-romans-place.me.uk: could not connect to host
 ronvandordt.info: could not connect to host
 roosterpgplus.nl: did not receive HSTS header
 ru.search.yahoo.com: did not receive HSTS header
 rudloff.pro: did not receive HSTS header
 rusl.me: did not receive HSTS header
 rw.search.yahoo.com: did not receive HSTS header
-sabahattin-gucukoglu.com: could not connect to host
 sah3.net: could not connect to host
 salserocafe.com: could not connect to host
 saturngames.co.uk: could not connect to host
 savetheinternet.eu: did not receive HSTS header
 schlarp.com: did not receive HSTS header
 schoop.me: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 134"  data: no]
 schreiber-netzwerk.eu: did not receive HSTS header
 scrambl.is: could not connect to host
@@ -511,25 +513,29 @@ seomobo.com: did not receive HSTS header
 seowarp.net: could not connect to host
 serverdensity.io: did not receive HSTS header
 sg.search.yahoo.com: did not receive HSTS header
 shanewadleigh.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 134"  data: no]
 shiinko.com: could not connect to host
 shoprose.ru: did not receive HSTS header
 shops.neonisi.com: could not connect to host
 siammedia.co: did not receive HSTS header
+sifls.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 134"  data: no]
 silentcircle.org: could not connect to host
 simon.butcher.name: max-age too low: 2629743
+simplelearner.com: could not connect to host
 simplyfixit.co.uk: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 134"  data: no]
 sistemy48.ru: did not receive HSTS header
 sites.google.com: did not receive HSTS header (error ignored - included regardless)
-slattery.co: did not receive HSTS header
+smartcoin.com.br: did not receive HSTS header
 smartlend.se: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 134"  data: no]
+smkn1lengkong.sch.id: did not receive HSTS header
 snailing.org: could not connect to host
-soccergif.com: could not connect to host
+sneberger.cz: did not receive HSTS header
+soccergif.com: did not receive HSTS header
 soci.ml: could not connect to host
 sol.io: could not connect to host
 souyar.de: could not connect to host
 souyar.net: could not connect to host
 souyar.us: could not connect to host
 spartantheatre.org: did not receive HSTS header
 spdysync.com: did not receive HSTS header
 spencerbaer.com: did not receive HSTS header
@@ -562,27 +568,28 @@ temehu.com: did not receive HSTS header
 terrax.berlin: could not connect to host
 terrax.info: could not connect to host
 terrax.net: could not connect to host
 th.search.yahoo.com: did not receive HSTS header
 the-sky-of-valkyries.com: could not connect to host
 thecoffeehouse.xyz: could not connect to host
 therapyportal.com: did not receive HSTS header
 theshadestore.com: did not receive HSTS header
-thomasgriffin.io: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 134"  data: no]
 thorncreek.net: did not receive HSTS header
 timotrans.de: did not receive HSTS header
 timotrans.eu: did not receive HSTS header
 tinyvpn.net: could not connect to host
 tinyvpn.org: could not connect to host
 tipsyk.ru: could not connect to host
 tirex.media: did not receive HSTS header
 titties.ml: could not connect to host
+tncnanet.com.br: did not receive HSTS header
 tollmanz.com: did not receive HSTS header
 tomfisher.eu: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 134"  data: no]
+topbargains.com.au: did not receive HSTS header
 topodin.com: did not receive HSTS header
 topshelfguild.com: did not receive HSTS header
 tr.search.yahoo.com: did not receive HSTS header
 tradingcentre.com.au: did not receive HSTS header
 translate.googleapis.com: did not receive HSTS header (error ignored - included regardless)
 translatoruk.co.uk: did not receive HSTS header
 travador.com: did not receive HSTS header
 triop.se: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 134"  data: no]
@@ -636,18 +643,18 @@ www.jitsi.org: did not receive HSTS head
 www.ledgerscope.net: max-age too low: 86400
 www.logentries.com: did not receive HSTS header
 www.moneybookers.com: did not receive HSTS header
 www.neonisi.com: could not connect to host
 www.paycheckrecords.com: max-age too low: 86400
 www.rme.li: did not receive HSTS header
 www.sandbox.mydigipass.com: could not connect to host
 www.surfeasy.com: did not receive HSTS header
+www.tinfoilsecurity.com: did not receive HSTS header
 xa.search.yahoo.com: did not receive HSTS header
-xgclan.com: did not receive HSTS header
 xplore-dna.net: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 134"  data: no]
 xtream-hosting.com: could not connect to host
 xtream-hosting.de: could not connect to host
 xtream-hosting.eu: could not connect to host
 xtreamhosting.eu: could not connect to host
 yenniferallulli.moda: could not connect to host
 yokeepo.com: max-age too low: 0
 za.search.yahoo.com: did not receive HSTS header
--- a/security/manager/ssl/nsSTSPreloadList.inc
+++ b/security/manager/ssl/nsSTSPreloadList.inc
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /*****************************************************************************/
 /* This is an automatically generated file. If you're not                    */
 /* nsSiteSecurityService.cpp, you shouldn't be #including it.     */
 /*****************************************************************************/
 
 #include <stdint.h>
-const PRTime gPreloadListExpirationTime = INT64_C(1452335501132000);
+const PRTime gPreloadListExpirationTime = INT64_C(1452940221783000);
 
 class nsSTSPreload
 {
   public:
     const char *mHost;
     const bool mIncludeSubdomains;
 };
 
@@ -32,24 +32,26 @@ static const nsSTSPreload kSTSPreloadLis
   { "1a-werkstattgeraete.de", true },
   { "2048game.co.uk", true },
   { "2600hq.com", true },
   { "2bis10.de", true },
   { "301.website", true },
   { "302.nyc", true },
   { "314chan.org", true },
   { "3473-wiki.de", true },
+  { "368mibn.com", true },
   { "3do3dont.com", true },
   { "47ronin.com", false },
   { "4eyes.ch", true },
   { "4g-server.eu", false },
   { "4mm.org", true },
   { "4sqsu.eu", true },
   { "5apps.com", false },
   { "7183.org", true },
+  { "888sport.dk", true },
   { "8ack.de", true },
   { "9point6.com", true },
   { "abecodes.net", false },
   { "abiapp.net", true },
   { "abioniere.de", true },
   { "abiturma.de", true },
   { "abmahnhelfer.de", true },
   { "access-sofia.org", true },
@@ -69,30 +71,32 @@ static const nsSTSPreload kSTSPreloadLis
   { "admin.google.com", true },
   { "admin.stg.fedoraproject.org", true },
   { "adorai.tk", true },
   { "adsfund.org", true },
   { "advanced-online.eu", true },
   { "adviespuntklokkenluiders.nl", true },
   { "aerolog.co", true },
   { "aes256.ru", true },
+  { "aevpn.net", true },
   { "aeyoun.com", true },
   { "affinitysync.com", true },
   { "afp548.com", true },
   { "afrodigital.uk", true },
   { "agilebits.net", false },
   { "agonswim.com", true },
   { "ahoyconference.com", true },
   { "ahwatukeefoothillsmontessori.com", true },
   { "aids.gov", true },
   { "aie.de", true },
   { "airlea.com", true },
   { "aiticon.com", true },
   { "ajouin.com", true },
   { "akachanikuji.com", true },
+  { "akclinics.org", true },
   { "akselinurmio.fi", true },
   { "aktiv-naturheilmittel.at", true },
   { "aktiv-naturheilmittel.ch", true },
   { "aktiv-naturheilmittel.de", true },
   { "aladdinschools.appspot.com", true },
   { "alainwolf.net", true },
   { "alaninkenya.org", true },
   { "alanrickmanflipstable.com", true },
@@ -113,16 +117,17 @@ static const nsSTSPreload kSTSPreloadLis
   { "amisharingstuff.com", true },
   { "amunoz.org", true },
   { "anadoluefessk.org", true },
   { "anadoluefessporkulubu.org", true },
   { "anakros.me", false },
   { "andere-gedanken.net", true },
   { "andreasbreitenlohner.de", true },
   { "andreasolsson.se", true },
+  { "andreigec.net", true },
   { "andrewimeson.com", true },
   { "andymartin.cc", true },
   { "anetaben.nl", true },
   { "anfsanchezo.me", false },
   { "angularjs.org", true },
   { "anime.my", false },
   { "animesharp.com", true },
   { "animurecs.com", true },
@@ -162,20 +167,22 @@ static const nsSTSPreload kSTSPreloadLis
   { "appuro.com", true },
   { "aprz.de", true },
   { "aranycsillag.net", true },
   { "arbitrary.ch", true },
   { "archlinux.de", true },
   { "areafiftylan.nl", true },
   { "arendburgers.nl", true },
   { "arguggi.co.uk", true },
-  { "arivo.com.br", true },
+  { "arivo.com.br", false },
   { "arlen.io", true },
   { "armory.consulting", true },
+  { "armory.supplies", false },
   { "armytricka.cz", true },
+  { "arnaudfeld.de", true },
   { "aroonchande.com", true },
   { "artegusto.ru", true },
   { "arteseideias.com.pt", true },
   { "arty.name", true },
   { "ask.fedoraproject.org", true },
   { "ask.stg.fedoraproject.org", true },
   { "askfit.cz", true },
   { "asm-x.com", true },
@@ -228,16 +235,17 @@ static const nsSTSPreload kSTSPreloadLis
   { "beautykat.ru", true },
   { "bebesurdoue.com", true },
   { "bedeta.de", true },
   { "bedreid.dk", true },
   { "beercandle.com", true },
   { "ben-energy.com", true },
   { "benchling.com", true },
   { "beneathvt.com", true },
+  { "beneffy.com", true },
   { "benjamin.pe", true },
   { "benjamins.com", true },
   { "bentertain.de", true },
   { "best-wedding-quotes.com", true },
   { "betaworx.de", true },
   { "betaworx.eu", true },
   { "bevapehappy.com", true },
   { "bfelob.gov", true },
@@ -309,23 +317,23 @@ static const nsSTSPreload kSTSPreloadLis
   { "bradkovach.com", true },
   { "brage.info", false },
   { "braineet.com", true },
   { "brainfork.ml", true },
   { "braintreegateway.com", true },
   { "brakemanpro.com", true },
   { "brakstad.org", true },
   { "bran.cc", true },
-  { "branchtrack.com", false },
   { "brandbuilderwebsites.com", true },
   { "breeswish.org", true },
   { "brianmwaters.net", true },
   { "brks.xyz", true },
   { "broeselei.at", true },
   { "brossmanit.com", true },
+  { "brrr.fr", true },
   { "brunosouza.org", true },
   { "bryanquigley.com", true },
   { "buddhistische-weisheiten.org", true },
   { "bugzil.la", true },
   { "bugzilla.mozilla.org", true },
   { "buiko.com", true },
   { "buildkite.com", true },
   { "bulktrade.de", true },
@@ -381,16 +389,17 @@ static const nsSTSPreload kSTSPreloadLis
   { "cesidianroot.eu", true },
   { "cfcnexus.org", true },
   { "cfo.gov", true },
   { "chahub.com", true },
   { "chainmonitor.com", true },
   { "chaletmanager.com", true },
   { "changetip.com", true },
   { "chaosdorf.de", true },
+  { "charge.co", true },
   { "chartstoffarm.de", false },
   { "chatbot.me", true },
   { "cheapgeekts.com", true },
   { "check.torproject.org", false },
   { "checkout.google.com", true },
   { "cheerflow.com", true },
   { "cheesetart.my", false },
   { "chippy.ch", true },
@@ -429,16 +438,17 @@ static const nsSTSPreload kSTSPreloadLis
   { "cloud.google.com", true },
   { "cloudflareonazure.com", true },
   { "cloudimag.es", true },
   { "cloudmigrator365.com", true },
   { "cloudns.com.au", true },
   { "cloudpagesforwork.com", true },
   { "cloudpebble.net", true },
   { "cloudsecurityalliance.org", true },
+  { "cloudspace-analytics.com", true },
   { "cloudstoragemaus.com", true },
   { "cloudup.com", true },
   { "clu-in.org", true },
   { "clubmini.jp", true },
   { "cmc-versand.de", true },
   { "cobalt.io", true },
   { "cocoaheads.at", true },
   { "code-poets.co.uk", true },
@@ -453,55 +463,59 @@ static const nsSTSPreload kSTSPreloadLis
   { "codingforspeed.com", true },
   { "coinapult.com", true },
   { "coinbase.com", true },
   { "coindam.com", false },
   { "collabornation.net", true },
   { "collinmbarrett.com", true },
   { "coloradocomputernetworking.net", true },
   { "colorlib.com", true },
+  { "comiteshopping.com", true },
   { "commencepayments.com", true },
   { "completionist.audio", true },
   { "comssa.org.au", true },
   { "config.schokokeks.org", false },
   { "conformal.com", true },
   { "connext.de", true },
   { "conrad-kostecki.de", true },
   { "console.support", true },
   { "consumersentinel.gov", true },
   { "contributor.google.com", true },
   { "controlcenter.gigahost.dk", true },
   { "coore.jp", true },
   { "cor-ser.es", true },
   { "cordial-restaurant.com", true },
   { "core.mx", true },
+  { "coreless-stretchfilm.com", true },
   { "corruption-mc.net", true },
   { "corruption-rsps.net", true },
   { "corruption-server.net", true },
   { "costablancavoorjou.com", true },
   { "cotonea.de", true },
   { "courtlistener.com", true },
   { "covenantoftheriver.org", true },
   { "covoiturage.fr", false },
   { "cpvmatch.eu", true },
   { "cracker.in.th", true },
   { "crackingking.com", true },
   { "cradlepointecm.com", true },
   { "craftbeerbarn.co.uk", true },
   { "crm.onlime.ch", false },
   { "crowdjuris.com", true },
+  { "crudysql.com", true },
   { "crute.me", true },
   { "crypto.cat", false },
   { "crypto.graphics", true },
   { "cryptobin.org", true },
   { "cryptography.io", true },
   { "cryptopartyatx.org", true },
   { "cryptopush.com", true },
   { "crysadm.com", true },
   { "csacongress.org", true },
+  { "csgokings.eu", true },
   { "cspbuilder.info", true },
   { "csuw.net", true },
   { "cthulhuden.com", true },
   { "ctns.de", true },
   { "cube.de", true },
   { "cupcake.io", true },
   { "cupcake.is", true },
   { "curiosity-driven.org", true },
@@ -520,16 +534,17 @@ static const nsSTSPreload kSTSPreloadLis
   { "cyprus-company-service.com", true },
   { "czakey.net", true },
   { "czbix.com", true },
   { "czk.mk", true },
   { "d42.no", true },
   { "dailyenglishchallenge.com", true },
   { "daknob.net", true },
   { "danielalvarez.net", true },
+  { "dank.ninja", true },
   { "danonsecurity.com", true },
   { "danskoferie.dk", true },
   { "danw.io", true },
   { "daphne.informatik.uni-freiburg.de", true },
   { "darchoods.net", false },
   { "darkengine.io", true },
   { "darknode.in", true },
   { "darkpony.ru", true },
@@ -561,19 +576,21 @@ static const nsSTSPreload kSTSPreloadLis
   { "dedimax.de", true },
   { "dee.pe", true },
   { "defcon.org", true },
   { "dekasan.ru", true },
   { "deliverance.co.uk", false },
   { "democracy.io", true },
   { "democracychronicles.com", true },
   { "demuzere.be", true },
+  { "demuzere.com", true },
+  { "demuzere.eu", true },
+  { "demuzere.net", true },
   { "denh.am", true },
   { "depechemode-live.com", true },
-  { "derevtsov.com", false },
   { "derhil.de", true },
   { "derp.army", true },
   { "derreichesack.com", true },
   { "desmaakvanplanten.be", true },
   { "detectify.com", false },
   { "developer.mydigipass.com", false },
   { "developers.facebook.com", false },
   { "devh.de", true },
@@ -604,16 +621,17 @@ static const nsSTSPreload kSTSPreloadLis
   { "dm.mylookout.com", false },
   { "dn42.us", true },
   { "dnmlab.it", true },
   { "dnsman.se", true },
   { "dobet.in", true },
   { "doc.python.org", true },
   { "docs.google.com", true },
   { "docs.python.org", true },
+  { "docucopies.com", true },
   { "dogoodbehappyllc.com", true },
   { "dohosting.ru", true },
   { "dolphin-cloud.com", true },
   { "dolphin-hosting.com", true },
   { "dolphin-it.de", true },
   { "domainexpress.de", true },
   { "domainkauf.de", true },
   { "domains.google.com", true },
@@ -640,16 +658,17 @@ static const nsSTSPreload kSTSPreloadLis
   { "drtroyhendrickson.com", true },
   { "drumbandesperanto.nl", true },
   { "dsebastien.net", true },
   { "dubrovskiy.net", true },
   { "duckduckstart.com", true },
   { "ducohosting.com", true },
   { "dyeager.org", true },
   { "dylanscott.com.au", true },
+  { "dynaloop.net", true },
   { "dynamicsnetwork.net", true },
   { "dzlibs.io", true },
   { "e-deca2.org", true },
   { "e-kontakti.fi", true },
   { "e-typ.eu", true },
   { "e.mail.ru", true },
   { "earmarks.gov", true },
   { "easysimplecrm.com", false },
@@ -682,16 +701,17 @@ static const nsSTSPreload kSTSPreloadLis
   { "eksisozluk.com", true },
   { "electronic-ignition-system.com", true },
   { "eleicoes2016.com.br", true },
   { "elenag.ga", true },
   { "elitegameservers.net", true },
   { "elitehosting.de", true },
   { "ellegaard.dk", true },
   { "elliquiy.com", true },
+  { "elmermx.ch", true },
   { "elvidence.com.au", true },
   { "emailhunter.co", true },
   { "emailprivacytester.com", true },
   { "empowerdb.com", true },
   { "emptypath.com", true },
   { "encircleapp.com", true },
   { "encryptallthethings.net", true },
   { "encrypted.google.com", true },
@@ -731,22 +751,24 @@ static const nsSTSPreload kSTSPreloadLis
   { "exceltobarcode.com", true },
   { "exon.io", true },
   { "expatads.com", true },
   { "experienceoz.com.au", true },
   { "explodie.org", true },
   { "expoundite.net", true },
   { "expressvpn.com", true },
   { "extendwings.com", true },
+  { "extreemhost.nl", true },
   { "ezequiel-garzon.com", true },
   { "ezequiel-garzon.net", true },
   { "f-droid.org", true },
   { "f2f.cash", true },
   { "fa-works.com", true },
   { "fabhub.io", true },
+  { "fabianasantiago.com", true },
   { "fabse.net", true },
   { "facebook.com", false },
   { "factor.cc", false },
   { "fairbill.com", true },
   { "fakturoid.cz", true },
   { "falconvintners.com", true },
   { "fangs.ink", true },
   { "faq.lookout.com", false },
@@ -758,28 +780,29 @@ static const nsSTSPreload kSTSPreloadLis
   { "fedorahosted.org", true },
   { "fedorapeople.org", true },
   { "feedbin.com", false },
   { "feedthebot.com", true },
   { "feminists.co", true },
   { "ferienhaus-polchow-ruegen.de", false },
   { "fewo-thueringer-wald.de", true },
   { "ffbans.org", true },
+  { "fi.google.com", true },
   { "fidanza.eu", true },
   { "fidelapp.com", true },
   { "fiftyshadesofluca.ml", true },
   { "fightr.co", true },
   { "fiken.no", true },
   { "filedir.com", false },
   { "filip-prochazka.com", true },
   { "finn.io", false },
   { "firebaseio-demo.com", true },
   { "firebaseio.com", true },
   { "firebirdrangecookers.com", true },
-  { "firefart.at", true },
+  { "firefart.at", false },
   { "firemail.io", true },
   { "firma-offshore.com", true },
   { "firmapi.com", true },
   { "firstlook.org", true },
   { "fischer-its.com", true },
   { "fish-hook.ru", true },
   { "fitkram.cz", true },
   { "fj.simple.com", false },
@@ -838,16 +861,17 @@ static const nsSTSPreload kSTSPreloadLis
   { "gambit.pro", true },
   { "gambitnash.co.uk", true },
   { "gambitnash.com", true },
   { "gambitprint.com", true },
   { "gamenected.com", true },
   { "gamenected.de", true },
   { "gamercredo.com", true },
   { "gamercredo.net", true },
+  { "gamers-life.fr", true },
   { "gameserver-sponsor.de", true },
   { "garron.net", true },
   { "gavick.com", true },
   { "gaytorrent.ru", true },
   { "gc.net", true },
   { "ge3k.net", true },
   { "geblitzt.de", true },
   { "gemeinfreie-lieder.de", true },
@@ -877,16 +901,17 @@ static const nsSTSPreload kSTSPreloadLis
   { "gipsamsfashion.com", true },
   { "github.com", true },
   { "github.party", false },
   { "giveattheoffice.org", true },
   { "givingnexus.org", true },
   { "gizzo.sk", true },
   { "glasgestaltung.biz", true },
   { "glass.google.com", true },
+  { "globalinstitutefortraining.org.au", true },
   { "globalittech.com", false },
   { "globuli-info.de", true },
   { "glossopnorthendafc.co.uk", true },
   { "gmail.com", false },
   { "gmantra.org", true },
   { "gmcd.co", true },
   { "gmdu.net", true },
   { "gmta.nl", true },
@@ -906,25 +931,27 @@ static const nsSTSPreload kSTSPreloadLis
   { "gotspot.com", true },
   { "govtrack.us", true },
   { "gplintegratedit.com", true },
   { "gpsfix.cz", true },
   { "gpsvideocanada.com", true },
   { "gra2.com", true },
   { "gracedays.org", true },
   { "grafitec.ru", true },
+  { "graingert.co.uk", true },
   { "grandcapital.id", true },
   { "grandcapital.ru", true },
   { "grandlinecsk.ru", true },
   { "granth.io", true },
   { "gravity-net.de", true },
   { "grc.com", false },
   { "greatfire.org", true },
   { "greenroach.ru", true },
   { "greensolid.biz", true },
+  { "greenvines.com.tw", true },
   { "gregorytlee.me", true },
   { "grepular.com", true },
   { "grigalanzsoftware.com", true },
   { "grimm-gastrobedarf.de", true },
   { "grocock.me.uk", true },
   { "groetzner.net", true },
   { "groszek.pl", true },
   { "groups.google.com", true },
@@ -932,33 +959,34 @@ static const nsSTSPreload kSTSPreloadLis
   { "gtmetrix.com", true },
   { "gtraxapp.com", true },
   { "gudini.net", true },
   { "gugga.dk", false },
   { "guidetoiceland.is", false },
   { "guilde-vindicta.fr", true },
   { "gunnarhafdal.com", true },
   { "guphi.net", true },
-  { "guru-naradi.cz", true },
   { "gurusupe.com", true },
   { "guthabenkarten-billiger.de", true },
   { "gvt2.com", true },
   { "gvt3.com", true },
   { "gw2treasures.com", true },
   { "h2check.org", true },
   { "hablemosdetecnologia.com.ve", true },
   { "hachre.de", false },
   { "hack.li", true },
   { "hackerone-user-content.com", true },
   { "hackerone.com", true },
   { "hafniatimes.com", true },
   { "haircrazy.com", true },
+  { "hana.ondemand.com", true },
   { "hangouts.google.com", true },
   { "hannover-banditen.de", true },
   { "hansvaneijsden.com", true },
+  { "hao2taiwan.com", false },
   { "happygadget.me", true },
   { "happylifestyle.com", true },
   { "happyteamlabs.com", true },
   { "hardh.at", true },
   { "harvestapp.com", true },
   { "hash-list.com", true },
   { "hashplex.com", true },
   { "hasilocke.de", true },
@@ -968,16 +996,17 @@ static const nsSTSPreload kSTSPreloadLis
   { "haveeruexaminer.com", true },
   { "haveibeenpwned.com", true },
   { "hboeck.de", true },
   { "hda.me", true },
   { "hdc.cz", true },
   { "healthcare.gov", false },
   { "heartlandrentals.com", true },
   { "heavystresser.com", true },
+  { "heftkaufen.de", true },
   { "heh.ee", true },
   { "heha.co", false },
   { "heid.ws", true },
   { "heijblok.com", true },
   { "helichat.de", true },
   { "helloacm.com", true },
   { "help.simpletax.ca", false },
   { "helpadmin.net", true },
@@ -993,19 +1022,22 @@ static const nsSTSPreload kSTSPreloadLis
   { "hg.python.org", true },
   { "hicn.gq", true },
   { "hicoria.com", true },
   { "hisbrucker.net", true },
   { "history.google.com", false },
   { "hiv.gov", true },
   { "hledejpravnika.cz", true },
   { "hobbyspeed.com", true },
+  { "hollowrap.com", true },
   { "holymoly.lu", true },
   { "honeybadger.io", false },
   { "horza.org", true },
+  { "hoshinplan.com", true },
+  { "hostanalyticsconsulting.com", true },
   { "hostedtalkgadget.google.com", true },
   { "hostinginnederland.nl", true },
   { "hostix.de", true },
   { "howrandom.org", true },
   { "howsmyssl.com", true },
   { "howsmytls.com", true },
   { "hozana.si", true },
   { "hpac-portal.com", true },
@@ -1013,28 +1045,28 @@ static const nsSTSPreload kSTSPreloadLis
   { "hranicka.cz", true },
   { "hs-group.net", true },
   { "hsmr.cc", true },
   { "hsr.gov", true },
   { "hsts.date", true },
   { "hstsfail.appspot.com", true },
   { "html5.org", true },
   { "httpswatch.com", true },
+  { "humankode.com", true },
   { "humblefinances.com", true },
   { "hurricanelabs.com", true },
   { "hushfile.it", true },
   { "hyper-text.org", true },
   { "i10z.com", true },
   { "i5y.co.uk", true },
   { "iamcarrico.com", true },
   { "ian.sh", true },
   { "iban.is", true },
   { "icq-project.net", true },
   { "id-co.in", true },
-  { "id-conf.com", true },
   { "id.atlassian.com", true },
   { "id.mayfirst.org", false },
   { "ideaweb.de", true },
   { "idndx.com", true },
   { "ieval.ro", true },
   { "ihrlotto.de", true },
   { "iispeed.com", true },
   { "ijohan.nl", true },
@@ -1047,16 +1079,17 @@ static const nsSTSPreload kSTSPreloadLis
   { "im-c-shop.com", true },
   { "imaginary.ca", true },
   { "imagr.io", true },
   { "imbrian.org", true },
   { "imgg.es", true },
   { "imirhil.fr", false },
   { "immoverkauf24.at", true },
   { "immoverkauf24.de", true },
+  { "immunicity.info", true },
   { "imouto.my", false },
   { "impex.com.bd", true },
   { "in.xero.com", false },
   { "inb4.us", true },
   { "inbitcoin.it", true },
   { "inbounder.io", true },
   { "inbox.google.com", true },
   { "indiecert.net", true },
@@ -1164,16 +1197,17 @@ static const nsSTSPreload kSTSPreloadLis
   { "junqtion.com", false },
   { "jurriaan.ninja", true },
   { "justyy.com", true },
   { "jwilsson.com", true },
   { "jwilsson.me", true },
   { "jwnotifier.org", true },
   { "k-dev.de", true },
   { "kaheim.de", true },
+  { "kahopoon.net", true },
   { "kalevlamps.co.uk", true },
   { "kalmar.com", true },
   { "kaneo-gmbh.de", true },
   { "kantorosobisty.pl", true },
   { "kanzashi.com", true },
   { "karaoketonight.com", true },
   { "kardize24.pl", true },
   { "karmaspa.se", true },
@@ -1199,16 +1233,17 @@ static const nsSTSPreload kSTSPreloadLis
   { "kermadec.com", true },
   { "kernel-error.de", true },
   { "keskeces.com", true },
   { "kevincox.ca", true },
   { "keybase.io", true },
   { "keycdn.com", true },
   { "keyerror.com", true },
   { "khanovaskola.cz", true },
+  { "khetzal.info", true },
   { "khipu.com", true },
   { "khmath.com", true },
   { "ki-on.net", true },
   { "kick-in.nl", true },
   { "kickass.al", true },
   { "kinderbasar-luhe.de", true },
   { "kinderbuecher-kostenlos.de", true },
   { "kingant.net", true },
@@ -1227,16 +1262,17 @@ static const nsSTSPreload kSTSPreloadLis
   { "kleidertauschpartys.de", true },
   { "kliemann.me", true },
   { "klingeletest.de", true },
   { "knip.ch", true },
   { "knowledgehook.com", true },
   { "koen.io", true },
   { "koenrouwhorst.nl", true },
   { "koenvdheuvel.me", true },
+  { "koerperimpuls.ch", true },
   { "kojipkgs.fedoraproject.org", true },
   { "kollawat.me", true },
   { "komandakovalchuk.com", false },
   { "konklone.com", true },
   { "konsertoversikt.no", true },
   { "koop-bremen.de", true },
   { "koordinate.net", true },
   { "korinar.com", true },
@@ -1331,17 +1367,17 @@ static const nsSTSPreload kSTSPreloadLis
   { "login.sapo.pt", true },
   { "login.ubuntu.com", true },
   { "login.xero.com", false },
   { "login.yahoo.com", false },
   { "lognot.net", true },
   { "lolicore.ch", true },
   { "lookout.com", false },
   { "lookyman.net", true },
-  { "lore.azurewebsites.net", true },
+  { "lostinsecurity.com", true },
   { "ludwig.im", true },
   { "luelistan.net", true },
   { "lukasztkacz.com", true },
   { "lumi.do", false },
   { "luneta.nearbuysystems.com", false },
   { "luxwatch.com", true },
   { "lymia.moe", true },
   { "lyst.co.uk", true },
@@ -1359,19 +1395,21 @@ static const nsSTSPreload kSTSPreloadLis
   { "maff.scot", false },
   { "magneticanvil.com", true },
   { "mahamed91.pw", true },
   { "mail-settings.google.com", true },
   { "mail.de", true },
   { "mail.google.com", true },
   { "mail.yahoo.com", false },
   { "mailbox.org", true },
+  { "mailinabox.email", true },
   { "mailmag.net", true },
   { "makeitdynamic.com", true },
   { "makeyourlaws.org", true },
+  { "malash.me", true },
   { "mall.cz", true },
   { "mall.hu", true },
   { "mall.pl", true },
   { "mall.sk", true },
   { "malnex.de", true },
   { "malwre.io", true },
   { "mamaison.io", true },
   { "mammaw.com", true },
@@ -1387,16 +1425,17 @@ static const nsSTSPreload kSTSPreloadLis
   { "mark-semmler.de", true },
   { "markayapilandirma.com", true },
   { "market.android.com", true },
   { "markhaehnel.de", true },
   { "marktboten.de", true },
   { "markusueberallassetmanagement.de", true },
   { "marshut.net", true },
   { "martijnvhoof.nl", true },
+  { "masjidtawheed.net", true },
   { "massivum.de", false },
   { "masters.black", true },
   { "matatall.com", false },
   { "mathiasbynens.be", true },
   { "matteomarescotti.it", true },
   { "mattfin.ch", true },
   { "mattmccutchen.net", true },
   { "mattsvensson.com", true },
@@ -1428,17 +1467,16 @@ static const nsSTSPreload kSTSPreloadLis
   { "meetings2.com", true },
   { "mega.co.nz", true },
   { "mega.nz", true },
   { "megaplan.cz", true },
   { "megaplan.ru", true },
   { "mehmetince.net", true },
   { "meinebo.it", true },
   { "melf.nl", true },
-  { "members.mayfirst.org", false },
   { "members.nearlyfreespeech.net", false },
   { "mercuryamericas.com", true },
   { "mercurystorm.co.za", true },
   { "meritz.rocks", true },
   { "mertcangokgoz.com", true },
   { "mesvt.com", true },
   { "meta-db.com", true },
   { "meteosky.net", true },
@@ -1463,16 +1501,17 @@ static const nsSTSPreload kSTSPreloadLis
   { "mimovrste.com", true },
   { "mindcoding.ro", true },
   { "minecraftvoter.com", true },
   { "mineover.es", true },
   { "minez-nightswatch.com", false },
   { "minikneet.com", true },
   { "minkondom.nu", true },
   { "minnesotadata.com", true },
+  { "minora.io", true },
   { "mirindadomo.ru", false },
   { "mironet.cz", true },
   { "mirtes.cz", true },
   { "miskatonic.org", true },
   { "miss-inventory.co.uk", true },
   { "mistacms.com", true },
   { "mister.hosting", true },
   { "mitchellrenouf.ca", true },
@@ -1506,17 +1545,16 @@ static const nsSTSPreload kSTSPreloadLis
   { "movlib.org", true },
   { "mp3gratuiti.com", true },
   { "mp3juices.is", true },
   { "mpreserver.com", true },
   { "mqas.net", true },
   { "mr-hosting.com", true },
   { "msa-aesch.ch", true },
   { "msebera.cz", true },
-  { "mtau.com", true },
   { "mthode.org", true },
   { "mths.be", true },
   { "mtouch.facebook.com", false },
   { "mudcrab.us", true },
   { "mujadin.se", true },
   { "multigamecard.com", true },
   { "munich-rage.de", true },
   { "munki.org", true },
@@ -1578,21 +1616,23 @@ static const nsSTSPreload kSTSPreloadLis
   { "net-safe.info", true },
   { "netbox.cc", true },
   { "netera.se", true },
   { "nethackwiki.com", true },
   { "netrelay.email", true },
   { "netrider.net.au", false },
   { "nette.org", true },
   { "new-black-order.com", true },
+  { "newodesign.com", true },
   { "newstarnootropics.com", true },
   { "nextend.net", true },
   { "ng-security.com", true },
   { "nginxnudes.com", true },
   { "nicky.io", true },
+  { "nicolaelmer.ch", true },
   { "nicolaw.uk", true },
   { "nieselregen.com", true },
   { "nijm.nl", true },
   { "niloxy.com", true },
   { "nmctest.net", true },
   { "nmd.so", true },
   { "nodari.com.ar", true },
   { "noemax.com", true },
@@ -1622,31 +1662,34 @@ static const nsSTSPreload kSTSPreloadLis
   { "null.tips", true },
   { "nuos.org", true },
   { "nuvini.com", true },
   { "nwa.xyz", true },
   { "nwgh.org", true },
   { "nymphetomania.net", true },
   { "oakslighting.co.uk", true },
   { "obermeiers.eu", true },
+  { "ochsundjunior.ch", true },
   { "ocrami.us", true },
   { "odin.xxx", true },
   { "offshore-firma.org", true },
   { "oguya.ch", true },
   { "ohling.org", true },
   { "ohnemusik.com", true },
   { "okmx.de", true },
+  { "okonetwork.org.uk", true },
   { "olivierlemoal.fr", true },
   { "ollning.com", true },
   { "omacostudio.com", true },
   { "omitech.co.uk", true },
   { "onedot.nl", true },
   { "onedrive.com", true },
   { "onedrive.live.com", false },
   { "onewpst.com", false },
+  { "onixcco.com.br", true },
   { "only-roses.com", true },
   { "onsitemassageco.com", true },
   { "ontimestamp.com", true },
   { "ooonja.de", true },
   { "open-to-repair.fr", true },
   { "openacademies.com", true },
   { "openkvk.nl", true },
   { "oplop.appspot.com", true },
@@ -1704,35 +1747,37 @@ static const nsSTSPreload kSTSPreloadLis
   { "pay.ubuntu.com", true },
   { "paymentaccuracy.gov", true },
   { "payments-reference.org", true },
   { "paymill.com", true },
   { "paymill.de", true },
   { "paypal.com", false },
   { "payroll.xero.com", false },
   { "paysera.com", true },
-  { "pbprint.ru", false },
+  { "pbprint.ru", true },
   { "pcfeuerwehr.de", true },
   { "pclob.gov", true },
+  { "pctonic.net", true },
   { "pdf.yt", true },
   { "peercraft.com", true },
   { "pentesterlab.com", true },
   { "perfectionis.me", true },
   { "personaldatabasen.no", true },
   { "pestici.de", true },
   { "petersmark.com", true },
   { "petplum.com", true },
   { "petrachuk.ru", true },
   { "petrolplus.ru", true },
   { "pharmaboard.de", true },
   { "phil.tw", true },
   { "philosopherswool.com", true },
   { "philosophyguides.org", true },
   { "phoenix.dj", true },
   { "phoenixlogan.com", true },
+  { "photoblogverona.com", true },
   { "phpfashion.com", true },
   { "phryanjr.com", false },
   { "phryneas.de", true },
   { "phurl.de", true },
   { "pi-supply.com", true },
   { "picksin.club", true },
   { "picsto.re", true },
   { "pieperhome.de", true },
@@ -1747,16 +1792,17 @@ static const nsSTSPreload kSTSPreloadLis
   { "pirlitu.com", true },
   { "pirxpilot.me", true },
   { "pixel.facebook.com", false },
   { "pixi.me", true },
   { "play.google.com", true },
   { "playkh.com", true },
   { "pleier-it.de", true },
   { "pleier.it", true },
+  { "pluga.co", true },
   { "plus.google.com", false },
   { "plus.sandbox.google.com", false },
   { "plzenskybarcamp.cz", true },
   { "pmctire.com", true },
   { "pmg-offshore-company.com", true },
   { "pmg-purchase.com", true },
   { "pmg-purchase.net", true },
   { "pmnts.io", true },
@@ -1771,22 +1817,26 @@ static const nsSTSPreload kSTSPreloadLis
   { "poolvilla-margarita.net", true },
   { "portal.tirol.gv.at", true },
   { "portalplatform.net", true },
   { "posteo.de", false },
   { "postfinance.ch", true },
   { "posttigo.com", true },
   { "pothe.com", true },
   { "pothe.de", true },
+  { "powerplannerapp.com", true },
   { "prakharprasad.com", true },
+  { "prefis.com", true },
   { "prefontaine.name", true },
   { "preissler.co.uk", true },
   { "preloaded-hsts.badssl.com", true },
+  { "prepandgo-euro.com", true },
   { "presidentials2016.com", true },
   { "privategiant.com", true },
+  { "production.vn", true },
   { "profiles.google.com", true },
   { "progg.no", true },
   { "progressiveplanning.com", true },
   { "projectascension.io", true },
   { "projektzentrisch.de", true },
   { "proofwiki.org", true },
   { "propagandism.org", true },
   { "prospo.co", true },
@@ -1814,24 +1864,26 @@ static const nsSTSPreload kSTSPreloadLis
   { "qixxit.de", true },
   { "qualityhomesystems.com", true },
   { "quebecmailbox.com", true },
   { "quli.nl", true },
   { "quppa.net", true },
   { "quuz.org", true },
   { "r3s1stanc3.me", true },
   { "raah.co", true },
+  { "raconconsulting.co.uk", true },
   { "rad-route.de", true },
   { "radiormi.com", true },
   { "radtke.bayern", true },
   { "rafaelcz.de", true },
   { "ragingserenity.com", true },
   { "railgun.ac", true },
   { "rambitteh.ru", true },
   { "ramsor-gaming.de", true },
+  { "rangde.org", true },
   { "rantanda.com", true },
   { "rasing.me", true },
   { "raspass.me", true },
   { "rawstorieslondon.com", true },
   { "raydobe.me", false },
   { "raymii.org", true },
   { "rc4.io", true },
   { "reaconverter.com", true },
@@ -1848,19 +1900,21 @@ static const nsSTSPreload kSTSPreloadLis
   { "reedloden.com", true },
   { "refundo.cz", true },
   { "refundo.sk", true },
   { "reg.ru", false },
   { "regar42.fr", false },
   { "reishunger.de", true },
   { "release-monitoring.org", true },
   { "reliable-mail.de", true },
+  { "remotestance.com", true },
   { "remoteutilities.com", true },
   { "renem.net", true },
   { "renlong.org", true },
+  { "renuo.ch", true },
   { "report-uri.io", true },
   { "research.facebook.com", false },
   { "research.md", true },
   { "residentsinsurance.co.uk", true },
   { "resources.flowfinity.com", true },
   { "respice.xyz", true },
   { "retroarms.com", true },
   { "retroarms.cz", true },
@@ -1871,16 +1925,17 @@ static const nsSTSPreload kSTSPreloadLis
   { "richardwarrender.com", true },
   { "richiemail.net", true },
   { "ricochet.im", true },
   { "rid-wan.com", true },
   { "riesenmagnete.de", true },
   { "rigolitch.fr", true },
   { "rika.me", true },
   { "rischard.org", true },
+  { "riskmitigation.ch", true },
   { "ristioja.ee", true },
   { "rj.gg", true },
   { "rlalique.com", true },
   { "rmmanfredi.com", true },
   { "robertglastra.com", true },
   { "roberthurlbut.com", true },
   { "robertof.ovh", true },
   { "robinadr.com", true },
@@ -1934,22 +1989,24 @@ static const nsSTSPreload kSTSPreloadLis
   { "salserocafe.com", true },
   { "salserototal.com", true },
   { "samba.org", true },
   { "samfunnet.no", false },
   { "samizdat.cz", true },
   { "samuelkeeley.com", true },
   { "sanatfilan.com", false },
   { "sandbox.mydigipass.com", false },
+  { "sanhei.ch", true },
   { "sarahlicity.co.uk", false },
   { "satmep.com", true },
   { "saulchristie.com", true },
   { "save.gov", true },
   { "saveaward.gov", true },
   { "savvytime.com", true },
+  { "scaling.solutions", true },
   { "schachburg.de", true },
   { "schallert.com", true },
   { "schokokeks.org", true },
   { "schorel.ovh", true },
   { "schorelweb.nl", true },
   { "schreibnacht.de", true },
   { "schwarzer.it", true },
   { "sciencex.com", true },
@@ -2045,41 +2102,39 @@ static const nsSTSPreload kSTSPreloadLis
   { "skoda-nurdiebesten.de", true },
   { "skogsbruket.fi", true },
   { "skogskultur.fi", true },
   { "skoleniphp.cz", true },
   { "skydrive.live.com", false },
   { "slack-files.com", true },
   { "slack.com", true },
   { "slainvet.net", true },
+  { "slattery.co", true },
   { "sleio.com", true },
   { "slever.cz", true },
   { "slevomat.cz", true },
   { "slicketl.com", true },
   { "slidebatch.com", true },
   { "slix.io", true },
   { "slope.haus", true },
   { "slse.ca", true },
   { "smartcleaningcenter.nl", true },
-  { "smartcoin.com.br", true },
   { "smartlend.se", true },
   { "smartlocksmith.com", true },
   { "smartship.co.jp", true },
   { "smb445.com", true },
   { "smiatek.name", true },
   { "smith.is", true },
   { "snailing.org", true },
   { "snakehosting.dk", false },
   { "snazel.co.uk", true },
   { "sneakynote.com", true },
-  { "sneberger.cz", false },
   { "sneezry.com", true },
   { "sny.no", true },
   { "sobabox.ru", true },
-  { "soccergif.com", true },
   { "soci.ml", true },
   { "social-media-strategies.it", true },
   { "socialrank.com", false },
   { "socialspirit.com.br", false },
   { "sockeye.cc", false },
   { "soia.ca", true },
   { "solihullcarnival.co.uk", true },
   { "solihulllionsclub.org.uk", true },
@@ -2107,21 +2162,23 @@ static const nsSTSPreload kSTSPreloadLis
   { "sprueche-zur-hochzeit.de", true },
   { "sprueche-zur-konfirmation.de", true },
   { "spyroszarzonis.com", true },
   { "square.com", false },
   { "squareup.com", false },
   { "srevilak.net", true },
   { "sro.center", true },
   { "ssl.google-analytics.com", true },
+  { "ssldecoder.org", true },
   { "sslmate.com", true },
   { "stablelib.com", true },
   { "stage.wepay.com", false },
   { "standardssuck.org", true },
   { "starapple.nl", true },
+  { "startupsort.com", true },
   { "static.wepay.com", false },
   { "staticanime.net", false },
   { "stationary-traveller.eu", true },
   { "steelephys.com.au", true },
   { "stemsims.com", true },
   { "stereo.lu", true },
   { "stereochro.me", true },
   { "stesti.cz", true },
@@ -2154,16 +2211,17 @@ static const nsSTSPreload kSTSPreloadLis
   { "supplies24.at", true },
   { "supplies24.es", true },
   { "surkatty.org", true },
   { "survivalmonkey.com", true },
   { "svager.cz", true },
   { "sweetll.me", true },
   { "swehack.org", false },
   { "swift-devedge.de", true },
+  { "sx3.no", true },
   { "sychov.pro", true },
   { "sylaps.com", true },
   { "syncappate.com", true },
   { "syntaxnightmare.com", true },
   { "sysctl.se", true },
   { "sysdb.io", true },
   { "syso.name", true },
   { "syss.de", true },
@@ -2194,16 +2252,17 @@ static const nsSTSPreload kSTSPreloadLis
   { "tdrs.info", true },
   { "teachforcanada.ca", true },
   { "teamblueridge.org", true },
   { "teamnorthgermany.de", true },
   { "teamupturn.com", true },
   { "tecart-cloud.de", true },
   { "tecart-system.de", true },
   { "tecartcrm.de", true },
+  { "tech-seminar.jp", true },
   { "techandtux.de", true },
   { "techhipster.net", true },
   { "techhub.ml", true },
   { "techllage.com", true },
   { "techloaner.com", true },
   { "technotonic.com.au", false },
   { "techvalue.gr", true },
   { "tehrabbitt.com", true },
@@ -2270,16 +2329,17 @@ static const nsSTSPreload kSTSPreloadLis
   { "todoist.com", true },
   { "tokke.dk", true },
   { "tollsjekk.no", true },
   { "tom.horse", true },
   { "tomfisher.eu", true },
   { "tomharling.co.uk", true },
   { "tomharling.uk", true },
   { "tomli.me", true },
+  { "tomo.gr", false },
   { "tomrichards.net", true },
   { "tomvote.com", true },
   { "toner24.at", true },
   { "toner24.co.uk", true },
   { "toner24.es", true },
   { "toner24.fr", true },
   { "toner24.it", true },
   { "toner24.nl", true },
@@ -2291,17 +2351,16 @@ static const nsSTSPreload kSTSPreloadLis
   { "tonerkurier.de", true },
   { "tonermaus.de", true },
   { "tonermonster.de", true },
   { "tonex.de", true },
   { "tonex.nl", true },
   { "tonytan.cn", true },
   { "tonytan.io", true },
   { "tonywebster.com", true },
-  { "topbargains.com.au", true },
   { "topnewstoday.org", true },
   { "toptexture.com", true },
   { "tor2web.org", true },
   { "tormentedradio.com", true },
   { "torproject.org", false },
   { "torquato.de", false },
   { "tosecure.link", true },
   { "toshnix.com", true },
@@ -2368,16 +2427,17 @@ static const nsSTSPreload kSTSPreloadLis
   { "upload.facebook.com", false },
   { "uploadbeta.com", true },
   { "uptrends.com", true },
   { "uptrends.de", true },
   { "usaa.com", false },
   { "uscntalk.com", true },
   { "uspsoig.gov", true },
   { "ust.space", true },
+  { "utilia.tools", true },
   { "utilityapi.com", true },
   { "utleieplassen.no", true },
   { "utonia.ch", true },
   { "vaddder.com", true },
   { "valopv.be", true },
   { "vanhoutte.be", true },
   { "vapemania.eu", true },
   { "varden.info", true },
@@ -2390,36 +2450,40 @@ static const nsSTSPreload kSTSPreloadLis
   { "vcsjones.com", true },
   { "vechkasov.ru", true },
   { "venicerealdeal.com", true },
   { "vhost.co.id", true },
   { "viasinc.com", false },
   { "victorcanera.com", true },
   { "videomail.io", false },
   { "viennan.net", true },
+  { "viewmyrecords.com", true },
   { "vigo-krankenversicherung.de", true },
   { "vijos.org", true },
+  { "vino75.com", true },
   { "visionless.me", false },
   { "vitrado.de", true },
   { "vivendi.de", true },
   { "vmoagents.com", false },
+  { "vmrdev.com", true },
   { "vocaloid.my", true },
   { "voicesuk.co.uk", true },
   { "vokeapp.com", true },
   { "vomitb.in", true },
   { "vorlif.org", true },
   { "vortexhobbies.com", true },
   { "votocek.cz", true },
   { "votockova.cz", true },
   { "vox.vg", true },
   { "vpnzoom.com", true },
   { "vrobert.fr", false },
   { "vrtak-cz.net", true },
   { "vsean.net", true },
   { "vserver-preis-vergleich.de", true },
+  { "vulnerability.ch", true },
   { "vyplnto.cz", true },
   { "vzk.io", false },
   { "w-spotlight.appspot.com", true },
   { "wachter.biz", true },
   { "wallet.google.com", true },
   { "walnutgaming.co.uk", true },
   { "walnutgaming.com", true },
   { "warrencreative.com", false },
@@ -2465,17 +2529,17 @@ static const nsSTSPreload kSTSPreloadLis
   { "wf-dogfood-hrd.appspot.com", true },
   { "wf-pentest.appspot.com", true },
   { "wf-staging-hr.appspot.com", true },
   { "wf-training-hrd.appspot.com", true },
   { "wf-training-master.appspot.com", true },
   { "wf-trial-hrd.appspot.com", true },
   { "whatwg.org", true },
   { "whd-guide.de", true },
-  { "when-release.ru", true },
+  { "when-release.ru", false },
   { "when.fm", true },
   { "wherephoto.com", true },
   { "whispeer.de", true },
   { "whitehouse.gov", true },
   { "whitestagforge.com", true },
   { "whocalld.com", true },
   { "wholebites.com", true },
   { "whonix.org", true },
@@ -2560,17 +2624,16 @@ static const nsSTSPreload kSTSPreloadLis
   { "www.opsmate.com", true },
   { "www.paypal.com", false },
   { "www.python.org", true },
   { "www.roddis.net", true },
   { "www.schokokeks.org", true },
   { "www.simbolo.co.uk", false },
   { "www.simple.com", false },
   { "www.therapynotes.com", true },
-  { "www.tinfoilsecurity.com", false },
   { "www.torproject.org", false },
   { "www.twitter.com", false },
   { "www.usaa.com", false },
   { "www.viasinc.com", true },
   { "www.wepay.com", false },
   { "www.zenpayroll.com", false },
   { "wzrd.in", true },
   { "wzyboy.org", true },
@@ -2579,22 +2642,26 @@ static const nsSTSPreload kSTSPreloadLis
   { "x64architecture.com", true },
   { "xavierbarroso.com", true },
   { "xbrlsuccess.appspot.com", true },
   { "xcoop.me", true },
   { "xd.cm", true },
   { "xellos.ml", true },
   { "xenesisziarovky.sk", true },
   { "xf-liam.com", true },
+  { "xgclan.com", true },
   { "xho.me", true },
+  { "xiaolan.me", true },
   { "xiaolvmu.me", true },
+  { "xiaoxiao.im", true },
   { "xn--4dbjwf8c.cf", true },
   { "xn--4dbjwf8c.ga", true },
   { "xn--4dbjwf8c.ml", true },
   { "xn--4dbjwf8c.tk", true },
+  { "xn--7xa.google.com", true },
   { "xn--datenrettung-mnchen-jbc.com", true },
   { "xn--hfk-allgu-schwaben-stb.de", true },
   { "xn--knstler-n2a.tips", false },
   { "xn--lgb3a8bcpn.cf", true },
   { "xn--lgb3a8bcpn.ga", true },
   { "xn--lgb3a8bcpn.gq", true },
   { "xn--lgb3a8bcpn.ml", true },
   { "xn--ls8hi7a.tk", true },
--- a/toolkit/devtools/webconsole/test/chrome.ini
+++ b/toolkit/devtools/webconsole/test/chrome.ini
@@ -10,16 +10,17 @@ support-files =
 
 [test_basics.html]
 [test_bug819670_getter_throws.html]
 [test_cached_messages.html]
 [test_commands_other.html]
 [test_commands_registration.html]
 [test_consoleapi.html]
 [test_consoleapi_innerID.html]
+[test_console_styling.html]
 [test_file_uri.html]
 [test_reflow.html]
 [test_jsterm.html]
 [test_jsterm_cd_iframe.html]
 [test_jsterm_last_result.html]
 [test_jsterm_queryselector.html]
 [test_network_get.html]
 [test_network_longstring.html]
new file mode 100644
--- /dev/null
+++ b/toolkit/devtools/webconsole/test/test_console_styling.html
@@ -0,0 +1,126 @@
+<!DOCTYPE HTML>
+<html lang="en">
+<head>
+  <meta charset="utf8">
+  <title>Test for console.log styling with %c</title>
+  <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript;version=1.8" src="common.js"></script>
+  <!-- Any copyright is dedicated to the Public Domain.
+     - http://creativecommons.org/publicdomain/zero/1.0/ -->
+</head>
+<body>
+<p>Test for console.log styling with %c</p>
+
+<script class="testbody" type="text/javascript;version=1.8">
+SimpleTest.waitForExplicitFinish();
+
+let expectedConsoleCalls = [];
+
+function doConsoleCalls(aState)
+{
+  top.console.log("%cOne formatter with no styles");
+  top.console.log("%cOne formatter", "color: red");
+  top.console.log("%cTwo formatters%cEach with an arg",
+    "color: red", "background: red");
+  top.console.log("%c%cTwo formatters next to each other",
+    "color: red", "background: red");
+  top.console.log("%c%c%cThree formatters next to each other",
+    "color: red", "background: red", "font-size: 150%");
+  top.console.log("%c%cTwo formatters%cWith a third separated",
+    "color: red", "background: red", "font-size: 150%");
+  top.console.log("%cOne formatter", "color: red",
+                  "Second arg with no styles");
+  top.console.log("%cOne formatter", "color: red",
+                  "%cSecond formatter is ignored", "background: blue")
+
+  expectedConsoleCalls = [
+    {
+      level: "log",
+      styles: /^$/,
+      arguments: ["%cOne formatter with no styles"],
+    },
+    {
+      level: "log",
+      styles: /^color: red$/,
+      arguments: ["One formatter"],
+    },
+    {
+      level: "log",
+      styles: /^color: red,background: red$/,
+      arguments: ["Two formatters", "Each with an arg"],
+    },
+    {
+      level: "log",
+      styles: /^background: red$/,
+      arguments: ["Two formatters next to each other"],
+    },
+    {
+      level: "log",
+      styles: /^font-size: 150%$/,
+      arguments: ["Three formatters next to each other"],
+    },
+    {
+      level: "log",
+      styles: /^background: red,font-size: 150%$/,
+      arguments: ["Two formatters", "With a third separated"],
+    },
+    {
+      level: "log",
+      styles: /^color: red$/,
+      arguments: ["One formatter", "Second arg with no styles"],
+    },
+    {
+      level: "log",
+      styles: /^color: red$/,
+      arguments: ["One formatter",
+                  "%cSecond formatter is ignored",
+                  "background: blue"],
+    },
+  ];
+}
+
+function startTest()
+{
+  removeEventListener("load", startTest);
+
+  attachConsole(["ConsoleAPI"], onAttach, true);
+}
+
+function onAttach(aState, aResponse)
+{
+  onConsoleAPICall = onConsoleAPICall.bind(null, aState);
+  aState.dbgClient.addListener("consoleAPICall", onConsoleAPICall);
+  doConsoleCalls(aState.actor);
+}
+
+let consoleCalls = [];
+
+function onConsoleAPICall(aState, aType, aPacket)
+{
+  info("received message level: " + aPacket.message.level);
+  is(aPacket.from, aState.actor, "console API call actor");
+
+  consoleCalls.push(aPacket.message);
+  if (consoleCalls.length != expectedConsoleCalls.length) {
+    return;
+  }
+
+  aState.dbgClient.removeListener("consoleAPICall", onConsoleAPICall);
+
+  expectedConsoleCalls.forEach(function(aMessage, aIndex) {
+    info("checking received console call #" + aIndex);
+    checkConsoleAPICall(consoleCalls[aIndex], expectedConsoleCalls[aIndex]);
+  });
+
+
+  consoleCalls = [];
+
+  closeDebugger(aState, function() {
+    SimpleTest.finish();
+  });
+}
+
+addEventListener("load", startTest);
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_bug1180901_2.js
@@ -0,0 +1,60 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function run_test() {
+  createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
+  startupManager();
+  run_next_test();
+}
+
+add_task(function* () {
+  let profileDir = OS.Constants.Path.profileDir;
+  let trashDir = OS.Path.join(profileDir, "extensions", "trash");
+  let testFile = OS.Path.join(trashDir, "test.txt");
+
+  yield OS.File.makeDir(trashDir, {
+    from: profileDir,
+    ignoreExisting: true
+  });
+
+  let trashDirExists = yield OS.File.exists(trashDir);
+  ok(trashDirExists, "trash directory should have been created");
+
+  let file = yield OS.File.open(testFile, {create: true}, {winShare: 0});
+  let fileExists = yield OS.File.exists(testFile);
+  ok(fileExists, "test.txt should have been created in " + trashDir);
+
+  let promiseInstallStatus = new Promise((resolve, reject) => {
+    let listener = {
+      onInstallFailed: function() {
+        AddonManager.removeInstallListener(listener);
+        reject("extension installation should not have failed");
+      },
+      onInstallEnded: function() {
+        AddonManager.removeInstallListener(listener);
+        ok(true, "extension installation should not have failed");
+        resolve();
+      }
+    };
+
+    AddonManager.addInstallListener(listener);
+  });
+
+  yield promiseInstallAllFiles([do_get_addon("test_bootstrap1_1")]);
+
+  // The testFile should still exist at this point because we have not
+  // yet closed the file handle and as a result, Windows cannot remove it.
+  fileExists = yield OS.File.exists(testFile);
+  ok(fileExists, "test.txt should still exist");
+
+  // Wait for the AddonManager to tell us if the installation of the extension
+  // succeeded or not.
+  yield promiseInstallStatus;
+
+  // Cleanup
+  yield promiseShutdownManager();
+  yield file.close();
+  yield OS.File.remove(testFile);
+  yield OS.File.removeDir(trashDir);
+});
--- a/toolkit/mozapps/extensions/test/xpcshell/xpcshell-shared.ini
+++ b/toolkit/mozapps/extensions/test/xpcshell/xpcshell-shared.ini
@@ -289,10 +289,12 @@ run-sequentially = Uses global XCurProcD
 # Bug 676992: test consistently hangs on Android
 skip-if = os == "android"
 run-sequentially = Uses global XCurProcD dir.
 [test_overrideblocklist.js]
 run-sequentially = Uses global XCurProcD dir.
 [test_sourceURI.js]
 [test_webextension.js]
 [test_bootstrap_globals.js]
+[test_bug1180901_2.js]
+skip-if = os != "win"
 [test_bug1180901.js]
 skip-if = os != "win"
--- a/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
+++ b/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
@@ -25,9 +25,10 @@ skip-if = appname != "firefox"
 [test_provider_unsafe_access_startup.js]
 [test_shutdown.js]
 [test_system_reset.js]
 [test_XPIcancel.js]
 [test_XPIStates.js]
 
 
 
+
 [include:xpcshell-shared.ini]