Merge central->date
authorJustin Wood <Callek@gmail.com>
Mon, 14 Nov 2016 09:12:50 -0500
changeset 439910 d898b8d228afefbf2cc7933c89827859f4925bf2
parent 439909 9c16a1693a53854677878a906b4017aca724e634 (current diff)
parent 438410 a516c754042c438a5c1499171ca525a980ecb911 (diff)
child 439911 c81db640f5ad4b58c2d929ce57dd01bb2bac39ab
push id36120
push userCallek@gmail.com
push dateWed, 16 Nov 2016 18:58:20 +0000
milestone53.0a1
Merge central->date MozReview-Commit-ID: 5dhOTFW7abk
browser/base/content/test/general/browser_aboutTabCrashed.js
browser/base/content/test/general/browser_aboutTabCrashed_clearEmail.js
browser/base/content/test/general/browser_aboutTabCrashed_showForm.js
browser/base/content/test/general/browser_aboutTabCrashed_withoutDump.js
devtools/client/inspector/inspector.js
devtools/client/inspector/shared/style-inspector-overlays.js
dom/inputport/AVInputPort.cpp
dom/inputport/AVInputPort.h
dom/inputport/DisplayPortInputPort.cpp
dom/inputport/DisplayPortInputPort.h
dom/inputport/FakeInputPortService.cpp
dom/inputport/FakeInputPortService.h
dom/inputport/HDMIInputPort.cpp
dom/inputport/HDMIInputPort.h
dom/inputport/InputPort.cpp
dom/inputport/InputPort.h
dom/inputport/InputPortData.cpp
dom/inputport/InputPortData.h
dom/inputport/InputPortListeners.cpp
dom/inputport/InputPortListeners.h
dom/inputport/InputPortManager.cpp
dom/inputport/InputPortManager.h
dom/inputport/InputPortServiceFactory.cpp
dom/inputport/InputPortServiceFactory.h
dom/inputport/moz.build
dom/inputport/nsIInputPortService.idl
dom/inputport/test/mochitest/mochitest.ini
dom/inputport/test/mochitest/test_inputport_connection_event.html
dom/inputport/test/mochitest/test_inputport_get_inputports.html
dom/inputport/test/xpcshell/test_inputport_data.js
dom/inputport/test/xpcshell/xpcshell.ini
dom/media/ogg/OggReader.cpp
dom/media/ogg/OggReader.h
dom/media/wave/WaveReader.cpp
dom/media/wave/WaveReader.h
dom/webidl/AVInputPort.webidl
dom/webidl/DisplayPortInputPort.webidl
dom/webidl/HDMIInputPort.webidl
dom/webidl/InputPort.webidl
dom/webidl/InputPortManager.webidl
hal/fallback/FallbackFMRadio.cpp
hal/gonk/GonkFMRadio.cpp
js/src/wasm/WasmBinary.cpp
js/src/wasm/WasmBinary.h
layout/reftests/w3c-css/received/css-conditional-3/background-lime.html
layout/reftests/w3c-css/received/css-multicol-1/multicol-basic-ref.html
layout/reftests/w3c-css/received/css-multicol-1/ref-filled-green-100px-square.xht
layout/reftests/w3c-css/received/css-namespaces-3/ref-lime-1-block.xml
layout/reftests/w3c-css/received/css-namespaces-3/ref-lime-1-generic.xml
layout/reftests/w3c-css/received/css-namespaces-3/ref-lime-1.xml
layout/reftests/w3c-css/received/css-namespaces-3/ref-lime-2-generic.xml
layout/reftests/w3c-css/received/css-namespaces-3/ref-lime-2.xml
layout/reftests/w3c-css/received/css-namespaces-3/ref-lime-3.xml
layout/reftests/w3c-css/received/css-namespaces-3/ref-lime-5.xml
layout/reftests/w3c-css/received/css-namespaces-3/ref-lime-6.xml
layout/reftests/w3c-css/received/css-values-3/200-200-green.html
layout/reftests/w3c-css/received/css-values-3/all-green.html
layout/reftests/w3c-css/received/css-values-3/ch-unit-001-ref.html
layout/reftests/w3c-css/received/css-values-3/vh_not_refreshing_on_chrome-ref.html
other-licenses/ia2/ia2_api_all.idl
security/manager/ssl/tests/compiled/TestCertDB.cpp
security/manager/ssl/tests/compiled/TestIsCertBuiltInRoot.cpp
security/manager/ssl/tests/compiled/TestSTSParser.cpp
security/manager/ssl/tests/compiled/moz.build
taskcluster/ci/build/android.yml
taskcluster/taskgraph/transforms/task.py
testing/docker/image_builder/bin/build_image.sh
testing/marionette/harness/session/__init__.py
testing/marionette/harness/session/runner/__init__.py
testing/marionette/harness/session/runner/base.py
testing/marionette/harness/session/runner/ping_server.py
testing/marionette/harness/session/runtests.py
testing/marionette/harness/session/session_test.py
testing/marionette/harness/session/tests/test_session.py
testing/marionette/harness/session/tests/unit-tests.ini
testing/mozharness/configs/builds/branch_specifics.py
testing/web-platform/meta/html/semantics/forms/constraints/form-validation-validity-valueMissing.html.ini
testing/xpcshell/b2g_xpcshell_venv.sh
testing/xpcshell/runtestsb2g.py
toolkit/components/extensions/ext-test.js
toolkit/components/extensions/test/mochitest/file_WebRequest_page1.html
toolkit/components/extensions/test/mochitest/file_WebRequest_page2.html
toolkit/components/extensions/test/mochitest/test_ext_webrequest.html
toolkit/components/places/tests/network/.eslintrc.js
toolkit/components/places/tests/network/head_network.js
toolkit/components/places/tests/network/test_history_redirects.js
toolkit/components/places/tests/network/xpcshell.ini
toolkit/mozapps/downloads/content/helperApps.js
widget/nsIPrintOptions.idl
xpcom/reflect/xptcall/tests/TestXPTCInvoke.cpp
xpcom/reflect/xptcall/tests/moz.build
xpcom/reflect/xptinfo/tests/TestInterfaceInfo.cpp
xpcom/reflect/xptinfo/tests/moz.build
xpcom/tests/TestBase64.cpp
xpcom/tests/TestCallTemplates.cpp
xpcom/tests/TestDeadlockDetector.cpp
xpcom/tests/TestDeadlockDetectorScalability.cpp
xpcom/tests/TestINIParser.cpp
xpcom/tests/TestJemalloc.cpp
xpcom/tests/TestRacingServiceManager.cpp
xpcom/tests/TestRegistrationOrder.cpp
xpcom/tests/TestSTLWrappers.cpp
xpcom/tests/TestThreadPoolListener.cpp
xpcom/tests/TestTimers.cpp
xpcom/tests/nsIFileEnumerator.cpp
xpcom/tests/regorder/core/component.js
xpcom/tests/regorder/core/component.manifest
xpcom/tests/regorder/core/component2.js
xpcom/tests/regorder/extension/extComponent.js
xpcom/tests/regorder/extension/extComponent.manifest
xpcom/tests/regorder/extension2.jar
--- a/.eslintignore
+++ b/.eslintignore
@@ -75,36 +75,30 @@ browser/extensions/pdfjs/**
 browser/extensions/pocket/content/panels/js/tmpl.js
 browser/extensions/pocket/content/panels/js/vendor/**
 browser/locales/**
 
 # devtools/ exclusions
 devtools/client/canvasdebugger/**
 devtools/client/commandline/**
 devtools/client/debugger/**
-devtools/client/eyedropper/**
 devtools/client/framework/**
 !devtools/client/framework/selection.js
 !devtools/client/framework/toolbox.js
 devtools/client/jsonview/lib/**
 devtools/client/memory/**
 devtools/client/netmonitor/test/**
 devtools/client/netmonitor/har/test/**
 devtools/client/projecteditor/**
 devtools/client/promisedebugger/**
 devtools/client/responsivedesign/**
 devtools/client/scratchpad/**
 devtools/client/shadereditor/**
 devtools/client/shared/*.jsm
 devtools/client/shared/webgl-utils.js
-devtools/client/shared/developer-toolbar.js
-devtools/client/shared/components/test/**
-devtools/client/shared/redux/middleware/test/**
-devtools/client/shared/test/**
-!devtools/client/shared/test/test-actor-registry.js
 devtools/client/shared/widgets/*.jsm
 devtools/client/sourceeditor/test/*.js
 devtools/client/webaudioeditor/**
 devtools/client/webconsole/**
 !devtools/client/webconsole/panel.js
 !devtools/client/webconsole/jsterm.js
 !devtools/client/webconsole/console-commands.js
 devtools/client/webide/**
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -1,14 +1,14 @@
 "use strict";
 
 module.exports = {
   // When adding items to this file please check for effects on sub-directories.
   "plugins": [
     "mozilla"
   ],
   "rules": {
-    "mozilla/import-globals": 1,
+    "mozilla/import-globals": "warn",
   },
   "env": {
     "es6": true
   },
 };
--- a/.hgtags
+++ b/.hgtags
@@ -124,8 +124,9 @@ fcef8ded82219c89298b4e376cfbdfba79a1d35a
 67a788db9f07822cfef52351bbbe3745dff8bd7f FIREFOX_AURORA_44_BASE
 99137d6d4061f408ae0869122649d8bdf489cc30 FIREFOX_AURORA_45_BASE
 67c66c2878aed17ae3096d7db483ddbb2293c503 FIREFOX_AURORA_46_BASE
 68d3781deda0d4d58ec9877862830db89669b3a5 FIREFOX_AURORA_47_BASE
 1c6385ae1fe7e37d8f23f958ce14582f07af729e FIREFOX_AURORA_48_BASE
 d98f20c25feeac4dd7ebbd1c022957df1ef58af4 FIREFOX_AURORA_49_BASE
 465d150bc8be5bbf9f02a8607d4552b6a5e1697c FIREFOX_AURORA_50_BASE
 fc69febcbf6c0dcc4b3dfc7a346d8d348798a65f FIREFOX_AURORA_51_BASE
+1196bf3032e1bce1fb07a01fd9082a767426c5fb FIREFOX_AURORA_52_BASE
--- a/.taskcluster.yml
+++ b/.taskcluster.yml
@@ -114,16 +114,12 @@ tasks:
               --head-rev='{{revision}}'
               --revision-hash='{{revision_hash}}'
 
         artifacts:
           'public':
             type: 'directory'
             path: '/home/worker/artifacts'
             expires: '{{#from_now}}364 days{{/from_now}}'
-          'public/docker_image_contexts':
-            type: 'directory'
-            path: '/home/worker/docker_image_contexts'
-            expires: '{{#from_now}}7 days{{/from_now}}'
 
       extra:
         treeherder:
           symbol: D
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 1277704 - jemalloc may need a clobber
+Merge day clobber
\ No newline at end of file
--- a/accessible/interfaces/ia2/IA2Typelib.idl
+++ b/accessible/interfaces/ia2/IA2Typelib.idl
@@ -27,11 +27,35 @@ typedef [wire_marshal(mozHACCEL)] void* 
 typedef [wire_marshal(mozHBRUSH)] void* HBRUSH;
 typedef [wire_marshal(mozHFONT)] void* HFONT;
 typedef [wire_marshal(mozHDC)] void* HDC;
 typedef [wire_marshal(mozHICON)] void* HICON;
 typedef [wire_marshal(mozHRGN)] void* HRGN;
 typedef [wire_marshal(mozHMONITOR)] void* HMONITOR;
 cpp_quote("#endif // 0")
 
+import "Accessible2.idl";
+import "Accessible2_2.idl";
+import "Accessible2_3.idl";
+import "AccessibleAction.idl";
+import "AccessibleApplication.idl";
+import "AccessibleComponent.idl";
+import "AccessibleDocument.idl";
+import "AccessibleEditableText.idl";
+import "AccessibleEventId.idl";
+import "AccessibleHyperlink.idl";
+import "AccessibleHypertext.idl";
+import "AccessibleHypertext2.idl";
+import "AccessibleImage.idl";
+import "AccessibleRelation.idl";
+import "AccessibleRole.idl";
+import "AccessibleStates.idl";
+import "AccessibleTable.idl";
+import "AccessibleTable2.idl";
+import "AccessibleTableCell.idl";
+import "AccessibleText.idl";
+import "AccessibleText2.idl";
+import "AccessibleValue.idl";
+import "IA2CommonTypes.idl";
+
 // We are explicitly using #include instead of import so that the imported
 // IDL is treated as part of this IDL file.
-#include "ia2_api_all.idl"
+#include "IA2TypeLibrary.idl"
--- a/accessible/tests/browser/.eslintrc.js
+++ b/accessible/tests/browser/.eslintrc.js
@@ -46,173 +46,173 @@ module.exports = { // eslint-disable-lin
     "waitForEvent": true,
     "waitForMultipleEvents": true,
     "invokeSetAttribute": true,
     "invokeSetStyle": true,
     "invokeFocus": true,
     "findAccessibleChildByID": true
   },
   "rules": {
-    "mozilla/no-aArgs": 1,
-    "mozilla/no-cpows-in-tests": 1,
-    "mozilla/reject-importGlobalProperties": 1,
-    "mozilla/var-only-at-top-level": 1,
+    "mozilla/no-aArgs": "warn",
+    "mozilla/no-cpows-in-tests": "warn",
+    "mozilla/reject-importGlobalProperties": "warn",
+    "mozilla/var-only-at-top-level": "warn",
 
-    "block-scoped-var": 2,
-    "brace-style": [2, "1tbs"],
-    "camelcase": 2,
-    "comma-dangle": [2, "never"],
-    "comma-spacing": 2,
-    "comma-style": [2, "last"],
-    "complexity": [2, 35],
-    "consistent-this": 0,
-    "curly": [2, "multi-line"],
-    "default-case": 0,
-    "dot-location": [2, "property"],
-    "dot-notation": 2,
-    "eol-last": 2,
-    "eqeqeq": 0,
-    "func-names": 0,
-    "func-style": 0,
-    "generator-star": 0,
-    "global-strict": 0,
-    "handle-callback-err": [2, "er"],
-    "indent": [2, 2, {"SwitchCase": 1}],
-    "key-spacing": [2, {"beforeColon": false, "afterColon": true}],
-    "linebreak-style": 0,
-    "max-depth": 0,
-    "max-nested-callbacks": [2, 4],
-    "max-params": 0,
-    "max-statements": 0,
-    "new-cap": [2, {"capIsNew": false}],
-    "new-parens": 2,
-    "no-array-constructor": 2,
-    "no-bitwise": 0,
-    "no-caller": 2,
-    "no-catch-shadow": 2,
-    "no-comma-dangle": 0,
-    "no-cond-assign": 2,
-    "no-console": 0,
-    "no-constant-condition": 0,
-    "no-continue": 0,
-    "no-control-regex": 2,
-    "no-debugger": 2,
-    "no-delete-var": 2,
-    "no-div-regex": 0,
-    "no-dupe-args": 2,
-    "no-dupe-keys": 2,
-    "no-duplicate-case": 2,
-    "no-else-return": 2,
-    "no-empty": 2,
-    "no-empty-character-class": 2,
-    "no-eval": 2,
-    "no-ex-assign": 2,
-    "no-extend-native": 2,
-    "no-extra-bind": 2,
-    "no-extra-boolean-cast": 2,
-    "no-extra-parens": 0,
-    "no-extra-semi": 2,
-    "no-extra-strict": 0,
-    "no-fallthrough": 2,
-    "no-floating-decimal": 0,
-    "no-inline-comments": 0,
-    "no-lonely-if": 2,
-    "no-mixed-requires": 0,
-    "no-mixed-spaces-and-tabs": 2,
-    "no-multi-spaces": 2,
-    "no-multi-str": 2,
-    "no-multiple-empty-lines": [2, {"max": 1}],
-    "no-native-reassign": 2,
-    "no-nested-ternary": 2,
-    "no-new-require": 0,
-    "no-octal": 2,
-    "no-param-reassign": 0,
-    "no-path-concat": 0,
-    "no-plusplus": 0,
-    "no-process-env": 0,
-    "no-process-exit": 0,
-    "no-proto": 2,
-    "no-redeclare": 2,
-    "no-regex-spaces": 2,
-    "no-reserved-keys": 0,
-    "no-restricted-modules": 0,
-    "no-return-assign": 1,
-    "no-script-url": 0,
-    "no-self-compare": 2,
-    "no-sequences": 2,
-    "no-shadow": 1,
-    "no-shadow-restricted-names": 2,
-    "no-space-before-semi": 0,
-    "no-spaced-func": 2,
-    "no-sparse-arrays": 2,
-    "no-sync": 0,
-    "no-ternary": 0,
-    "no-throw-literal": 2,
-    "no-trailing-spaces": 2,
-    "no-undef": 2,
-    "no-underscore-dangle": 0,
-    "no-undefined": 0,
-    "no-unneeded-ternary": 2,
-    "no-unreachable": 2,
-    "no-unused-vars": [2, {"vars": "all", "args": "none"}],
-    "no-use-before-define": 0,
-    "no-var": 0,
-    "no-warning-comments": 0,
-    "no-with": 2,
-    "object-shorthand": 0,
-    "one-var": [2, "never"],
-    "padded-blocks": [2, "never"],
-    "quote-props": 0,
-    "radix": 2,
-    "semi": [2, "always"],
-    "semi-spacing": [2, {"before": false, "after": true}],
-    "sort-vars": 0,
-    "space-after-function-name": 0,
-    "keyword-spacing": 2,
-    "space-before-blocks": 2,
-    "space-before-function-parentheses": 0,
-    "space-before-function-paren": [2, "never"],
-    "space-in-brackets": 0,
-    "space-in-parens": [2, "never"],
-    "space-infix-ops": [2, {"int32Hint": true}],
-    "space-unary-ops": [2, { "words": true, "nonwords": false }],
-    "space-unary-word-ops": 0,
-    "spaced-comment": [2, "always"],
-    "strict": [2, "global"],
-    "use-isnan": 2,
-    "valid-jsdoc": 0,
-    "valid-typeof": 2,
-    "vars-on-top": 0,
-    "wrap-iife": 0,
-    "wrap-regex": 0,
-    "yoda": 2,
+    "block-scoped-var": "error",
+    "brace-style": ["error", "1tbs"],
+    "camelcase": "error",
+    "comma-dangle": ["error", "never"],
+    "comma-spacing": "error",
+    "comma-style": ["error", "last"],
+    "complexity": ["error", 35],
+    "consistent-this": "off",
+    "curly": ["error", "multi-line"],
+    "default-case": "off",
+    "dot-location": ["error", "property"],
+    "dot-notation": "error",
+    "eol-last": "error",
+    "eqeqeq": "off",
+    "func-names": "off",
+    "func-style": "off",
+    "generator-star": "off",
+    "global-strict": "off",
+    "handle-callback-err": ["error", "er"],
+    "indent": ["error", 2, {"SwitchCase": 1}],
+    "key-spacing": ["error", {"beforeColon": false, "afterColon": true}],
+    "linebreak-style": "off",
+    "max-depth": "off",
+    "max-nested-callbacks": ["error", 4],
+    "max-params": "off",
+    "max-statements": "off",
+    "new-cap": ["error", {"capIsNew": false}],
+    "new-parens": "error",
+    "no-array-constructor": "error",
+    "no-bitwise": "off",
+    "no-caller": "error",
+    "no-catch-shadow": "error",
+    "no-comma-dangle": "off",
+    "no-cond-assign": "error",
+    "no-console": "off",
+    "no-constant-condition": "off",
+    "no-continue": "off",
+    "no-control-regex": "error",
+    "no-debugger": "error",
+    "no-delete-var": "error",
+    "no-div-regex": "off",
+    "no-dupe-args": "error",
+    "no-dupe-keys": "error",
+    "no-duplicate-case": "error",
+    "no-else-return": "error",
+    "no-empty": "error",
+    "no-empty-character-class": "error",
+    "no-eval": "error",
+    "no-ex-assign": "error",
+    "no-extend-native": "error",
+    "no-extra-bind": "error",
+    "no-extra-boolean-cast": "error",
+    "no-extra-parens": "off",
+    "no-extra-semi": "error",
+    "no-extra-strict": "off",
+    "no-fallthrough": "error",
+    "no-floating-decimal": "off",
+    "no-inline-comments": "off",
+    "no-lonely-if": "error",
+    "no-mixed-requires": "off",
+    "no-mixed-spaces-and-tabs": "error",
+    "no-multi-spaces": "error",
+    "no-multi-str": "error",
+    "no-multiple-empty-lines": ["error", {"max": 1}],
+    "no-native-reassign": "error",
+    "no-nested-ternary": "error",
+    "no-new-require": "off",
+    "no-octal": "error",
+    "no-param-reassign": "off",
+    "no-path-concat": "off",
+    "no-plusplus": "off",
+    "no-process-env": "off",
+    "no-process-exit": "off",
+    "no-proto": "error",
+    "no-redeclare": "error",
+    "no-regex-spaces": "error",
+    "no-reserved-keys": "off",
+    "no-restricted-modules": "off",
+    "no-return-assign": "error",
+    "no-script-url": "off",
+    "no-self-compare": "error",
+    "no-sequences": "error",
+    "no-shadow": "error",
+    "no-shadow-restricted-names": "error",
+    "no-space-before-semi": "off",
+    "no-spaced-func": "error",
+    "no-sparse-arrays": "error",
+    "no-sync": "off",
+    "no-ternary": "off",
+    "no-throw-literal": "error",
+    "no-trailing-spaces": "error",
+    "no-undef": "error",
+    "no-underscore-dangle": "off",
+    "no-undefined": "off",
+    "no-unneeded-ternary": "error",
+    "no-unreachable": "error",
+    "no-unused-vars": ["error", {"vars": "all", "args": "none"}],
+    "no-use-before-define": "off",
+    "no-var": "off",
+    "no-warning-comments": "off",
+    "no-with": "error",
+    "object-shorthand": "off",
+    "one-var": ["error", "never"],
+    "padded-blocks": ["error", "never"],
+    "quote-props": "off",
+    "radix": "error",
+    "semi": ["error", "always"],
+    "semi-spacing": ["error", {"before": false, "after": true}],
+    "sort-vars": "off",
+    "space-after-function-name": "off",
+    "keyword-spacing": "error",
+    "space-before-blocks": "error",
+    "space-before-function-parentheses": "off",
+    "space-before-function-paren": ["error", "never"],
+    "space-in-brackets": "off",
+    "space-in-parens": ["error", "never"],
+    "space-infix-ops": ["error", {"int32Hint": true}],
+    "space-unary-ops": ["error", { "words": true, "nonwords": false }],
+    "space-unary-word-ops": "off",
+    "spaced-comment": ["error", "always"],
+    "strict": ["error", "global"],
+    "use-isnan": "error",
+    "valid-jsdoc": "off",
+    "valid-typeof": "error",
+    "vars-on-top": "off",
+    "wrap-iife": "off",
+    "wrap-regex": "off",
+    "yoda": "error",
 
-    "guard-for-in": 0,
-    "newline-after-var": 0,
-    "no-alert": 0,
-    "no-eq-null": 0,
-    "no-func-assign": 0,
-    "no-implied-eval": 0,
-    "no-inner-declarations": 0,
-    "no-invalid-regexp": 0,
-    "no-irregular-whitespace": 0,
-    "no-iterator": 0,
-    "no-label-var": 0,
-    "no-labels": 2,
-    "no-lone-blocks": 0,
-    "no-loop-func": 0,
-    "no-negated-in-lhs": 0,
-    "no-new": 0,
-    "no-new-func": 0,
-    "no-new-object": 0,
-    "no-new-wrappers": 0,
-    "no-obj-calls": 0,
-    "no-octal-escape": 0,
-    "no-undef-init": 2,
-    "no-unexpected-multiline": 2,
-    "object-curly-spacing": 0,
-    "no-unused-expressions": 0,
-    "no-void": 0,
-    "no-wrap-func": 0,
-    "operator-assignment": 0,
-    "operator-linebreak": [2, "after"]
+    "guard-for-in": "off",
+    "newline-after-var": "off",
+    "no-alert": "off",
+    "no-eq-null": "off",
+    "no-func-assign": "off",
+    "no-implied-eval": "off",
+    "no-inner-declarations": "off",
+    "no-invalid-regexp": "off",
+    "no-irregular-whitespace": "off",
+    "no-iterator": "off",
+    "no-label-var": "off",
+    "no-labels": "error",
+    "no-lone-blocks": "off",
+    "no-loop-func": "off",
+    "no-negated-in-lhs": "off",
+    "no-new": "off",
+    "no-new-func": "off",
+    "no-new-object": "off",
+    "no-new-wrappers": "off",
+    "no-obj-calls": "off",
+    "no-octal-escape": "off",
+    "no-undef-init": "error",
+    "no-unexpected-multiline": "error",
+    "object-curly-spacing": "off",
+    "no-unused-expressions": "off",
+    "no-void": "off",
+    "no-wrap-func": "off",
+    "operator-assignment": "off",
+    "operator-linebreak": ["error", "after"]
   }
 };
--- a/accessible/tests/browser/e10s/browser_events_statechange.js
+++ b/accessible/tests/browser/e10s/browser_events_statechange.js
@@ -36,25 +36,27 @@ let iframeSrc = `data:text/html,
  *   - isEnabled
  */
 addAccessibleTask(`
   <iframe id="iframe" src="${iframeSrc}"></iframe>
   <input id="checkbox" type="checkbox" />`, function*(browser) {
   // Test state change
   let onStateChange = waitForEvent(EVENT_STATE_CHANGE, 'checkbox');
   // Set checked for a checkbox.
-  yield ContentTask.spawn(browser, {}, () =>
-    content.document.getElementById('checkbox').checked = true);
+  yield ContentTask.spawn(browser, {}, () => {
+    content.document.getElementById('checkbox').checked = true;
+  });
   let event = yield onStateChange;
 
   checkStateChangeEvent(event, STATE_CHECKED, false, true);
   testStates(event.accessible, STATE_CHECKED, 0);
 
   // Test extra state
   onStateChange = waitForEvent(EVENT_STATE_CHANGE, 'iframe');
   // Set design mode on.
-  yield ContentTask.spawn(browser, {}, () =>
-    content.document.getElementById('iframe').contentDocument.designMode = 'on');
+  yield ContentTask.spawn(browser, {}, () => {
+    content.document.getElementById('iframe').contentDocument.designMode = 'on';
+  });
   event = yield onStateChange;
 
   checkStateChangeEvent(event, EXT_STATE_EDITABLE, true, true);
   testStates(event.accessible, 0, EXT_STATE_EDITABLE);
 });
--- a/accessible/tests/browser/e10s/browser_events_textchange.js
+++ b/accessible/tests/browser/e10s/browser_events_textchange.js
@@ -19,32 +19,34 @@ function checkTextChangeEvent(event, id,
 }
 
 function* changeText(browser, id, value, events) {
   let onEvents = waitForMultipleEvents(events.map(({ isInserted }) => {
     let eventType = isInserted ? EVENT_TEXT_INSERTED : EVENT_TEXT_REMOVED;
     return { id, eventType };
   }));
   // Change text in the subtree.
-  yield ContentTask.spawn(browser, { id, value }, ({ id, value }) =>
-    content.document.getElementById(id).firstChild.textContent = value);
+  yield ContentTask.spawn(browser, [id, value], ([contentId, contentValue]) => {
+    content.document.getElementById(contentId).firstChild.textContent =
+      contentValue;
+  });
   let resolvedEvents = yield onEvents;
 
   events.forEach(({ isInserted, str, offset }, idx) =>
     checkTextChangeEvent(resolvedEvents[idx],
       id, str, offset, offset + str.length, isInserted, false));
 }
 
 function* removeTextFromInput(browser, id, value, start, end) {
   let onTextRemoved = waitForEvent(EVENT_TEXT_REMOVED, id);
   // Select text and delete it.
-  yield ContentTask.spawn(browser, { id, start, end }, ({ id, start, end }) => {
-    let el = content.document.getElementById(id);
+  yield ContentTask.spawn(browser, [id, start, end], ([contentId, contentStart, contentEnd]) => {
+    let el = content.document.getElementById(contentId);
     el.focus();
-    el.setSelectionRange(start, end);
+    el.setSelectionRange(contentStart, contentEnd);
   });
   yield BrowserTestUtils.sendChar('VK_DELETE', browser);
 
   let event = yield onTextRemoved;
   checkTextChangeEvent(event, id, value, start, end, false, true);
 }
 
 /**
--- a/accessible/tests/browser/e10s/browser_treeupdate_ariadialog.js
+++ b/accessible/tests/browser/e10s/browser_treeupdate_ariadialog.js
@@ -13,18 +13,19 @@ loadScripts({ name: 'role.js', dir: MOCH
 addAccessibleTask('doc_treeupdate_ariadialog.html', function*(browser, accDoc) {
   testAccessibleTree(accDoc, {
     role: ROLE_DOCUMENT,
     children: [ ]
   });
 
   // Make dialog visible and update its inner content.
   let onShow = waitForEvent(EVENT_SHOW, 'dialog');
-  yield ContentTask.spawn(browser, {}, () =>
-    content.document.getElementById('dialog').style.display = 'block');
+  yield ContentTask.spawn(browser, {}, () => {
+    content.document.getElementById('dialog').style.display = 'block';
+  });
   yield onShow;
 
   testAccessibleTree(accDoc, {
     role: ROLE_DOCUMENT,
     children: [
       {
         role: ROLE_DIALOG,
         children: [
--- a/accessible/tests/browser/e10s/browser_treeupdate_ariaowns.js
+++ b/accessible/tests/browser/e10s/browser_treeupdate_ariaowns.js
@@ -88,21 +88,21 @@ function* testContainer1(browser, accDoc
       { SECTION: [ ] }, // subdiv from the subtree, t1_subdiv
       { GROUPING: [ ] } // group from outside, t1_group
     ]
   };
   testAccessibleTree(acc, tree);
 
   /* ================ Append element ======================================== */
   onReorder = waitForEvent(EVENT_REORDER, id);
-  yield ContentTask.spawn(browser, id, id => {
+  yield ContentTask.spawn(browser, id, contentId => {
     let div = content.document.createElement('div');
     div.setAttribute('id', 't1_child3');
     div.setAttribute('role', 'radio');
-    content.document.getElementById(id).appendChild(div);
+    content.document.getElementById(contentId).appendChild(div);
   });
   yield onReorder;
 
   // children are invalidated, they includes aria-owns swapped kids and
   // newly inserted child.
   tree = {
     SECTION: [
       { CHECKBUTTON: [ ] }, // existing explicit, t1_checkbox
@@ -289,19 +289,20 @@ function* removeNotARIAOwnedEl(browser, 
     SECTION: [
       { TEXT_LEAF: [ ] },
       { GROUPING: [ ] }
     ]
   };
   testAccessibleTree(acc, tree);
 
   let onReorder = waitForEvent(EVENT_REORDER, id);
-  yield ContentTask.spawn(browser, id, id =>
-    content.document.getElementById(id).removeChild(
-      content.document.getElementById('t6_span')));
+  yield ContentTask.spawn(browser, id, contentId => {
+    content.document.getElementById(contentId).removeChild(
+      content.document.getElementById('t6_span'));
+  });
   yield onReorder;
 
   tree = {
     SECTION: [
       { GROUPING: [ ] }
     ]
   };
   testAccessibleTree(acc, tree);
--- a/accessible/tests/browser/e10s/browser_treeupdate_doc.js
+++ b/accessible/tests/browser/e10s/browser_treeupdate_doc.js
@@ -29,22 +29,22 @@ addAccessibleTask(`
   let tree = {
     role: ROLE_DOCUMENT,
     children: [ ]
   };
   testAccessibleTree(iframe, tree);
 
   /* ================= Write iframe document ================================ */
   let reorderEventPromise = waitForEvent(EVENT_REORDER, id);
-  yield ContentTask.spawn(browser, id, id => {
+  yield ContentTask.spawn(browser, id, contentId => {
     let docNode = content.document.getElementById('iframe').contentDocument;
     let newHTMLNode = docNode.createElement('html');
     let newBodyNode = docNode.createElement('body');
     let newTextNode = docNode.createTextNode('New Wave');
-    newBodyNode.id = id;
+    newBodyNode.id = contentId;
     newBodyNode.appendChild(newTextNode);
     newHTMLNode.appendChild(newBodyNode);
     docNode.replaceChild(newHTMLNode, docNode.documentElement);
   });
   yield reorderEventPromise;
 
   tree = {
     role: ROLE_DOCUMENT,
@@ -54,24 +54,24 @@ addAccessibleTask(`
         name: 'New Wave'
       }
     ]
   };
   testAccessibleTree(iframe, tree);
 
   /* ================= Replace iframe HTML element ========================== */
   reorderEventPromise = waitForEvent(EVENT_REORDER, id);
-  yield ContentTask.spawn(browser, id, id => {
+  yield ContentTask.spawn(browser, id, contentId => {
     let docNode = content.document.getElementById('iframe').contentDocument;
     // We can't use open/write/close outside of iframe document because of
     // security error.
     let script = docNode.createElement('script');
     script.textContent = `
       document.open();
-      document.write('<body id="${id}">hello</body>');
+      document.write('<body id="${contentId}">hello</body>');
       document.close();`;
     docNode.body.appendChild(script);
   });
   yield reorderEventPromise;
 
   tree = {
     role: ROLE_DOCUMENT,
     children: [
@@ -80,21 +80,21 @@ addAccessibleTask(`
         name: 'hello'
       }
     ]
   };
   testAccessibleTree(iframe, tree);
 
   /* ================= Replace iframe body ================================== */
   reorderEventPromise = waitForEvent(EVENT_REORDER, id);
-  yield ContentTask.spawn(browser, id, id => {
+  yield ContentTask.spawn(browser, id, contentId => {
     let docNode = content.document.getElementById('iframe').contentDocument;
     let newBodyNode = docNode.createElement('body');
     let newTextNode = docNode.createTextNode('New Hello');
-    newBodyNode.id = id;
+    newBodyNode.id = contentId;
     newBodyNode.appendChild(newTextNode);
     newBodyNode.setAttribute('role', 'button');
     docNode.documentElement.replaceChild(newBodyNode, docNode.body);
   });
   yield reorderEventPromise;
 
   tree = {
     role: ROLE_PUSHBUTTON,
@@ -104,28 +104,28 @@ addAccessibleTask(`
         name: 'New Hello'
       }
     ]
   };
   testAccessibleTree(iframe, tree);
 
   /* ================= Open iframe document ================================= */
   reorderEventPromise = waitForEvent(EVENT_REORDER, id);
-  yield ContentTask.spawn(browser, id, id => {
+  yield ContentTask.spawn(browser, id, contentId => {
     // Open document.
     let docNode = content.document.getElementById('iframe').contentDocument;
     let script = docNode.createElement('script');
     script.textContent = `
       function closeMe() {
         document.write('Works?');
         document.close();
       }
       window.closeMe = closeMe;
       document.open();
-      document.write('<body id="${id}"></body>');`;
+      document.write('<body id="${contentId}"></body>');`;
     docNode.body.appendChild(script);
   });
   yield reorderEventPromise;
 
   tree = {
     role: ROLE_DOCUMENT,
     children: [ ]
   };
@@ -166,24 +166,24 @@ addAccessibleTask(`
   tree = {
     role: ROLE_DOCUMENT,
     children: [ ]
   };
   testAccessibleTree(iframe, tree);
 
   /* ================= Insert HTML to iframe document ======================= */
   reorderEventPromise = waitForEvent(EVENT_REORDER, id);
-  yield ContentTask.spawn(browser, id, id => {
+  yield ContentTask.spawn(browser, id, contentId => {
     // Insert HTML element.
     let docNode = content.document.getElementById('iframe').contentDocument;
     let html = docNode.createElement('html');
     let body = docNode.createElement('body');
     let text = docNode.createTextNode('Haha');
     body.appendChild(text);
-    body.id = id;
+    body.id = contentId;
     html.appendChild(body);
     docNode.appendChild(html);
   });
   yield reorderEventPromise;
 
   tree = {
     role: ROLE_DOCUMENT,
     children: [
@@ -242,24 +242,24 @@ addAccessibleTask(`
   tree = {
     role: ROLE_DOCUMENT,
     children: [ ]
   };
   testAccessibleTree(iframe, tree);
 
   /* ================= Insert body to iframe document ======================= */
   reorderEventPromise = waitForEvent(EVENT_REORDER, id);
-  yield ContentTask.spawn(browser, id, id => {
+  yield ContentTask.spawn(browser, id, contentId => {
     // Write and close document.
     let docNode = content.document.getElementById('iframe').contentDocument;
     // Insert body element.
     let body = docNode.createElement('body');
     let text = docNode.createTextNode('Yo ho ho i butylka roma!');
     body.appendChild(text);
-    body.id = id;
+    body.id = contentId;
     docNode.documentElement.appendChild(body);
   });
   yield reorderEventPromise;
 
   tree = {
     role: ROLE_DOCUMENT,
     children: [
       {
@@ -283,23 +283,23 @@ addAccessibleTask(`
       ] }
     ]
   };
   testAccessibleTree(event.accessible, tree);
   iframe = findAccessibleChildByID(event.accessible, id);
 
   /* ================= Replace iframe body on ARIA role body ================ */
   reorderEventPromise = waitForEvent(EVENT_REORDER, id);
-  yield ContentTask.spawn(browser, id, id => {
+  yield ContentTask.spawn(browser, id, contentId => {
     let docNode = content.document.getElementById('iframe').contentDocument;
     let newBodyNode = docNode.createElement('body');
     let newTextNode = docNode.createTextNode('New Hello');
     newBodyNode.appendChild(newTextNode);
     newBodyNode.setAttribute('role', 'button');
-    newBodyNode.id = id;
+    newBodyNode.id = contentId;
     docNode.documentElement.replaceChild(newBodyNode, docNode.body);
   });
   yield reorderEventPromise;
 
   tree = {
     role: ROLE_PUSHBUTTON,
     children: [
       {
--- a/accessible/tests/browser/e10s/browser_treeupdate_imagemap.js
+++ b/accessible/tests/browser/e10s/browser_treeupdate_imagemap.js
@@ -127,31 +127,31 @@ function* testContainer(browser) {
     SECTION: [
       { GRAPHIC: [ ] }
     ]
   };
   testAccessibleTree(acc, tree);
 
   /* ================= Insert map =========================================== */
   onReorder = waitForEvent(EVENT_REORDER, id);
-  yield ContentTask.spawn(browser, id, id => {
+  yield ContentTask.spawn(browser, id, contentId => {
     let map = content.document.createElement('map');
     let area = content.document.createElement('area');
 
     map.setAttribute('name', 'atoz_map');
     map.setAttribute('id', 'map');
 
     area.setAttribute('href',
                       'http://www.bbc.co.uk/radio4/atoz/index.shtml#b');
     area.setAttribute('coords', '17,0,30,14');
     area.setAttribute('alt', 'b');
     area.setAttribute('shape', 'rect');
 
     map.appendChild(area);
-    content.document.getElementById(id).appendChild(map);
+    content.document.getElementById(contentId).appendChild(map);
   });
   yield onReorder;
 
   tree = {
     SECTION: [ {
       IMAGE_MAP: [
         { LINK: [ ] }
       ]
--- a/accessible/tests/browser/e10s/browser_treeupdate_optgroup.js
+++ b/accessible/tests/browser/e10s/browser_treeupdate_optgroup.js
@@ -10,32 +10,32 @@ loadScripts({ name: 'role.js', dir: MOCH
 
 addAccessibleTask('<select id="select"></select>', function*(browser, accDoc) {
   let select = findAccessibleChildByID(accDoc, 'select');
 
   let onEvent = waitForEvent(EVENT_REORDER, 'select');
   // Create a combobox with grouping and 2 standalone options
   yield ContentTask.spawn(browser, {}, () => {
     let doc = content.document;
-    let select = doc.getElementById('select');
+    let contentSelect = doc.getElementById('select');
     let optGroup = doc.createElement('optgroup');
 
     for (let i = 0; i < 2; i++) {
       let opt = doc.createElement('option');
       opt.value = i;
       opt.text = 'Option: Value ' + i;
       optGroup.appendChild(opt);
     }
-    select.add(optGroup, null);
+    contentSelect.add(optGroup, null);
 
     for (let i = 0; i < 2; i++) {
       let opt = doc.createElement('option');
-      select.add(opt, null);
+      contentSelect.add(opt, null);
     }
-    select.firstChild.firstChild.id = 'option1Node';
+    contentSelect.firstChild.firstChild.id = 'option1Node';
   });
   let event = yield onEvent;
   let option1Node = findAccessibleChildByID(event.accessible, 'option1Node');
 
   let tree = {
     COMBOBOX: [ {
       COMBOBOX_LIST: [ {
         GROUPING: [
@@ -50,18 +50,18 @@ addAccessibleTask('<select id="select"><
     } ]
   };
   testAccessibleTree(select, tree);
   ok(!isDefunct(option1Node), 'option shouldn\'t be defunct');
 
   onEvent = waitForEvent(EVENT_REORDER, 'select');
   // Remove grouping from combobox
   yield ContentTask.spawn(browser, {}, () => {
-    let select = content.document.getElementById('select');
-    select.removeChild(select.firstChild);
+    let contentSelect = content.document.getElementById('select');
+    contentSelect.removeChild(contentSelect.firstChild);
   });
   yield onEvent;
 
   tree = {
     COMBOBOX: [ {
       COMBOBOX_LIST: [
         { COMBOBOX_OPTION: [] },
         { COMBOBOX_OPTION: [] }
@@ -70,19 +70,19 @@ addAccessibleTask('<select id="select"><
   };
   testAccessibleTree(select, tree);
   ok(isDefunct(option1Node),
     'removed option shouldn\'t be accessible anymore!');
 
   onEvent = waitForEvent(EVENT_REORDER, 'select');
   // Remove all options from combobox
   yield ContentTask.spawn(browser, {}, () => {
-    let select = content.document.getElementById('select');
-    while (select.length) {
-      select.remove(0);
+    let contentSelect = content.document.getElementById('select');
+    while (contentSelect.length) {
+      contentSelect.remove(0);
     }
   });
   yield onEvent;
 
   tree = {
     COMBOBOX: [ {
       COMBOBOX_LIST: [ ]
     } ]
--- a/accessible/tests/browser/e10s/browser_treeupdate_textleaf.js
+++ b/accessible/tests/browser/e10s/browser_treeupdate_textleaf.js
@@ -11,18 +11,19 @@ loadScripts({ name: 'role.js', dir: MOCH
 function* removeTextData(browser, accessible, id, role) {
   let tree = {
     role: role,
     children: [ { role: ROLE_TEXT_LEAF, name: "text" } ]
   };
   testAccessibleTree(accessible, tree);
 
   let onReorder = waitForEvent(EVENT_REORDER, id);
-  yield ContentTask.spawn(browser, id, id =>
-    content.document.getElementById(id).firstChild.textContent = '');
+  yield ContentTask.spawn(browser, id, contentId => {
+    content.document.getElementById(contentId).firstChild.textContent = '';
+  });
   yield onReorder;
 
   tree = { role: role, children: [] };
   testAccessibleTree(accessible, tree);
 }
 
 addAccessibleTask(`
   <p id="p">text</p>
--- a/accessible/tests/browser/shared-head.js
+++ b/accessible/tests/browser/shared-head.js
@@ -109,23 +109,23 @@ function isDefunct(accessible) {
  * @return {Promise}          promise indicating that attribute is set/removed
  */
 function invokeSetAttribute(browser, id, attr, value) {
   if (value) {
     Logger.log(`Setting ${attr} attribute to ${value} for node with id: ${id}`);
   } else {
     Logger.log(`Removing ${attr} attribute from node with id: ${id}`);
   }
-  return ContentTask.spawn(browser, { id, attr, value },
-    ({ id, attr, value }) => {
-      let elm = content.document.getElementById(id);
-      if (value) {
-        elm.setAttribute(attr, value);
+  return ContentTask.spawn(browser, [id, attr, value],
+    ([contentId, contentAttr, contentValue]) => {
+      let elm = content.document.getElementById(contentId);
+      if (contentValue) {
+        elm.setAttribute(contentAttr, contentValue);
       } else {
-        elm.removeAttribute(attr);
+        elm.removeAttribute(contentAttr);
       }
     });
 }
 
 /**
  * Asynchronously set or remove content element's style (in content process if
  * e10s is enabled).
  * @param  {Object}  browser  current "tabbrowser" element
@@ -136,38 +136,38 @@ function invokeSetAttribute(browser, id,
  * @return {Promise}          promise indicating that style is set/removed
  */
 function invokeSetStyle(browser, id, style, value) {
   if (value) {
     Logger.log(`Setting ${style} style to ${value} for node with id: ${id}`);
   } else {
     Logger.log(`Removing ${style} style from node with id: ${id}`);
   }
-  return ContentTask.spawn(browser, { id, style, value },
-    ({ id, style, value }) => {
-      let elm = content.document.getElementById(id);
-      if (value) {
-        elm.style[style] = value;
+  return ContentTask.spawn(browser, [id, style, value],
+    ([contentId, contentStyle, contentValue]) => {
+      let elm = content.document.getElementById(contentId);
+      if (contentValue) {
+        elm.style[contentStyle] = contentValue;
       } else {
-        delete elm.style[style];
+        delete elm.style[contentStyle];
       }
     });
 }
 
 /**
  * Asynchronously set focus on a content element (in content process if e10s is
  * enabled).
  * @param  {Object}  browser  current "tabbrowser" element
  * @param  {String}  id       content element id
  * @return {Promise} promise  indicating that focus is set
  */
 function invokeFocus(browser, id) {
   Logger.log(`Setting focus on a node with id: ${id}`);
-  return ContentTask.spawn(browser, id, id => {
-    let elm = content.document.getElementById(id);
+  return ContentTask.spawn(browser, id, contentId => {
+    let elm = content.document.getElementById(contentId);
     if (elm instanceof Ci.nsIDOMNSEditableElement && elm.editor ||
         elm instanceof Ci.nsIDOMXULTextBoxElement) {
       elm.selectionStart = elm.selectionEnd = elm.value.length;
     }
     elm.focus();
   });
 }
 
--- a/accessible/tests/mochitest/tree/test_tabbrowser.xul
+++ b/accessible/tests/mochitest/tree/test_tabbrowser.xul
@@ -85,16 +85,25 @@
             {
               // xul:toolbarbutton ("Close current tab")
               role: ROLE_PUSHBUTTON,
               children: []
             }
             );
         } else {
           SimpleTest.ok(true, "Testing Firefox tabbrowser UI.");
+          let newTabChildren = [];
+          if (SpecialPowers.getBoolPref("privacy.userContext.enabled")) {
+            newTabChildren = [
+              {
+                role: ROLE_MENUPOPUP,
+                children: []
+              }
+            ];
+          }
 
           // NB: The (3) buttons are not visible, unless manually hovered,
           //     probably due to size reduction in this test.
           tabsAccTree.children.splice(0, 0,
             {
               // xul:tab ("about:")
               role: ROLE_PAGETAB,
               children: [
@@ -114,17 +123,17 @@
                   role: ROLE_PUSHBUTTON,
                   children: []
                 }
               ]
             },
             {
               // xul:toolbarbutton ("Open a new tab")
               role: ROLE_PUSHBUTTON,
-              children: []
+              children: newTabChildren
             }
             // "List all tabs" dropdown
             // XXX: This child(?) is not present in this test.
             //      I'm not sure why (though probably expected).
             );
         }
 
         testAccessibleTree(tabBrowser().tabContainer, tabsAccTree);
--- a/addon-sdk/source/lib/sdk/addon/installer.js
+++ b/addon-sdk/source/lib/sdk/addon/installer.js
@@ -59,17 +59,17 @@ exports.install = function install(xpiPa
     },
     onDownloadFailed: function(aInstall) {
       this.onInstallFailed(aInstall);
     }
   };
 
   // Order AddonManager to install the addon
   AddonManager.getInstallForFile(file, function(install) {
-    if (install.error != null) {
+    if (install.error == 0) {
       install.addListener(listener);
       install.install();
     } else {
       reject(install.error);
     }
   });
 
   return promise;
--- a/addon-sdk/source/lib/sdk/panel/utils.js
+++ b/addon-sdk/source/lib/sdk/panel/utils.js
@@ -250,17 +250,17 @@ function onPanelClick(event) {
 }
 
 function setupPanelFrame(frame) {
   frame.setAttribute("flex", 1);
   frame.setAttribute("transparent", "transparent");
   frame.setAttribute("autocompleteenabled", true);
   frame.setAttribute("tooltip", "aHTMLTooltip");
   if (platform === "darwin") {
-    frame.style.borderRadius = "6px";
+    frame.style.borderRadius = "var(--arrowpanel-border-radius, 3.5px)";
     frame.style.padding = "1px";
   }
 }
 
 function make(document, options) {
   document = document || getMostRecentBrowserWindow().document;
   let panel = document.createElementNS(XUL_NS, "panel");
   panel.setAttribute("type", "arrow");
--- a/addon-sdk/source/lib/sdk/ui/frame/view.html
+++ b/addon-sdk/source/lib/sdk/ui/frame/view.html
@@ -1,18 +1,18 @@
-<script>
-// HACK: This is not an ideal way to deliver chrome messages
-// to a innef frame content but seems only way that would
-// make `event.source` an this (outer frame) window.
-window.onmessage = function(event) {
-  var frame = document.querySelector("iframe");
-  var content = frame.contentWindow;
-  // If message is posted from chrome it has no `event.source`.
-  if (event.source === null)
-    content.postMessage(event.data, "*");
-};
-// Hack: Ideally we would have used srcdoc on iframe, but in
-// that case origin of document is either content which is unable
-// to load add-on resources or a chrome to which add-on resource
-// can not send messages back.
-document.documentElement.style.overflow = "hidden";
-document.documentElement.innerHTML = atob(location.hash.substr(1));
-</script>
+<!DOCTYPE html>
+<html>
+  <head>
+    <script>
+      // HACK: This is not an ideal way to deliver chrome messages
+      // to an inner frame content but seems only way that would
+      // make `event.source` this (outer frame) window.
+      window.onmessage = function(event) {
+        var frame = document.querySelector("iframe");
+        var content = frame.contentWindow;
+        // If message is posted from chrome it has no `event.source`.
+        if (event.source === null)
+          content.postMessage(event.data, "*");
+      };
+    </script>
+  </head>
+  <body style="overflow: hidden"></body>
+</html>
--- a/addon-sdk/source/lib/sdk/ui/frame/view.js
+++ b/addon-sdk/source/lib/sdk/ui/frame/view.js
@@ -58,39 +58,45 @@ const registerFrame = ({id, url}) => {
     id: id,
     type: "custom",
     removable: true,
     onBuild: document => {
       let view = document.createElementNS(XUL_NS, "toolbaritem");
       view.setAttribute("id", id);
       view.setAttribute("flex", 2);
 
-      let innerFrame = document.createElementNS(HTML_NS, "iframe");
-      innerFrame.setAttribute("id", id);
-      innerFrame.setAttribute("src", url);
-      innerFrame.setAttribute("seamless", "seamless");
-      innerFrame.setAttribute("sandbox", "allow-scripts");
-      innerFrame.setAttribute("scrolling", "no");
-      innerFrame.setAttribute("data-is-sdk-inner-frame", true);
-      innerFrame.setAttribute("style", [ "border:none",
-        "position:absolute", "width:100%", "top: 0",
-        "left: 0", "overflow: hidden"].join(";"));
-
       let outerFrame = document.createElementNS(XUL_NS, "iframe");
-      outerFrame.setAttribute("src", OUTER_FRAME_URI + "#" +
-                                     encode(innerFrame.outerHTML));
+      outerFrame.setAttribute("src", OUTER_FRAME_URI);
       outerFrame.setAttribute("id", "outer-" + id);
       outerFrame.setAttribute("data-is-sdk-outer-frame", true);
       outerFrame.setAttribute("type", "content");
       outerFrame.setAttribute("transparent", true);
       outerFrame.setAttribute("flex", 2);
       outerFrame.setAttribute("style", "overflow: hidden;");
       outerFrame.setAttribute("scrolling", "no");
       outerFrame.setAttribute("disablehistory", true);
       outerFrame.setAttribute("seamless", "seamless");
+      outerFrame.addEventListener("load", function onload() {
+        outerFrame.removeEventListener("load", onload, true);
+
+        let doc = outerFrame.contentDocument;
+
+        let innerFrame = doc.createElementNS(HTML_NS, "iframe");
+        innerFrame.setAttribute("id", id);
+        innerFrame.setAttribute("src", url);
+        innerFrame.setAttribute("seamless", "seamless");
+        innerFrame.setAttribute("sandbox", "allow-scripts");
+        innerFrame.setAttribute("scrolling", "no");
+        innerFrame.setAttribute("data-is-sdk-inner-frame", true);
+        innerFrame.setAttribute("style", [ "border:none",
+          "position:absolute", "width:100%", "top: 0",
+          "left: 0", "overflow: hidden"].join(";"));
+
+        doc.body.appendChild(innerFrame);
+      }, true);
 
       view.appendChild(outerFrame);
 
       return view;
     }
   });
 };
 
--- a/addon-sdk/source/test/addons/jetpack-addon.ini
+++ b/addon-sdk/source/test/addons/jetpack-addon.ini
@@ -24,16 +24,17 @@ skip-if = true
 [main.xpi]
 [name-in-numbers.xpi]
 [name-in-numbers-plus.xpi]
 [packaging.xpi]
 [packed.xpi]
 [page-mod-debugger-post.xpi]
 [page-mod-debugger-pre.xpi]
 [page-worker.xpi]
+skip-if = true # Bug 1288619 and Bug 1288708
 [places.xpi]
 [predefined-id-with-at.xpi]
 [preferences-branch.xpi]
 [private-browsing-supported.xpi]
 skip-if = true
 [remote.xpi]
 [require.xpi]
 [self.xpi]
--- a/addon-sdk/test/browser.ini
+++ b/addon-sdk/test/browser.ini
@@ -2,14 +2,13 @@
 support-files =
   head.js
   Math.jsm
   math.js
   data.json
   invalid.json
 [browser_sdk_loader_sdk_modules.js]
 [browser_sdk_loader_sdk_gui_modules.js]
-skip-if = e10s # Bug 1315042
 [browser_sdk_loader_jsm_modules.js]
 [browser_sdk_loader_js_modules.js]
 [browser_sdk_loader_json.js]
 [browser_sdk_loader_chrome.js]
 [browser_sdk_loader_chrome_in_sdk.js]
--- a/b2g/dev/config/tooltool-manifests/linux64/hazard.manifest
+++ b/b2g/dev/config/tooltool-manifests/linux64/hazard.manifest
@@ -19,19 +19,19 @@
 "algorithm" : "sha512",
 "filename" : "gtk3.tar.xz",
 "setup" : "setup.sh",
 "unpack" : true,
 "digest" : "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
 "size" : 12072532
 },
 {
-"version": "rustc 1.12.0 (3191fbae9 2016-09-23) repack",
-"size": 102403884,
-"digest": "a7c1512d955d3030bcc1ebddfbf512f7b11b66e31634726deab78d0403fc0ceadd603d32b08c1a5025d3e9ee4ff48ddcf5eaba33468bb2161cfb9fb1a557affa",
+"version": "rustc 1.13.0 (2c6933acc 2016-11-07) repack",
+"size": 68921028,
+"digest": "9a9ceccc02d4be445ffa64617683419a4f47990b1f2689980ac8db13d6369435ef4af1a3714d77377fb7b3b0ec213856ab7144ff22cbe0881d49aed44d82c0fc",
 "algorithm": "sha512",
 "filename": "rustc.tar.xz",
 "unpack": true
 },
 {
 "algorithm" : "sha512",
 "filename" : "sccache.tar.bz2",
 "unpack" : true,
--- a/b2g/dev/config/tooltool-manifests/linux64/releng.manifest
+++ b/b2g/dev/config/tooltool-manifests/linux64/releng.manifest
@@ -11,27 +11,27 @@
 "size": 12072532,
 "digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
 "algorithm": "sha512",
 "filename": "gtk3.tar.xz",
 "setup": "setup.sh",
 "unpack": true
 },
 {
-"version": "rustc 1.12.0 (3191fbae9 2016-09-23) repack",
-"size": 102403884,
-"digest": "a7c1512d955d3030bcc1ebddfbf512f7b11b66e31634726deab78d0403fc0ceadd603d32b08c1a5025d3e9ee4ff48ddcf5eaba33468bb2161cfb9fb1a557affa",
+"version": "rustc 1.13.0 (2c6933acc 2016-11-07) repack",
+"size": 68921028,
+"digest": "9a9ceccc02d4be445ffa64617683419a4f47990b1f2689980ac8db13d6369435ef4af1a3714d77377fb7b3b0ec213856ab7144ff22cbe0881d49aed44d82c0fc",
 "algorithm": "sha512",
 "filename": "rustc.tar.xz",
 "unpack": true
 },
 {
-"version": "cargo 0.13.0-nightly (e713e7f 2016-08-31)",
-"size": 3245716,
-"digest": "d5bb0d88ce7bb1b5a316d7a8ca6341672f5ee8008fa7754511bf53fabd54c0770e95397232896d6087547891f1143f6968d8b1e106e39800b43defeb0025c7c0",
+"version": "cargo 0.13.0-nightly (eca9e15 2016-11-01) repack",
+"size": 3027932,
+"digest": "a5c99eeb12b3b9b49632c259c762e34ec13cf72dadf90a0608b8ab1dc66b36cb114c5b45f71d326e12d31d9e88a41b029e6a728ca64cef392c0a8d211c2fe191",
 "algorithm": "sha512",
 "filename": "cargo.tar.xz",
 "unpack": true
 },
 {
 "size": 167175,
 "digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
 "algorithm": "sha512",
--- a/browser/app/blocklist.xml
+++ b/browser/app/blocklist.xml
@@ -1,10 +1,10 @@
 <?xml version='1.0' encoding='UTF-8'?>
-<blocklist lastupdate="1478699528704" xmlns="http://www.mozilla.org/2006/addons-blocklist">
+<blocklist lastupdate="1479042428179" xmlns="http://www.mozilla.org/2006/addons-blocklist">
   <emItems>
     <emItem blockID="i988" id="{b12785f5-d8d0-4530-a3ea-5c4263b85bef}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i398" id="{377e5d4d-77e5-476a-8716-7e70a9272da0}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
@@ -192,26 +192,26 @@
     <emItem blockID="i360" id="ytd@mybrowserbar.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i666" id="wecarereminder@bryan">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
+    <emItem blockID="i504" id="aytac@abc.com">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="3"/>
+    </emItem>
     <emItem blockID="i684" id="{9edd0ea8-2819-47c2-8320-b007d5996f8a}">
       <prefs>
         <pref>browser.search.defaultenginename</pref>
       </prefs>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
-    <emItem blockID="i504" id="aytac@abc.com">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="3"/>
-    </emItem>
     <emItem blockID="i69" id="{977f3b97-5461-4346-92c8-a14c749b77c9}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i444" id="fplayer@adobe.flash">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
@@ -346,18 +346,18 @@
     <emItem blockID="i618" id="toolbar@ask.com">
       <prefs/>
       <versionRange minVersion="3.15.24" maxVersion="3.15.24.*" severity="1"/>
       <versionRange minVersion="3.15.13" maxVersion="3.15.13.*" severity="1"/>
       <versionRange minVersion="3.15.28" maxVersion="3.15.28.*" severity="1"/>
       <versionRange minVersion="3.15.22" maxVersion="3.15.22.*" severity="1"/>
       <versionRange minVersion="3.15.8" maxVersion="3.15.8.*" severity="1"/>
       <versionRange minVersion="3.15.10" maxVersion="3.15.11.*" severity="1"/>
+      <versionRange minVersion="3.15.5" maxVersion="3.15.5.*" severity="1"/>
       <versionRange minVersion="3.15.18" maxVersion="3.15.20.*" severity="1"/>
-      <versionRange minVersion="3.15.5" maxVersion="3.15.5.*" severity="1"/>
       <versionRange minVersion="3.15.31" maxVersion="3.15.31.*" severity="1"/>
       <versionRange minVersion="3.15.26" maxVersion="3.15.26.*" severity="1"/>
     </emItem>
     <emItem blockID="i15" id="personas@christopher.beard">
       <prefs/>
       <versionRange minVersion="1.6" maxVersion="1.6">
         <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
           <versionRange maxVersion="3.6.*" minVersion="3.6"/>
@@ -439,28 +439,28 @@
     <emItem blockID="i222" id="dealcabby@jetpack">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i100" id="{394DCBA4-1F92-4f8e-8EC9-8D2CB90CB69B}">
       <prefs/>
       <versionRange minVersion="2.5.0" maxVersion="2.5.0" severity="1"/>
     </emItem>
+    <emItem blockID="i590" id="{94cd2cc3-083f-49ba-a218-4cda4b4829fd}">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="1"/>
+    </emItem>
     <emItem blockID="i1232" id="nosquint@urandom.ca">
       <prefs/>
       <versionRange minVersion="0" maxVersion="2.1.9.1-signed.1-signed" severity="1">
         <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
           <versionRange maxVersion="*" minVersion="47"/>
         </targetApplication>
       </versionRange>
     </emItem>
-    <emItem blockID="i590" id="{94cd2cc3-083f-49ba-a218-4cda4b4829fd}">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="1"/>
-    </emItem>
     <emItem blockID="i650" id="jid1-qj0w91o64N7Eeg@jetpack">
       <prefs/>
       <versionRange minVersion="39.5.1" maxVersion="47.0.4" severity="3"/>
     </emItem>
     <emItem blockID="i748" id="{32da2f20-827d-40aa-a3b4-2fc4a294352e}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
@@ -673,28 +673,28 @@
     <emItem blockID="i968" id="{184AA5E6-741D-464a-820E-94B3ABC2F3B4}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i538" id="{354dbb0a-71d5-4e9f-9c02-6c88b9d387ba}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
-    <emItem blockID="i658" id="low_quality_flash@pie2k.com">
-      <prefs/>
-      <versionRange minVersion="46.2" maxVersion="47.1" severity="3"/>
-    </emItem>
     <emItem blockID="i792" id="{8f894ed3-0bf2-498e-a103-27ef6e88899f}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i742" id="{f894a29a-f065-40c3-bb19-da6057778493}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
+    <emItem blockID="i658" id="low_quality_flash@pie2k.com">
+      <prefs/>
+      <versionRange minVersion="46.2" maxVersion="47.1" severity="3"/>
+    </emItem>
     <emItem blockID="i17" id="{3252b9ae-c69a-4eaf-9502-dc9c1f6c009e}">
       <prefs/>
       <versionRange minVersion="2.2" maxVersion="2.2"/>
     </emItem>
     <emItem blockID="i109" id="{392e123b-b691-4a5e-b52f-c4c1027e749c}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*"/>
     </emItem>
@@ -854,28 +854,28 @@
     <emItem blockID="i165" id="{EEF73632-A085-4fd3-A778-ECD82C8CB297}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i1022" id="g99hiaoekjoasiijdkoleabsy278djasi@jetpack">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
+    <emItem blockID="i499" id="{babb9931-ad56-444c-b935-38bffe18ad26}">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="3"/>
+    </emItem>
     <emItem blockID="i75" id="firebug@software.joehewitt.com" os="Darwin,Linux">
       <prefs/>
       <versionRange minVersion="1.9.0" maxVersion="1.9.0" severity="1">
         <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
           <versionRange maxVersion="9.*" minVersion="9.0a1"/>
         </targetApplication>
       </versionRange>
     </emItem>
-    <emItem blockID="i499" id="{babb9931-ad56-444c-b935-38bffe18ad26}">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="3"/>
-    </emItem>
     <emItem blockID="i718" id="G4Ce4@w.net">
       <prefs>
         <pref>browser.startup.homepage</pref>
       </prefs>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i21" id="support@update-firefox.com">
       <prefs/>
@@ -936,27 +936,27 @@
     <emItem blockID="i1077" id="helper@vidscrab.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i55" id="youtube@youtube7.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*"/>
     </emItem>
-    <emItem blockID="i664" id="123456789@offeringmedia.com">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="3"/>
-    </emItem>
     <emItem blockID="i630" id="webbooster@iminent.com">
       <prefs>
         <pref>browser.startup.homepage</pref>
         <pref>browser.search.defaultenginename</pref>
       </prefs>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
+    <emItem blockID="i664" id="123456789@offeringmedia.com">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="3"/>
+    </emItem>
     <emItem blockID="i93" id="{68b8676b-99a5-46d1-b390-22411d8bcd61}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*"/>
     </emItem>
     <emItem blockID="i624" id="/^({b95faac1-a3d7-4d69-8943-ddd5a487d966}|{ecce0073-a837-45a2-95b9-600420505f7e}|{2713b394-286f-4d7c-89ea-4174eeab9f5a}|{da7a20cf-bef4-4342-ad78-0240fdf87055})$/">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
@@ -1032,21 +1032,21 @@
     <emItem blockID="i1262" id="my7thfakeid@gmail.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i86" id="{45147e67-4020-47e2-8f7a-55464fb535aa}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*"/>
     </emItem>
-    <emItem blockID="i598" id="{29b136c9-938d-4d3d-8df8-d649d9b74d02}">
+    <emItem blockID="i402" id="{99079a25-328f-4bd4-be04-00955acaa0a7}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
-    <emItem blockID="i402" id="{99079a25-328f-4bd4-be04-00955acaa0a7}">
+    <emItem blockID="i598" id="{29b136c9-938d-4d3d-8df8-d649d9b74d02}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i451" id="{e44a1809-4d10-4ab8-b343-3326b64c7cdd}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i108" id="{28bfb930-7620-11e1-b0c4-0800200c9a66}">
@@ -1175,28 +1175,28 @@
       <prefs/>
       <versionRange minVersion="1.0" maxVersion="1.3.1">
         <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
           <versionRange maxVersion="*" minVersion="3.0a1"/>
         </targetApplication>
       </versionRange>
       <versionRange minVersion="1.5.7.5" maxVersion="1.5.7.5" severity="1"/>
     </emItem>
-    <emItem blockID="i461" id="{8E9E3331-D360-4f87-8803-52DE43566502}">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="1"/>
-    </emItem>
     <emItem blockID="i596" id="{b99c8534-7800-48fa-bd71-519a46cdc7e1}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i818" id="contentarget@maildrop.cc">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
+    <emItem blockID="i461" id="{8E9E3331-D360-4f87-8803-52DE43566502}">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="1"/>
+    </emItem>
     <emItem blockID="i23" id="firefox@bandoo.com">
       <prefs/>
       <versionRange minVersion="5.0" maxVersion="5.0" severity="1">
         <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
           <versionRange maxVersion="*" minVersion="3.7a1pre"/>
         </targetApplication>
       </versionRange>
     </emItem>
@@ -1296,24 +1296,24 @@
     <emItem blockID="i364" id="{FE1DEEEA-DB6D-44b8-83F0-34FC0F9D1052}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i356" id="{341f4dac-1966-47ff-aacf-0ce175f1498a}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
+    <emItem blockID="i336" id="CortonExt@ext.com">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="1"/>
+    </emItem>
     <emItem blockID="i536" id="{25D77636-38B1-1260-887C-2D4AFA92D6A4}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
-    <emItem blockID="i336" id="CortonExt@ext.com">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="1"/>
-    </emItem>
     <emItem blockID="i374" id="update@firefox.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i858" id="fftoolbar2014@etech.com">
       <prefs>
         <pref>browser.startup.homepage</pref>
         <pref>browser.search.defaultenginename</pref>
@@ -1387,21 +1387,21 @@
     <emItem blockID="i344" id="lrcsTube@hansanddeta.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i79" id="GifBlock@facebook.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*"/>
     </emItem>
-    <emItem blockID="i469" id="OKitSpace@OKitSpace.es">
+    <emItem blockID="i780" id="{b6ef1336-69bb-45b6-8cba-e578fc0e4433}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
-    <emItem blockID="i780" id="{b6ef1336-69bb-45b6-8cba-e578fc0e4433}">
+    <emItem blockID="i469" id="OKitSpace@OKitSpace.es">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i483" id="brasilescapefive@facebook.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i1058" id="amo-validator-bypass@example.com">
@@ -1682,21 +1682,21 @@
     <emItem blockID="i519" id="703db0db-5fe9-44b6-9f53-c6a91a0ad5bd@7314bc82-969e-4d2a-921b-e5edd0b02cf1.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i477" id="mbrnovone@facebook.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
-    <emItem blockID="i495" id="kallow@facebook.com">
+    <emItem blockID="i836" id="hansin@topvest.id">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
-    <emItem blockID="i836" id="hansin@topvest.id">
+    <emItem blockID="i495" id="kallow@facebook.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i542" id="/^({bf67a47c-ea97-4caf-a5e3-feeba5331231}|{24a0cfe1-f479-4b19-b627-a96bf1ea3a56})$/">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i286" id="{58bd07eb-0ee0-4df0-8121-dc9b693373df}">
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -77,20 +77,26 @@ pref("browser.dictionaries.download.url"
 
 // At startup, should we check to see if the installation
 // date is older than some threshold
 pref("app.update.checkInstallTime", true);
 
 // The number of days a binary is permitted to be old without checking is defined in
 // firefox-branding.js (app.update.checkInstallTime.days)
 
-// The minimum delay in seconds for the timer to fire.
-// default=2 minutes
+// The minimum delay in seconds for the timer to fire between the notification
+// of each consumer of the timer manager.
+// minimum=30 seconds, default=120 seconds, and maximum=300 seconds
 pref("app.update.timerMinimumDelay", 120);
 
+// The minimum delay in milliseconds for the first firing after startup of the timer
+// to notify consumers of the timer manager.
+// minimum=10 seconds, default=30 seconds, and maximum=120 seconds
+pref("app.update.timerFirstInterval", 30000);
+
 // App-specific update preferences
 
 // The interval to check for updates (app.update.interval) is defined in
 // firefox-branding.js
 
 // Alternative windowtype for an application update user interface window. When
 // a window with this windowtype is open the application update service won't
 // open the normal application update user interface window.
@@ -99,22 +105,16 @@ pref("app.update.altwindowtype", "Browse
 // Enables some extra Application Update Logging (can reduce performance)
 pref("app.update.log", false);
 
 // The number of general background check failures to allow before notifying the
 // user of the failure. User initiated update checks always notify the user of
 // the failure.
 pref("app.update.backgroundMaxErrors", 10);
 
-// When |app.update.cert.requireBuiltIn| is true or not specified the
-// final certificate and all certificates the connection is redirected to before
-// the final certificate for the url specified in the |app.update.url|
-// preference must be built-in.
-pref("app.update.cert.requireBuiltIn", false);
-
 // Whether or not app updates are enabled
 pref("app.update.enabled", true);
 
 // If set to true, the Update Service will automatically download updates when
 // app updates are enabled per the app.update.enabled preference and if the user
 // can apply updates.
 pref("app.update.auto", true);
 
@@ -133,19 +133,16 @@ pref("app.update.badge", false);
 // when it finishes downloading them.
 pref("app.update.staging.enabled", true);
 
 // Update service URL:
 pref("app.update.url", "https://aus5.mozilla.org/update/6/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%SYSTEM_CAPABILITIES%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml");
 // app.update.url.manual is in branding section
 // app.update.url.details is in branding section
 
-// User-settable override to app.update.url for testing purposes.
-//pref("app.update.url.override", "");
-
 // app.update.interval is in branding section
 // app.update.promptWaitTime is in branding section
 
 // Show the Update Checking/Ready UI when the user was idle for x seconds
 pref("app.update.idletime", 60);
 
 // Whether or not to attempt using the service for updates.
 #ifdef MOZ_MAINTENANCE_SERVICE
@@ -1038,17 +1035,17 @@ pref("browser.taskbar.lists.enabled", tr
 pref("browser.taskbar.lists.frequent.enabled", true);
 pref("browser.taskbar.lists.recent.enabled", false);
 pref("browser.taskbar.lists.maxListItemCount", 7);
 pref("browser.taskbar.lists.tasks.enabled", true);
 pref("browser.taskbar.lists.refreshInSeconds", 120);
 #endif
 
 // The sync engines to use.
-pref("services.sync.registerEngines", "Bookmarks,Form,History,Password,Prefs,Tab,Addons");
+pref("services.sync.registerEngines", "Bookmarks,Form,History,Password,Prefs,Tab,Addons,ExtensionStorage");
 // Preferences to be synced by default
 pref("services.sync.prefs.sync.accessibility.blockautorefresh", true);
 pref("services.sync.prefs.sync.accessibility.browsewithcaret", true);
 pref("services.sync.prefs.sync.accessibility.typeaheadfind", true);
 pref("services.sync.prefs.sync.accessibility.typeaheadfind.linksonly", true);
 pref("services.sync.prefs.sync.addons.ignoreUserEnabledChanges", true);
 // The addons prefs related to repository verification are intentionally
 // not synced for security reasons. If a system is compromised, a user
@@ -1433,16 +1430,17 @@ pref("privacy.usercontext.about_newtab_s
 // us to change everybody to true in the future, when desired.
 pref("browser.tabs.remote.autostart.1", false);
 pref("browser.tabs.remote.autostart.2", true);
 #endif
 
 // For the about:tabcrashed page
 pref("browser.tabs.crashReporting.sendReport", true);
 pref("browser.tabs.crashReporting.includeURL", false);
+pref("browser.tabs.crashReporting.requestEmail", false);
 pref("browser.tabs.crashReporting.emailMe", false);
 pref("browser.tabs.crashReporting.email", "");
 
 // Enable e10s add-on interposition by default.
 pref("extensions.interposition.enabled", true);
 pref("extensions.interposition.prefetching", true);
 
 // Enable blocking of e10s for add-on users on beta/release.
--- a/browser/base/content/aboutTabCrashed.css
+++ b/browser/base/content/aboutTabCrashed.css
@@ -1,8 +1,11 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 html:not(.crashDumpSubmitted) #reportSent,
-html:not(.crashDumpAvailable) #report-box {
+html:not(.crashDumpAvailable) #reportBox,
+.container[multiple="true"] > .offers > #offerHelpMessageSingle,
+.container[multiple="false"] > .offers > #offerHelpMessageMultiple,
+.container[multiple="false"] > .button-container > #restoreAll {
   display: none;
-}
+}
\ No newline at end of file
--- a/browser/base/content/aboutTabCrashed.js
+++ b/browser/base/content/aboutTabCrashed.js
@@ -57,17 +57,17 @@ var AboutTabCrashed = {
     addEventListener("DOMContentLoaded", this);
 
     document.title = this.pageData.title;
   },
 
   receiveMessage(message) {
     switch (message.name) {
       case "UpdateCount": {
-        this.showRestoreAll(message.data.count > 1);
+        this.setMultiple(message.data.count > 1);
         break;
       }
       case "SetCrashReportAvailable": {
         this.onSetCrashReportAvailable(message);
         break;
       }
       case "CrashReportSent": {
         this.onCrashReportSent();
@@ -146,48 +146,63 @@ var AboutTabCrashed = {
    * will respond with whether or not a crash report is available. This
    * method handles that message.
    *
    * @param message
    *        The message from the parent, which should contain a data
    *        Object property with the following properties:
    *
    *        hasReport (bool):
-   *          Whether or not there is a crash report
+   *          Whether or not there is a crash report.
    *
    *        sendReport (bool):
    *          Whether or not the the user prefers to send the report
-   *          by default
+   *          by default.
    *
    *        includeURL (bool):
    *          Whether or not the user prefers to send the URL of
    *          the tab that crashed.
    *
    *        emailMe (bool):
    *          Whether or not to send the email address of the user
    *          in the report.
    *
    *        email (String):
-   *          The email address of the user (empty if emailMe is false)
+   *          The email address of the user (empty if emailMe is false).
+   *
+   *        requestAutoSubmit (bool):
+   *          Whether or not we should ask the user to automatically
+   *          submit backlogged crash reports.
    *
    */
   onSetCrashReportAvailable(message) {
-    if (message.data.hasReport) {
+    let data = message.data;
+
+    if (data.hasReport) {
       this.hasReport = true;
       document.documentElement.classList.add("crashDumpAvailable");
 
-      let data = message.data;
       document.getElementById("sendReport").checked = data.sendReport;
       document.getElementById("includeURL").checked = data.includeURL;
-      document.getElementById("emailMe").checked = data.emailMe;
-      if (data.emailMe) {
-        document.getElementById("email").value = data.email;
+
+      if (data.requestEmail) {
+        document.getElementById("requestEmail").hidden = false;
+        document.getElementById("emailMe").checked = data.emailMe;
+        if (data.emailMe) {
+          document.getElementById("email").value = data.email;
+        }
       }
 
       this.showCrashReportUI(data.sendReport);
+    } else {
+      this.showCrashReportUI(false);
+    }
+
+    if (data.requestAutoSubmit) {
+      document.getElementById("requestAutoSubmit").hidden = false;
     }
 
     let event = new CustomEvent("AboutTabCrashedReady", {bubbles:true});
     document.dispatchEvent(event);
   },
 
   /**
    * Handler for when the parent reports that the crash report associated
@@ -200,34 +215,39 @@ var AboutTabCrashed = {
 
   /**
    * Toggles the display of the crash report form.
    *
    * @param shouldShow (bool)
    *        True if the crash report form should be shown
    */
   showCrashReportUI(shouldShow) {
-    let container = document.getElementById("crash-reporter-container");
-    container.hidden = !shouldShow;
+    let options = document.getElementById("options");
+    options.hidden = !shouldShow;
   },
 
   /**
-   * Toggles the display of the "Restore All" button.
+   * Toggles whether or not the page is one of several visible pages
+   * showing the crash reporter. This controls some of the language
+   * on the page, along with what the "primary" button is.
    *
-   * @param shouldShow (bool)
-   *        True if the "Restore All" button should be shown
+   * @param hasMultiple (bool)
+   *        True if there are multiple crash report pages being shown.
    */
-  showRestoreAll(shouldShow) {
-    let restoreAll = document.getElementById("restoreAll");
+  setMultiple(hasMultiple) {
+    let main = document.getElementById("main");
+    main.setAttribute("multiple", hasMultiple);
+
     let restoreTab = document.getElementById("restoreTab");
-    if (shouldShow) {
-      restoreAll.removeAttribute("hidden");
+
+    // The "Restore All" button has the "primary" class by default, so
+    // we only need to modify the "Restore Tab" button.
+    if (hasMultiple) {
       restoreTab.classList.remove("primary");
     } else {
-      restoreAll.setAttribute("hidden", true);
       restoreTab.classList.add("primary");
     }
   },
 
   /**
    * Sends a message to the parent in response to the user choosing
    * one of the actions available on the page. This might also send up
    * crash report information if the user has chosen to submit a crash
@@ -238,38 +258,51 @@ var AboutTabCrashed = {
    */
   sendMessage(messageName) {
     let comments = "";
     let email = "";
     let URL = "";
     let sendReport = false;
     let emailMe = false;
     let includeURL = false;
+    let autoSubmit = false;
 
     if (this.hasReport) {
       sendReport = document.getElementById("sendReport").checked;
       if (sendReport) {
         comments = document.getElementById("comments").value.trim();
 
         includeURL = document.getElementById("includeURL").checked;
         if (includeURL) {
           URL = this.pageData.URL.trim();
         }
 
-        emailMe = document.getElementById("emailMe").checked;
-        if (emailMe) {
-          email = document.getElementById("email").value.trim();
+        if (!document.getElementById("requestEmail").hidden) {
+          emailMe = document.getElementById("emailMe").checked;
+          if (emailMe) {
+            email = document.getElementById("email").value.trim();
+          }
         }
       }
     }
 
+    let requestAutoSubmit = document.getElementById("requestAutoSubmit");
+    if (requestAutoSubmit.hidden) {
+      // The checkbox is hidden if the user has already opted in to sending
+      // backlogged crash reports.
+      autoSubmit = true;
+    } else {
+      autoSubmit = document.getElementById("autoSubmit").checked;
+    }
+
     sendAsyncMessage(messageName, {
       sendReport,
       comments,
       email,
       emailMe,
       includeURL,
       URL,
+      autoSubmit,
     });
   },
 };
 
 AboutTabCrashed.init();
--- a/browser/base/content/aboutTabCrashed.xhtml
+++ b/browser/base/content/aboutTabCrashed.xhtml
@@ -25,47 +25,73 @@
           href="chrome://global/skin/in-content/info-pages.css"/>
     <link rel="stylesheet" type="text/css" media="all"
           href="chrome://browser/content/aboutTabCrashed.css"/>
     <link rel="stylesheet" type="text/css" media="all"
           href="chrome://browser/skin/aboutTabCrashed.css"/>
   </head>
 
   <body dir="&locale.dir;">
-    <div class="container">
+    <div id="main" class="container" multiple="false">
+
       <div class="title">
-        <h1 class="title-text">&tabCrashed.header;</h1>
+        <h1 class="title-text">&tabCrashed.header2;</h1>
+      </div>
+
+      <div class="offers">
+        <h2>&tabCrashed.offerHelp;</h2>
+        <p id="offerHelpMessageSingle">&tabCrashed.single.offerHelpMessage;</p>
+        <p id="offerHelpMessageMultiple">&tabCrashed.multiple.offerHelpMessage;</p>
       </div>
-      <p>&tabCrashed.message;</p>
+
+      <div id="reportBox">
+        <h2>&tabCrashed.requestHelp;</h2>
+        <p>&tabCrashed.requestHelpMessage;</p>
+
+        <h2>&tabCrashed.requestReport;</h2>
+
+        <div class="checkbox-with-label">
+          <input type="checkbox" id="sendReport"/>
+          <label for="sendReport">&tabCrashed.sendReport2;</label>
+        </div>
 
-      <div id="report-box">
-        <input type="checkbox" id="sendReport"/>
-        <label for="sendReport">&tabCrashed.sendReport;</label>
-        <div id="crash-reporter-container" hidden="true">
-          <p id="crash-reporter-title">&tabCrashed.crashReporter;</p>
-          <textarea id="comments" placeholder="&tabCrashed.commentPlaceholder;" rows="4"></textarea>
+        <ul id="options">
+          <li>
+            <textarea id="comments" placeholder="&tabCrashed.commentPlaceholder2;" rows="4"></textarea>
+          </li>
+
+          <li class="checkbox-with-label">
+            <input type="checkbox" id="includeURL"/>
+            <label for="includeURL">&tabCrashed.includeURL2;</label>
+          </li>
 
-          <ul id="options">
-            <li><input type="checkbox" id="includeURL"/>
-            <label for="includeURL">&tabCrashed.includeURL;</label></li>
+          <li id="requestEmail" hidden="true">
+            <div class="checkbox-with-label">
+              <input type="checkbox" id="emailMe"/>
+              <label for="emailMe">&tabCrashed.emailMe;</label>
+            </div>
+            <input type="text" id="email" placeholder="&tabCrashed.emailPlaceholder;"/>
+          </li>
+        </ul>
 
-            <li><input type="checkbox" id="emailMe"/>
-            <label for="emailMe">&tabCrashed.emailMe;</label></li>
-          </ul>
-
-          <input type="text" id="email" placeholder="&tabCrashed.emailPlaceholder;"/>
+        <div id="requestAutoSubmit" hidden="true">
+          <h2>&tabCrashed.requestAutoSubmit;</h2>
+          <div class="checkbox-with-label">
+            <input type="checkbox" id="autoSubmit"/>
+            <label for="autoSubmit">&tabCrashed.autoSubmit;</label>
+          </div>
         </div>
       </div>
 
       <p id="reportSent">&tabCrashed.reportSent;</p>
 
       <div class="button-container">
         <button id="closeTab">
           &tabCrashed.closeTab;</button>
-        <button id="restoreTab">
+        <button id="restoreTab" class="primary">
           &tabCrashed.restoreTab;</button>
         <button id="restoreAll" autofocus="true" class="primary">
           &tabCrashed.restoreAll;</button>
       </div>
     </div>
   </body>
   <script type="text/javascript;version=1.8" src="chrome://browser/content/aboutTabCrashed.js"/>
 </html>
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -114,16 +114,26 @@ tabbrowser {
 #TabsToolbar[customizing="true"] > #tabbrowser-tabs > .tabbrowser-arrowscrollbox > .tabs-newtab-button {
   visibility: collapse;
 }
 
 #tabbrowser-tabs:not([overflow="true"])[using-closing-tabs-spacer] ~ #alltabs-button {
   visibility: hidden; /* temporary space to keep a tab's close button under the cursor */
 }
 
+.tabs-newtab-button > .toolbarbutton-menu-dropmarker,
+#new-tab-button > .toolbarbutton-menu-dropmarker {
+  display: none;
+}
+
+/* override drop marker image padding */
+.tabs-newtab-button > .toolbarbutton-icon {
+  margin-inline-end: 0;
+}
+
 .tabbrowser-tab {
   -moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-tab");
 }
 
 .tabbrowser-tab:not([pinned]) {
   -moz-box-flex: 100;
   max-width: 210px;
   min-width: 100px;
@@ -172,16 +182,17 @@ tabbrowser {
   z-index: 2;
   pointer-events: none; /* avoid blocking dragover events on scroll buttons */
 }
 
 .tabbrowser-tabs[movingtab] > .tabbrowser-tab[fadein]:not([selected]) {
   transition: transform 200ms ease-out;
 }
 
+.new-tab-popup,
 #alltabs-popup {
   -moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-alltabs-popup");
 }
 
 toolbar[printpreview="true"] {
   -moz-binding: url("chrome://global/content/printPreviewBindings.xml#printpreviewtoolbar");
 }
 
@@ -467,17 +478,25 @@ toolbar:not(#TabsToolbar) > #personal-bo
 }
 #PopupAutoCompleteRichResult[noactions] > richlistbox > richlistitem.overridable-action > .ac-action {
   display: none;
 }
 #PopupAutoCompleteRichResult[noactions] > richlistbox > richlistitem.overridable-action > .ac-type-icon {
   list-style-image: none;
 }
 
-#urlbar:not([actiontype="switchtab"]) > #urlbar-display-box {
+#urlbar:not([actiontype="switchtab"]):not([actiontype="extension"]) > #urlbar-display-box {
+  display: none;
+}
+
+#urlbar:not([actiontype="switchtab"]) > #urlbar-display-box > #switchtab {
+  display: none;
+}
+
+#urlbar:not([actiontype="extension"]) > #urlbar-display-box > #extension {
   display: none;
 }
 
 #PopupAutoComplete > richlistbox > richlistitem > .ac-type-icon,
 #PopupAutoComplete > richlistbox > richlistitem > .ac-site-icon,
 #PopupAutoComplete > richlistbox > richlistitem > .ac-tags,
 #PopupAutoComplete > richlistbox > richlistitem > .ac-separator,
 #PopupAutoComplete > richlistbox > richlistitem > .ac-url {
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -263,93 +263,125 @@ function UpdateBackForwardCommands(aWebN
   }
 }
 
 /**
  * Click-and-Hold implementation for the Back and Forward buttons
  * XXXmano: should this live in toolbarbutton.xml?
  */
 function SetClickAndHoldHandlers() {
-  var timer;
-
-  function openMenu(aButton) {
-    cancelHold(aButton);
-    aButton.firstChild.hidden = false;
-    aButton.open = true;
-  }
-
-  function mousedownHandler(aEvent) {
+  // Bug 414797: Clone the back/forward buttons' context menu into both buttons.
+  let popup = document.getElementById("backForwardMenu").cloneNode(true);
+  popup.removeAttribute("id");
+  // Prevent the back/forward buttons' context attributes from being inherited.
+  popup.setAttribute("context", "");
+
+  let backButton = document.getElementById("back-button");
+  backButton.setAttribute("type", "menu");
+  backButton.appendChild(popup);
+  gClickAndHoldListenersOnElement.add(backButton);
+
+  let forwardButton = document.getElementById("forward-button");
+  popup = popup.cloneNode(true);
+  forwardButton.setAttribute("type", "menu");
+  forwardButton.appendChild(popup);
+  gClickAndHoldListenersOnElement.add(forwardButton);
+}
+
+
+const gClickAndHoldListenersOnElement = {
+  _timers: new Map(),
+
+  _mousedownHandler(aEvent) {
     if (aEvent.button != 0 ||
         aEvent.currentTarget.open ||
         aEvent.currentTarget.disabled)
       return;
 
     // Prevent the menupopup from opening immediately
     aEvent.currentTarget.firstChild.hidden = true;
 
-    aEvent.currentTarget.addEventListener("mouseout", mouseoutHandler, false);
-    aEvent.currentTarget.addEventListener("mouseup", mouseupHandler, false);
-    timer = setTimeout(openMenu, 500, aEvent.currentTarget);
-  }
-
-  function mouseoutHandler(aEvent) {
-    let buttonRect = aEvent.currentTarget.getBoundingClientRect();
-    if (aEvent.clientX >= buttonRect.left &&
-        aEvent.clientX <= buttonRect.right &&
-        aEvent.clientY >= buttonRect.bottom)
-      openMenu(aEvent.currentTarget);
-    else
-      cancelHold(aEvent.currentTarget);
-  }
-
-  function mouseupHandler(aEvent) {
-    cancelHold(aEvent.currentTarget);
-  }
-
-  function cancelHold(aButton) {
-    clearTimeout(timer);
-    aButton.removeEventListener("mouseout", mouseoutHandler, false);
-    aButton.removeEventListener("mouseup", mouseupHandler, false);
-  }
-
-  function clickHandler(aEvent) {
+    aEvent.currentTarget.addEventListener("mouseout", this, false);
+    aEvent.currentTarget.addEventListener("mouseup", this, false);
+    this._timers.set(aEvent.currentTarget, setTimeout((b) => this._openMenu(b), 500, aEvent.currentTarget));
+  },
+
+  _clickHandler(aEvent) {
     if (aEvent.button == 0 &&
         aEvent.target == aEvent.currentTarget &&
         !aEvent.currentTarget.open &&
         !aEvent.currentTarget.disabled) {
       let cmdEvent = document.createEvent("xulcommandevent");
       cmdEvent.initCommandEvent("command", true, true, window, 0,
                                 aEvent.ctrlKey, aEvent.altKey, aEvent.shiftKey,
                                 aEvent.metaKey, null);
       aEvent.currentTarget.dispatchEvent(cmdEvent);
-    }
-  }
-
-  function _addClickAndHoldListenersOnElement(aElm) {
-    aElm.addEventListener("mousedown", mousedownHandler, true);
-    aElm.addEventListener("click", clickHandler, true);
-  }
-
-  // Bug 414797: Clone the back/forward buttons' context menu into both buttons.
-  let popup = document.getElementById("backForwardMenu").cloneNode(true);
-  popup.removeAttribute("id");
-  // Prevent the back/forward buttons' context attributes from being inherited.
-  popup.setAttribute("context", "");
-
-  let backButton = document.getElementById("back-button");
-  backButton.setAttribute("type", "menu");
-  backButton.appendChild(popup);
-  _addClickAndHoldListenersOnElement(backButton);
-
-  let forwardButton = document.getElementById("forward-button");
-  popup = popup.cloneNode(true);
-  forwardButton.setAttribute("type", "menu");
-  forwardButton.appendChild(popup);
-  _addClickAndHoldListenersOnElement(forwardButton);
-}
+
+      // This is here to cancel the XUL default event
+      // dom.click() triggers a command even if there is a click handler
+      // however this can now be prevented with preventDefault().
+      aEvent.preventDefault();
+    }
+  },
+
+  _openMenu(aButton) {
+    this._cancelHold(aButton);
+    aButton.firstChild.hidden = false;
+    aButton.open = true;
+  },
+
+  _mouseoutHandler(aEvent) {
+    let buttonRect = aEvent.currentTarget.getBoundingClientRect();
+    if (aEvent.clientX >= buttonRect.left &&
+        aEvent.clientX <= buttonRect.right &&
+        aEvent.clientY >= buttonRect.bottom)
+      this._openMenu(aEvent.currentTarget);
+    else
+      this._cancelHold(aEvent.currentTarget);
+  },
+
+  _mouseupHandler(aEvent) {
+    this._cancelHold(aEvent.currentTarget);
+  },
+
+  _cancelHold(aButton) {
+    clearTimeout(this._timers.get(aButton));
+    aButton.removeEventListener("mouseout", this, false);
+    aButton.removeEventListener("mouseup", this, false);
+  },
+
+  handleEvent(e) {
+    switch (e.type) {
+      case "mouseout":
+        this._mouseoutHandler(e);
+        break;
+      case "mousedown":
+        this._mousedownHandler(e);
+        break;
+      case "click":
+        this._clickHandler(e);
+        break;
+      case "mouseup":
+        this._mouseupHandler(e);
+        break;
+    }
+  },
+
+  remove(aButton) {
+    aButton.removeEventListener("mousedown", this, true);
+    aButton.removeEventListener("click", this, true);
+  },
+
+  add(aElm) {
+    this._timers.delete(aElm);
+
+    aElm.addEventListener("mousedown", this, true);
+    aElm.addEventListener("click", this, true);
+  }
+};
 
 const gSessionHistoryObserver = {
   observe: function(subject, topic, data)
   {
     if (topic != "browser:purge-session-history")
       return;
 
     var backCommand = document.getElementById("Browser:Back");
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -755,17 +755,18 @@
                 <image id="tracking-protection-icon"/>
                 <image id="connection-icon"/>
                 <hbox id="identity-icon-labels">
                   <label id="identity-icon-label" class="plain" flex="1"/>
                   <label id="identity-icon-country-label" class="plain"/>
                 </hbox>
               </box>
               <box id="urlbar-display-box" align="center">
-                <label class="urlbar-display urlbar-display-switchtab" value="&urlbar.switchToTab.label;"/>
+                <label id="switchtab" class="urlbar-display urlbar-display-switchtab" value="&urlbar.switchToTab.label;"/>
+                <label id="extension" class="urlbar-display urlbar-display-extension" value="&urlbar.extension.label;"/>
               </box>
               <hbox id="urlbar-icons">
                 <image id="page-report-button"
                        class="urlbar-icon"
                        hidden="true"
                        tooltiptext="&pageReportIcon.tooltip;"
                        onmousedown="gPopupBlockerObserver.onReportButtonMousedown(event);"/>
                 <image id="reader-mode-button"
--- a/browser/base/content/tabbrowser.css
+++ b/browser/base/content/tabbrowser.css
@@ -19,26 +19,27 @@
 }
 
 .tab-close-button[pinned],
 .tabbrowser-tabs[closebuttons="activetab"] > * > * > * > .tab-close-button:not([selected="true"]),
 .tab-icon-image:not([src]):not([pinned]):not([crashed])[selected],
 .tab-icon-image:not([src]):not([pinned]):not([crashed]):not([sharing]),
 .tab-icon-image[busy],
 .tab-throbber:not([busy]),
-.tab-icon-sound:not([soundplaying]):not([muted]),
+.tab-icon-sound:not([soundplaying]):not([muted]):not([blocked]),
 .tab-icon-sound[pinned],
 .tab-sharing-icon-overlay,
 .tab-icon-overlay {
   display: none;
 }
 
 .tab-sharing-icon-overlay[sharing]:not([selected]),
 .tab-icon-overlay[soundplaying][pinned],
 .tab-icon-overlay[muted][pinned],
+.tab-icon-overlay[blocked][pinned],
 .tab-icon-overlay[crashed] {
   display: -moz-box;
 }
 
 .tab-label[pinned] {
   width: 0;
   margin-left: 0 !important;
   margin-right: 0 !important;
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -469,16 +469,32 @@
             if (!browser.tabModalPromptBox) {
               browser.tabModalPromptBox = new TabModalPromptBox(browser);
             }
             return browser.tabModalPromptBox;
           ]]>
         </body>
       </method>
 
+      <method name="getTabFromAudioEvent">
+        <parameter name="aEvent"/>
+        <body>
+        <![CDATA[
+          if (!Services.prefs.getBoolPref("browser.tabs.showAudioPlayingIcon") ||
+              !aEvent.isTrusted) {
+            return null;
+          }
+
+          var browser = aEvent.originalTarget;
+          var tab = this.getTabForBrowser(browser);
+          return tab;
+        ]]>
+        </body>
+      </method>
+
       <method name="_callProgressListeners">
         <parameter name="aBrowser"/>
         <parameter name="aMethod"/>
         <parameter name="aArguments"/>
         <parameter name="aCallGlobalListeners"/>
         <parameter name="aCallTabsListeners"/>
         <body><![CDATA[
           var rv = true;
@@ -791,26 +807,28 @@
                 // Don't clear the favicon if this onLocationChange was
                 // triggered by a pushState or a replaceState (bug 550565) or
                 // a hash change (bug 408415).
                 if (aWebProgress.isLoadingDocument && !isSameDocument) {
                   this.mBrowser.mIconURL = null;
                 }
 
                 let unifiedComplete = this.mTabBrowser._unifiedComplete;
+                let userContextId = this.mBrowser.getAttribute("usercontextid") || 0;
                 if (this.mBrowser.registeredOpenURI) {
-                  unifiedComplete.unregisterOpenPage(this.mBrowser.registeredOpenURI);
+                  unifiedComplete.unregisterOpenPage(this.mBrowser.registeredOpenURI,
+                                                     userContextId);
                   delete this.mBrowser.registeredOpenURI;
                 }
                 // Tabs in private windows aren't registered as "Open" so
                 // that they don't appear as switch-to-tab candidates.
                 if (!isBlankPageURL(aLocation.spec) &&
                     (!PrivateBrowsingUtils.isWindowPrivate(window) ||
                     PrivateBrowsingUtils.permanentPrivateBrowsing)) {
-                  unifiedComplete.registerOpenPage(aLocation);
+                  unifiedComplete.registerOpenPage(aLocation, userContextId);
                   this.mBrowser.registeredOpenURI = aLocation;
                 }
               }
 
               if (!this.mBlank) {
                 this._callProgressListeners("onLocationChange",
                                             [aWebProgress, aRequest, aLocation,
                                              aFlags]);
@@ -2570,17 +2588,18 @@
 
             browser.webProgress.removeProgressListener(filter);
 
             const listener = this._tabListeners.get(aTab);
             filter.removeProgressListener(listener);
             listener.destroy();
 
             if (browser.registeredOpenURI && !aAdoptedByTab) {
-              this._unifiedComplete.unregisterOpenPage(browser.registeredOpenURI);
+              this._unifiedComplete.unregisterOpenPage(browser.registeredOpenURI,
+                                                       browser.getAttribute("usercontextid") || 0);
               delete browser.registeredOpenURI;
             }
 
             // We are no longer the primary content area.
             browser.setAttribute("type", "content-targetable");
 
             // Remove this tab as the owner of any other tabs, since it's going away.
             for (let tab of this.tabs) {
@@ -2942,17 +2961,18 @@
 
       <method name="_swapRegisteredOpenURIs">
         <parameter name="aOurBrowser"/>
         <parameter name="aOtherBrowser"/>
         <body>
           <![CDATA[
             // If the current URI is registered as open remove it from the list.
             if (aOurBrowser.registeredOpenURI) {
-              this._unifiedComplete.unregisterOpenPage(aOurBrowser.registeredOpenURI);
+              this._unifiedComplete.unregisterOpenPage(aOurBrowser.registeredOpenURI,
+                                                       aOurBrowser.getAttribute("usercontextid") || 0);
               delete aOurBrowser.registeredOpenURI;
             }
 
             // If the other/new URI is registered as open then copy it over.
             if (aOtherBrowser.registeredOpenURI) {
               aOurBrowser.registeredOpenURI = aOtherBrowser.registeredOpenURI;
               delete aOtherBrowser.registeredOpenURI;
             }
@@ -4532,19 +4552,24 @@
           } else if (tab._overPlayingIcon) {
             let stringID;
             if (tab.selected) {
               stringID = tab.linkedBrowser.audioMuted ?
                 "tabs.unmuteAudio.tooltip" :
                 "tabs.muteAudio.tooltip";
               label = stringWithShortcut(stringID, "key_toggleMute");
             } else {
-              stringID = tab.linkedBrowser.audioMuted ?
-                "tabs.unmuteAudio.background.tooltip" :
-                "tabs.muteAudio.background.tooltip";
+              if (tab.linkedBrowser.audioBlocked) {
+                stringID = "tabs.unblockAudio.tooltip";
+              } else {
+                stringID = tab.linkedBrowser.audioMuted ?
+                  "tabs.unmuteAudio.background.tooltip" :
+                  "tabs.muteAudio.background.tooltip";
+              }
+
               label = this.mStringBundle.getString(stringID);
             }
           } else {
             label = tab.getAttribute("label") +
                       (this.AppConstants.E10S_TESTING_ONLY && tab.linkedBrowser && tab.linkedBrowser.isRemoteBrowser ? " - e10s" : "");
           }
           event.target.setAttribute("label", label);
         ]]></body>
@@ -4848,17 +4873,18 @@
       <destructor>
         <![CDATA[
           Services.obs.removeObserver(this, "live-resize-start", false);
           Services.obs.removeObserver(this, "live-resize-end", false);
 
           for (let tab of this.tabs) {
             let browser = tab.linkedBrowser;
             if (browser.registeredOpenURI) {
-              this._unifiedComplete.unregisterOpenPage(browser.registeredOpenURI);
+              this._unifiedComplete.unregisterOpenPage(browser.registeredOpenURI,
+                                                       browser.getAttribute("usercontextid") || 0);
               delete browser.registeredOpenURI;
             }
             let filter = this._tabFilters.get(tab);
             let listener = this._tabListeners.get(tab);
 
             browser.webProgress.removeProgressListener(filter);
             filter.removeProgressListener(listener);
             listener.destroy();
@@ -5059,24 +5085,20 @@
           }
 
           tab.removeAttribute("soundplaying");
           this.setIcon(tab, icon, browser.contentPrincipal);
         ]]>
       </handler>
       <handler event="DOMAudioPlaybackStarted">
         <![CDATA[
-          if (!Services.prefs.getBoolPref("browser.tabs.showAudioPlayingIcon") ||
-              !event.isTrusted)
+          var tab = getTabFromAudioEvent(event)
+          if (!tab) {
             return;
-
-          var browser = event.originalTarget;
-          var tab = this.getTabForBrowser(browser);
-          if (!tab)
-            return;
+          }
 
           clearTimeout(tab._soundPlayingAttrRemovalTimer);
           tab._soundPlayingAttrRemovalTimer = 0;
 
           let modifiedAttrs = [];
           if (tab.hasAttribute("soundplaying-scheduledremoval")) {
             tab.removeAttribute("soundplaying-scheduledremoval");
             modifiedAttrs.push("soundplaying-scheduledremoval");
@@ -5087,40 +5109,62 @@
             modifiedAttrs.push("soundplaying");
           }
 
           this._tabAttrModified(tab, modifiedAttrs);
         ]]>
       </handler>
       <handler event="DOMAudioPlaybackStopped">
         <![CDATA[
-          if (!Services.prefs.getBoolPref("browser.tabs.showAudioPlayingIcon") ||
-              !event.isTrusted)
+          var tab = getTabFromAudioEvent(event)
+          if (!tab) {
             return;
-
-          var browser = event.originalTarget;
-          var tab = this.getTabForBrowser(browser);
-          if (!tab)
-            return;
+          }
 
           if (tab.hasAttribute("soundplaying")) {
             let removalDelay = Services.prefs.getIntPref("browser.tabs.delayHidingAudioPlayingIconMS");
 
             tab.style.setProperty("--soundplaying-removal-delay", `${removalDelay - 300}ms`);
             tab.setAttribute("soundplaying-scheduledremoval", "true");
             this._tabAttrModified(tab, ["soundplaying-scheduledremoval"]);
 
             tab._soundPlayingAttrRemovalTimer = setTimeout(() => {
               tab.removeAttribute("soundplaying-scheduledremoval");
               tab.removeAttribute("soundplaying");
               this._tabAttrModified(tab, ["soundplaying", "soundplaying-scheduledremoval"]);
             }, removalDelay);
           }
         ]]>
       </handler>
+      <handler event="DOMAudioPlaybackBlockStarted">
+        <![CDATA[
+          var tab = getTabFromAudioEvent(event)
+          if (!tab) {
+            return;
+          }
+
+          if (!tab.hasAttribute("blocked")) {
+            tab.setAttribute("blocked", true);
+            this._tabAttrModified(tab, ["blocked"]);
+          }
+        ]]>
+      </handler>
+      <handler event="DOMAudioPlaybackBlockStopped">
+        <![CDATA[
+          var tab = getTabFromAudioEvent(event)
+          if (!tab) {
+            return;
+          }
+
+          if (tab.hasAttribute("blocked")) {
+            tab.removeAttribute("blocked");
+            this._tabAttrModified(tab, ["blocked"]);
+          }
+        ]]>
+      </handler>
     </handlers>
   </binding>
 
   <binding id="tabbrowser-tabbox"
            extends="chrome://global/content/bindings/tabbox.xml#tabbox">
     <implementation>
       <property name="tabs" readonly="true"
                 onget="return document.getBindingParent(this).tabContainer;"/>
@@ -5231,17 +5275,17 @@
                            onmouseover="document.getBindingParent(this)._enterNewTab();"
                            onmouseout="document.getBindingParent(this)._leaveNewTab();"
                            tooltip="dynamic-shortcut-tooltip"/>
         <xul:spacer class="closing-tabs-spacer" anonid="closing-tabs-spacer"
                     style="width: 0;"/>
       </xul:arrowscrollbox>
     </content>
 
-    <implementation implements="nsIDOMEventListener">
+    <implementation implements="nsIDOMEventListener, nsIObserver">
       <constructor>
         <![CDATA[
           this.mTabClipWidth = Services.prefs.getIntPref("browser.tabs.tabClipWidth");
 
           var tab = this.firstChild;
           tab.label = this.tabbrowser.mStringBundle.getString("tabs.emptyTabTitle");
           tab.setAttribute("crop", "end");
           tab.setAttribute("onerror", "this.removeAttribute('image');");
@@ -5250,19 +5294,27 @@
           window.addEventListener("load", this, false);
 
           try {
             this._tabAnimationLoggingEnabled = Services.prefs.getBoolPref("browser.tabs.animationLogging.enabled");
           } catch (ex) {
             this._tabAnimationLoggingEnabled = false;
           }
           this._browserNewtabpageEnabled = Services.prefs.getBoolPref("browser.newtabpage.enabled");
+          this.observe(null, "nsPref:changed", "privacy.userContext.enabled");
+          Services.prefs.addObserver("privacy.userContext.enabled", this, false);
         ]]>
       </constructor>
 
+      <destructor>
+        <![CDATA[
+          Services.prefs.removeObserver("privacy.userContext.enabled", this);
+        ]]>
+      </destructor>
+
       <field name="tabbrowser" readonly="true">
         document.getElementById(this.getAttribute("tabbrowser"));
       </field>
 
       <field name="tabbox" readonly="true">
         this.tabbrowser.mTabBox;
       </field>
 
@@ -5278,16 +5330,63 @@
 
       <field name="_firstTab">null</field>
       <field name="_lastTab">null</field>
       <field name="_afterSelectedTab">null</field>
       <field name="_beforeHoveredTab">null</field>
       <field name="_afterHoveredTab">null</field>
       <field name="_hoveredTab">null</field>
 
+      <method name="observe">
+        <parameter name="aSubject"/>
+        <parameter name="aTopic"/>
+        <parameter name="aData"/>
+        <body><![CDATA[
+          switch (aTopic) {
+            case "nsPref:changed":
+              // This is the only pref observed.
+              let containersEnabled = Services.prefs.getBoolPref("privacy.userContext.enabled");
+
+              const newTab = document.getElementById("new-tab-button");
+              const newTab2 = document.getAnonymousElementByAttribute(this, "anonid", "tabs-newtab-button")
+
+              if (containersEnabled) {
+                for (let parent of [newTab, newTab2]) {
+                  if (!parent)
+                    continue;
+                  let popup = document.createElementNS(
+                                "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
+                                "menupopup");
+                  if (parent.id) {
+                    popup.id = "newtab-popup";
+                  } else {
+                    popup.setAttribute("anonid", "newtab-popup");
+                  }
+                  popup.className = "new-tab-popup";
+                  popup.setAttribute("position", "after_end");
+                  parent.appendChild(popup);
+
+                  gClickAndHoldListenersOnElement.add(parent);
+                  parent.setAttribute("type", "menu");
+                }
+              } else {
+                for (let parent of [newTab, newTab2]) {
+                  if (!parent)
+                    continue;
+                  gClickAndHoldListenersOnElement.remove(parent);
+                  parent.removeAttribute("type");
+                  parent.firstChild.remove();
+                }
+              }
+
+              break;
+          }
+        ]]></body>
+      </method>
+
       <property name="_isCustomizing" readonly="true">
         <getter>
           let root = document.documentElement;
           return root.getAttribute("customizing") == "true" ||
                  root.getAttribute("customize-exiting") == "true";
         </getter>
       </property>
 
@@ -6551,25 +6650,25 @@
                      anonid="tab-icon-image"
                      class="tab-icon-image"
                      validate="never"
                      role="presentation"/>
           <xul:image xbl:inherits="sharing,selected=visuallyselected"
                      anonid="sharing-icon"
                      class="tab-sharing-icon-overlay"
                      role="presentation"/>
-          <xul:image xbl:inherits="crashed,busy,soundplaying,soundplaying-scheduledremoval,pinned,muted,selected=visuallyselected"
+          <xul:image xbl:inherits="crashed,busy,soundplaying,soundplaying-scheduledremoval,pinned,muted,blocked,selected=visuallyselected"
                      anonid="overlay-icon"
                      class="tab-icon-overlay"
                      role="presentation"/>
           <xul:label flex="1"
                      xbl:inherits="value=label,crop,accesskey,fadein,pinned,selected=visuallyselected,attention"
                      class="tab-text tab-label"
                      role="presentation"/>
-          <xul:image xbl:inherits="soundplaying,soundplaying-scheduledremoval,pinned,muted,selected=visuallyselected"
+          <xul:image xbl:inherits="soundplaying,soundplaying-scheduledremoval,pinned,muted,blocked,selected=visuallyselected"
                      anonid="soundplaying-icon"
                      class="tab-icon-sound"
                      role="presentation"/>
           <xul:toolbarbutton anonid="close-button"
                              xbl:inherits="fadein,pinned,selected=visuallyselected"
                              class="tab-close-button close-icon"/>
         </xul:hbox>
       </xul:stack>
@@ -6632,16 +6731,21 @@
           return this.getAttribute("hidden") == "true";
         </getter>
       </property>
       <property name="muted" readonly="true">
         <getter>
           return this.getAttribute("muted") == "true";
         </getter>
       </property>
+      <property name="blocked" readonly="true">
+        <getter>
+          return this.getAttribute("blocked") == "true";
+        </getter>
+      </property>
       <!--
       Describes how the tab ended up in this mute state. May be any of:
 
        - undefined: The tabs mute state has never changed.
        - null: The mute state was last changed through the UI.
        - Any string: The ID was changed through an extension API. The string
                      must be the ID of the extension which changed it.
       -->
@@ -6674,17 +6778,18 @@
       </method>
 
       <field name="cachePosition">Infinity</field>
 
       <field name="mOverCloseButton">false</field>
       <property name="_overPlayingIcon" readonly="true">
         <getter><![CDATA[
           let iconVisible = this.hasAttribute("soundplaying") ||
-                            this.hasAttribute("muted");
+                            this.hasAttribute("muted") ||
+                            this.hasAttribute("blocked");
           let soundPlayingIcon =
             document.getAnonymousElementByAttribute(this, "anonid", "soundplaying-icon");
           let overlayIcon =
             document.getAnonymousElementByAttribute(this, "anonid", "overlay-icon");
 
           return soundPlayingIcon && soundPlayingIcon.matches(":hover") ||
                  (overlayIcon && overlayIcon.matches(":hover") && iconVisible);
         ]]></getter>
@@ -6747,27 +6852,44 @@
       </method>
 
       <method name="toggleMuteAudio">
         <parameter name="aMuteReason"/>
         <body>
         <![CDATA[
           let tabContainer = this.parentNode;
           let browser = this.linkedBrowser;
-          if (browser.audioMuted) {
-            browser.unmute();
-            this.removeAttribute("muted");
-            BrowserUITelemetry.countTabMutingEvent("unmute", aMuteReason);
+          let modifiedAttrs = [];
+          if (browser.audioBlocked) {
+            this.removeAttribute("blocked");
+            modifiedAttrs.push("blocked");
+
+            // We don't want sound icon flickering between "blocked", "none" and
+            // "sound-playing", here adding the "soundplaying" is to keep the
+            // transition smoothly.
+            if (!this.hasAttribute("soundplaying")) {
+              this.setAttribute("soundplaying", true);
+              modifiedAttrs.push("soundplaying");
+            }
+
+            browser.resumeMedia();
           } else {
-            browser.mute();
-            this.setAttribute("muted", "true");
-            BrowserUITelemetry.countTabMutingEvent("mute", aMuteReason);
+            if (browser.audioMuted) {
+              browser.unmute();
+              this.removeAttribute("muted");
+              BrowserUITelemetry.countTabMutingEvent("unmute", aMuteReason);
+            } else {
+              browser.mute();
+              this.setAttribute("muted", "true");
+              BrowserUITelemetry.countTabMutingEvent("mute", aMuteReason);
+            }
+            this.muteReason = aMuteReason || null;
+            modifiedAttrs.push("muted");
           }
-          this.muteReason = aMuteReason || null;
-          tabContainer.tabbrowser._tabAttrModified(this, ["muted"]);
+          tabContainer.tabbrowser._tabAttrModified(this, modifiedAttrs);
         ]]>
         </body>
       </method>
 
       <method name="setUserContextId">
         <parameter name="aUserContextId"/>
         <body>
         <![CDATA[
@@ -6958,61 +7080,70 @@
             addEndImage().setAttribute("soundplaying", "true");
         ]]></body>
       </method>
     </implementation>
 
     <handlers>
       <handler event="popupshowing">
       <![CDATA[
-        if (event.target.getAttribute('id') == "alltabs_containersMenuTab") {
+        if (event.target.getAttribute("id") == "alltabs_containersMenuTab") {
           createUserContextMenu(event);
           return;
         }
 
         let containersEnabled = Services.prefs.getBoolPref("privacy.userContext.enabled");
-        document.getElementById("alltabs-popup-separator-1").hidden = !containersEnabled;
-        let containersTab = document.getElementById("alltabs_containersTab");
-
-        containersTab.hidden = !containersEnabled;
-        if (PrivateBrowsingUtils.isWindowPrivate(window)) {
-          containersTab.setAttribute("disabled", "true");
+
+        if (event.target.getAttribute("anonid") == "newtab-popup" ||
+            event.target.id == "newtab-popup") {
+          createUserContextMenu(event);
+        } else {
+          document.getElementById("alltabs-popup-separator-1").hidden = !containersEnabled;
+          let containersTab = document.getElementById("alltabs_containersTab");
+
+          containersTab.hidden = !containersEnabled;
+          if (PrivateBrowsingUtils.isWindowPrivate(window)) {
+            containersTab.setAttribute("disabled", "true");
+          }
+
+          document.getElementById("alltabs_undoCloseTab").disabled =
+            SessionStore.getClosedTabCount(window) == 0;
+
+          var tabcontainer = gBrowser.tabContainer;
+
+          // Listen for changes in the tab bar.
+          tabcontainer.addEventListener("TabAttrModified", this, false);
+          tabcontainer.addEventListener("TabClose", this, false);
+          tabcontainer.mTabstrip.addEventListener("scroll", this, false);
+
+          let tabs = gBrowser.visibleTabs;
+          for (var i = 0; i < tabs.length; i++) {
+            if (!tabs[i].pinned)
+              this._createTabMenuItem(tabs[i]);
+          }
+          this._updateTabsVisibilityStatus();
         }
-
-        document.getElementById("alltabs_undoCloseTab").disabled =
-          SessionStore.getClosedTabCount(window) == 0;
-
-        var tabcontainer = gBrowser.tabContainer;
-
-        // Listen for changes in the tab bar.
-        tabcontainer.addEventListener("TabAttrModified", this, false);
-        tabcontainer.addEventListener("TabClose", this, false);
-        tabcontainer.mTabstrip.addEventListener("scroll", this, false);
-
-        let tabs = gBrowser.visibleTabs;
-        for (var i = 0; i < tabs.length; i++) {
-          if (!tabs[i].pinned)
-            this._createTabMenuItem(tabs[i]);
-        }
-        this._updateTabsVisibilityStatus();
       ]]></handler>
 
       <handler event="popuphidden">
       <![CDATA[
-        if (event.target.getAttribute('id') == "alltabs_containersMenuTab") {
+        if (event.target.getAttribute("id") == "alltabs_containersMenuTab") {
           return;
         }
 
         // clear out the menu popup and remove the listeners
         for (let i = this.childNodes.length - 1; i > 0; i--) {
           let menuItem = this.childNodes[i];
           if (menuItem.tab) {
             menuItem.tab.mCorrespondingMenuitem = null;
             this.removeChild(menuItem);
           }
+          if (menuItem.hasAttribute("usercontextid")) {
+            this.removeChild(menuItem);
+          }
         }
         var tabcontainer = gBrowser.tabContainer;
         tabcontainer.mTabstrip.removeEventListener("scroll", this, false);
         tabcontainer.removeEventListener("TabAttrModified", this, false);
         tabcontainer.removeEventListener("TabClose", this, false);
       ]]></handler>
 
       <handler event="DOMMenuItemActive">
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -479,22 +479,15 @@ tags = psm
 [browser_mcb_redirect.js]
 tags = mcb
 [browser_windowactivation.js]
 [browser_contextmenu_childprocess.js]
 [browser_bug963945.js]
 [browser_domFullscreen_fullscreenMode.js]
 tags = fullscreen
 [browser_menuButtonBadgeManager.js]
-[browser_aboutTabCrashed.js]
-skip-if = !e10s || !crashreporter
-[browser_aboutTabCrashed_clearEmail.js]
-skip-if = !e10s || !crashreporter
 [browser_newTabDrop.js]
 [browser_newWindowDrop.js]
-[browser_aboutTabCrashed_showForm.js]
-skip-if = !e10s || !crashreporter
-[browser_aboutTabCrashed_withoutDump.js]
-skip-if = !e10s
 [browser_csp_block_all_mixedcontent.js]
 tags = mcb
 [browser_newwindow_focus.js]
 skip-if = (os == "linux" && !e10s) # Bug 1263254 - Perma fails on Linux without e10s for some reason.
+[browser_bug1299667.js]
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/browser_bug1299667.js
@@ -0,0 +1,71 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const { addObserver, removeObserver } = Cc["@mozilla.org/observer-service;1"].
+                                          getService(Ci.nsIObserverService);
+
+function receive(topic) {
+  return new Promise((resolve, reject) => {
+    let timeout = setTimeout(() => {
+      reject(new Error("Timeout"));
+    }, 90000);
+
+    const observer = {
+      observe: subject => {
+        removeObserver(observer, topic);
+        clearTimeout(timeout);
+        resolve(subject);
+      }
+    };
+    addObserver(observer, topic, false);
+  });
+}
+
+add_task(function* () {
+  yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com");
+
+  yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
+    content.history.pushState({}, "2", "2.html");
+  });
+
+  yield receive("sessionstore-state-write-complete");
+
+  // Wait for the session data to be flushed before continuing the test
+  yield new Promise(resolve => SessionStore.getSessionHistory(gBrowser.selectedTab, resolve));
+
+  let backButton = document.getElementById("back-button");
+  let contextMenu = document.getElementById("backForwardMenu");
+
+  info("waiting for the history menu to open");
+
+  let popupShownPromise = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
+  EventUtils.synthesizeMouseAtCenter(backButton, {type: "contextmenu", button: 2});
+  let event = yield popupShownPromise;
+
+  ok(true, "history menu opened");
+
+  // Wait for the session data to be flushed before continuing the test
+  yield new Promise(resolve => SessionStore.getSessionHistory(gBrowser.selectedTab, resolve));
+
+  is(event.target.children.length, 2, "Two history items");
+
+  let node = event.target.firstChild;
+  is(node.getAttribute("uri"), "http://example.com/2.html", "first item uri");
+  is(node.getAttribute("index"), "1", "first item index");
+  is(node.getAttribute("historyindex"), "0", "first item historyindex");
+
+  node = event.target.lastChild;
+  is(node.getAttribute("uri"), "http://example.com/", "second item uri");
+  is(node.getAttribute("index"), "0", "second item index");
+  is(node.getAttribute("historyindex"), "-1", "second item historyindex");
+
+  let popupHiddenPromise = BrowserTestUtils.waitForEvent(contextMenu, "popuphidden");
+  event.target.hidePopup();
+  yield popupHiddenPromise;
+  info("Hidden popup");
+
+  let onClose = BrowserTestUtils.waitForEvent(gBrowser.tabContainer, "TabClose");
+  yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
+  yield onClose;
+  info("Tab closed");
+});
--- a/browser/base/content/test/general/browser_bug575561.js
+++ b/browser/base/content/test/general/browser_bug575561.js
@@ -32,21 +32,21 @@ add_task(function*() {
   // Tests link to http://www.example.com/browser/browser/base/content/test/general/dummy_page.html
   yield testLink(4, true, false);
 
   // Pinned: Link to a data: URI should not open a new tab
   // Tests link to data:text/html,<!DOCTYPE html><html><body>Another Page</body></html>
   yield testLink(5, true, false);
 
   // Pinned: Link to an about: URI should not open a new tab
-  // Tests link to about:mozilla
+  // Tests link to about:logo
   yield testLink(function(doc) {
     let link = doc.createElement("a");
     link.textContent = "Link to Mozilla";
-    link.href = "about:mozilla";
+    link.href = "about:logo";
     doc.body.appendChild(link);
     return link;
   }, true, false, false, "about:robots");
 });
 
 var waitForPageLoad = Task.async(function*(browser, linkLocation) {
   yield waitForDocLoadComplete();
 
--- a/browser/base/content/test/general/head.js
+++ b/browser/base/content/test/general/head.js
@@ -986,114 +986,16 @@ function promiseOnBookmarkItemAdded(aExp
         Ci.nsINavBookmarkObserver,
       ])
     };
     info("Waiting for a bookmark to be added");
     PlacesUtils.bookmarks.addObserver(bookmarksObserver, false);
   });
 }
 
-/**
- * For an nsIPropertyBag, returns the value for a given
- * key.
- *
- * @param bag
- *        The nsIPropertyBag to retrieve the value from
- * @param key
- *        The key that we want to get the value for from the
- *        bag
- * @returns The value corresponding to the key from the bag,
- *          or null if the value could not be retrieved (for
- *          example, if no value is set at that key).
-*/
-function getPropertyBagValue(bag, key) {
-  try {
-    let val = bag.getProperty(key);
-    return val;
-  } catch (e) {
-    if (e.result != Cr.NS_ERROR_FAILURE) {
-      throw e;
-    }
-  }
-
-  return null;
-}
-
-/**
- * Returns a Promise that resolves once a crash report has
- * been submitted. This function will also test the crash
- * reports extra data to see if it matches expectedExtra.
- *
- * @param expectedExtra (object)
- *        An Object whose key-value pairs will be compared
- *        against the key-value pairs in the extra data of the
- *        crash report. A test failure will occur if there is
- *        a mismatch.
- *
- *        If the value of the key-value pair is "null", this will
- *        be interpreted as "this key should not be included in the
- *        extra data", and will cause a test failure if it is detected
- *        in the crash report.
- *
- *        Note that this will ignore any keys that are not included
- *        in expectedExtra. It's possible that the crash report
- *        will contain other extra information that is not
- *        compared against.
- * @returns Promise
- */
-function promiseCrashReport(expectedExtra={}) {
-  return Task.spawn(function*() {
-    info("Starting wait on crash-report-status");
-    let [subject, ] =
-      yield TestUtils.topicObserved("crash-report-status", (unused, data) => {
-        return data == "success";
-      });
-    info("Topic observed!");
-
-    if (!(subject instanceof Ci.nsIPropertyBag2)) {
-      throw new Error("Subject was not a Ci.nsIPropertyBag2");
-    }
-
-    let remoteID = getPropertyBagValue(subject, "serverCrashID");
-    if (!remoteID) {
-      throw new Error("Report should have a server ID");
-    }
-
-    let file = Cc["@mozilla.org/file/local;1"]
-                 .createInstance(Ci.nsILocalFile);
-    file.initWithPath(Services.crashmanager._submittedDumpsDir);
-    file.append(remoteID + ".txt");
-    if (!file.exists()) {
-      throw new Error("Report should have been received by the server");
-    }
-
-    file.remove(false);
-
-    let extra = getPropertyBagValue(subject, "extra");
-    if (!(extra instanceof Ci.nsIPropertyBag2)) {
-      throw new Error("extra was not a Ci.nsIPropertyBag2");
-    }
-
-    info("Iterating crash report extra keys");
-    let enumerator = extra.enumerator;
-    while (enumerator.hasMoreElements()) {
-      let key = enumerator.getNext().QueryInterface(Ci.nsIProperty).name;
-      let value = extra.getPropertyAsAString(key);
-      if (key in expectedExtra) {
-        if (expectedExtra[key] == null) {
-          ok(false, `Got unexpected key ${key} with value ${value}`);
-        } else {
-          is(value, expectedExtra[key],
-             `Crash report had the right extra value for ${key}`);
-        }
-      }
-    }
-  });
-}
-
 function promiseErrorPageLoaded(browser) {
   return new Promise(resolve => {
     browser.addEventListener("DOMContentLoaded", function onLoad() {
       browser.removeEventListener("DOMContentLoaded", onLoad, false, true);
       resolve();
     }, false, true);
   });
 }
--- a/browser/base/content/test/plugins/browser.ini
+++ b/browser/base/content/test/plugins/browser.ini
@@ -51,17 +51,16 @@ skip-if = toolkit == "gtk2" || toolkit =
 [browser_CTP_crashreporting.js]
 skip-if = !crashreporter
 [browser_CTP_data_urls.js]
 [browser_CTP_drag_drop.js]
 [browser_CTP_hide_overlay.js]
 [browser_CTP_iframe.js]
 [browser_CTP_multi_allow.js]
 [browser_CTP_nonplugins.js]
-skip-if = e10s # Bug 1315042
 [browser_CTP_notificationBar.js]
 [browser_CTP_outsideScrollArea.js]
 [browser_CTP_remove_navigate.js]
 [browser_CTP_resize.js]
 [browser_CTP_zoom.js]
 [browser_blocking.js]
 [browser_plugins_added_dynamically.js]
 [browser_pluginnotification.js]
--- a/browser/base/content/test/referrer/browser.ini
+++ b/browser/base/content/test/referrer/browser.ini
@@ -1,17 +1,16 @@
 [DEFAULT]
 support-files =
   file_referrer_policyserver.sjs
   file_referrer_policyserver_attr.sjs
   file_referrer_testserver.sjs
   head.js
 
 [browser_referrer_middle_click.js]
-skip-if = e10s # Bug 1315042
 [browser_referrer_middle_click_in_container.js]
 [browser_referrer_open_link_in_private.js]
 skip-if = os == 'linux' # Bug 1145199
 [browser_referrer_open_link_in_tab.js]
 skip-if = os == 'linux' # Bug 1144816
 [browser_referrer_open_link_in_window.js]
 skip-if = os == 'linux' # Bug 1145199
 [browser_referrer_open_link_in_window_in_container.js]
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabcrashed/browser.ini
@@ -0,0 +1,13 @@
+[DEFAULT]
+support-files =
+  head.js
+[browser_shown.js]
+skip-if = !e10s || !crashreporter
+[browser_clearEmail.js]
+skip-if = !e10s || !crashreporter
+[browser_showForm.js]
+skip-if = !e10s || !crashreporter
+[browser_withoutDump.js]
+skip-if = !e10s
+[browser_autoSubmitRequest.js]
+skip-if = !e10s || !crashreporter
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabcrashed/browser_autoSubmitRequest.js
@@ -0,0 +1,97 @@
+"use strict";
+
+const PAGE = "data:text/html,<html><body>A%20regular,%20everyday,%20normal%20page.";
+const AUTOSUBMIT_PREF = "browser.crashReports.unsubmittedCheck.autoSubmit";
+
+const {TabStateFlusher} =
+  Cu.import("resource:///modules/sessionstore/TabStateFlusher.jsm", {});
+
+// On debug builds, crashing tabs results in much thinking, which
+// slows down the test and results in intermittent test timeouts,
+// so we'll pump up the expected timeout for this test.
+requestLongerTimeout(2);
+
+/**
+ * Tests that if the user is not configured to autosubmit
+ * backlogged crash reports, that we offer to do that, and
+ * that the user can accept that offer.
+ */
+add_task(function* test_show_form() {
+  yield SpecialPowers.pushPrefEnv({
+    set: [[AUTOSUBMIT_PREF, false]],
+  })
+
+  return BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: PAGE,
+  }, function*(browser) {
+    // Make sure we've flushed the browser messages so that
+    // we can restore it.
+    yield TabStateFlusher.flush(browser);
+
+    // Now crash the browser.
+    yield BrowserTestUtils.crashBrowser(browser);
+
+    let doc = browser.contentDocument;
+
+    // Ensure the request is visible. We can safely reach into
+    // the content since about:tabcrashed is an in-process URL.
+    let requestAutoSubmit = doc.getElementById("requestAutoSubmit");
+    Assert.ok(!requestAutoSubmit.hidden,
+              "Request for autosubmission is visible.");
+
+    // Since the pref is set to false, the checkbox should be
+    // unchecked.
+    let autoSubmit = doc.getElementById("autoSubmit");
+    Assert.ok(!autoSubmit.checked,
+              "Checkbox for autosubmission is not checked.")
+
+    // Check the checkbox, and then restore the tab.
+    autoSubmit.checked = true;
+    let restoreButton = doc.getElementById("restoreTab");
+    restoreButton.click();
+
+    yield BrowserTestUtils.browserLoaded(browser, false, PAGE);
+
+    // The autosubmission pref should now be set.
+    Assert.ok(Services.prefs.getBoolPref(AUTOSUBMIT_PREF),
+              "Autosubmission pref should have been set.");
+  });
+});
+
+/**
+ * Tests that if the user is autosubmitting backlogged crash reports
+ * that we don't make the offer again.
+ */
+add_task(function* test_show_form() {
+  yield SpecialPowers.pushPrefEnv({
+    set: [[AUTOSUBMIT_PREF, true]],
+  })
+
+  return BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: PAGE,
+  }, function*(browser) {
+    yield TabStateFlusher.flush(browser);
+    // Now crash the browser.
+    yield BrowserTestUtils.crashBrowser(browser);
+
+    let doc = browser.contentDocument;
+
+    // Ensure the request is NOT visible. We can safely reach into
+    // the content since about:tabcrashed is an in-process URL.
+    let requestAutoSubmit = doc.getElementById("requestAutoSubmit");
+    Assert.ok(requestAutoSubmit.hidden,
+              "Request for autosubmission is not visible.");
+
+    // Restore the tab.
+    let restoreButton = doc.getElementById("restoreTab");
+    restoreButton.click();
+
+    yield BrowserTestUtils.browserLoaded(browser, false, PAGE);
+
+    // The autosubmission pref should still be set to true.
+    Assert.ok(Services.prefs.getBoolPref(AUTOSUBMIT_PREF),
+              "Autosubmission pref should have been set.");
+  });
+});
rename from browser/base/content/test/general/browser_aboutTabCrashed_clearEmail.js
rename to browser/base/content/test/tabcrashed/browser_clearEmail.js
--- a/browser/base/content/test/general/browser_aboutTabCrashed_clearEmail.js
+++ b/browser/base/content/test/tabcrashed/browser_clearEmail.js
@@ -16,16 +16,22 @@ add_task(function* setup() {
   // which CrashSubmit.jsm uses as a server override.
   let env = Cc["@mozilla.org/process/environment;1"]
               .getService(Components.interfaces.nsIEnvironment);
   let noReport = env.get("MOZ_CRASHREPORTER_NO_REPORT");
   let serverUrl = env.get("MOZ_CRASHREPORTER_URL");
   env.set("MOZ_CRASHREPORTER_NO_REPORT", "");
   env.set("MOZ_CRASHREPORTER_URL", SERVER_URL);
 
+  // By default, requesting the email address of the user is disabled.
+  // For the purposes of this test, we turn it back on.
+  yield SpecialPowers.pushPrefEnv({
+    set: [["browser.tabs.crashReporting.requestEmail", true]],
+  });
+
   registerCleanupFunction(function() {
     env.set("MOZ_CRASHREPORTER_NO_REPORT", noReport);
     env.set("MOZ_CRASHREPORTER_URL", serverUrl);
   });
 });
 
 /**
  * Test that if we have an email address stored in prefs, and we decide
rename from browser/base/content/test/general/browser_aboutTabCrashed_showForm.js
rename to browser/base/content/test/tabcrashed/browser_showForm.js
--- a/browser/base/content/test/general/browser_aboutTabCrashed_showForm.js
+++ b/browser/base/content/test/tabcrashed/browser_showForm.js
@@ -14,25 +14,27 @@ requestLongerTimeout(2);
 add_task(function* test_show_form() {
   return BrowserTestUtils.withNewTab({
     gBrowser,
     url: PAGE,
   }, function*(browser) {
     // Flip the pref so that the checkbox should be checked
     // by default.
     let pref = TabCrashHandler.prefs.root + "sendReport";
-    yield pushPrefs([pref, true]);
+    yield SpecialPowers.pushPrefEnv({
+      set: [[pref, true]]
+    });
 
     // Now crash the browser.
     yield BrowserTestUtils.crashBrowser(browser);
 
     let doc = browser.contentDocument;
 
     // Ensure the checkbox is checked. We can safely reach into
     // the content since about:tabcrashed is an in-process URL.
     let checkbox = doc.getElementById("sendReport");
     ok(checkbox.checked, "Send report checkbox is checked.");
 
-    // Ensure the form is displayed.
-    let container = doc.getElementById("crash-reporter-container");
-    ok(!container.hidden, "Showing the crash report detail form.");
+    // Ensure the options form is displayed.
+    let options = doc.getElementById("options");
+    ok(!options.hidden, "Showing the crash report options form.");
   });
 });
rename from browser/base/content/test/general/browser_aboutTabCrashed.js
rename to browser/base/content/test/tabcrashed/browser_shown.js
rename from browser/base/content/test/general/browser_aboutTabCrashed_withoutDump.js
rename to browser/base/content/test/tabcrashed/browser_withoutDump.js
--- a/browser/base/content/test/general/browser_aboutTabCrashed_withoutDump.js
+++ b/browser/base/content/test/tabcrashed/browser_withoutDump.js
@@ -27,18 +27,18 @@ add_task(function* test_without_dump() {
 
     let tabRemovedPromise = BrowserTestUtils.removeTab(tab, { dontRemove: true });
 
     yield ContentTask.spawn(browser, null, function*() {
       let doc = content.document;
       Assert.ok(!doc.documentElement.classList.contains("crashDumpAvailable"),
          "doesn't have crash dump");
 
-      let container = doc.getElementById("crash-reporter-container");
-      Assert.ok(container, "has crash-reporter-container");
-      Assert.ok(container.hidden, "crash-reporter-container is hidden");
+      let options = doc.getElementById("options");
+      Assert.ok(options, "has crash report options");
+      Assert.ok(options.hidden, "crash report options are hidden");
 
       doc.getElementById("closeTab").click();
     });
 
     yield tabRemovedPromise;
   });
 });
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabcrashed/head.js
@@ -0,0 +1,98 @@
+/**
+ * Returns a Promise that resolves once a crash report has
+ * been submitted. This function will also test the crash
+ * reports extra data to see if it matches expectedExtra.
+ *
+ * @param expectedExtra (object)
+ *        An Object whose key-value pairs will be compared
+ *        against the key-value pairs in the extra data of the
+ *        crash report. A test failure will occur if there is
+ *        a mismatch.
+ *
+ *        If the value of the key-value pair is "null", this will
+ *        be interpreted as "this key should not be included in the
+ *        extra data", and will cause a test failure if it is detected
+ *        in the crash report.
+ *
+ *        Note that this will ignore any keys that are not included
+ *        in expectedExtra. It's possible that the crash report
+ *        will contain other extra information that is not
+ *        compared against.
+ * @returns Promise
+ */
+function promiseCrashReport(expectedExtra={}) {
+  return Task.spawn(function*() {
+    info("Starting wait on crash-report-status");
+    let [subject, ] =
+      yield TestUtils.topicObserved("crash-report-status", (unused, data) => {
+        return data == "success";
+      });
+    info("Topic observed!");
+
+    if (!(subject instanceof Ci.nsIPropertyBag2)) {
+      throw new Error("Subject was not a Ci.nsIPropertyBag2");
+    }
+
+    let remoteID = getPropertyBagValue(subject, "serverCrashID");
+    if (!remoteID) {
+      throw new Error("Report should have a server ID");
+    }
+
+    let file = Cc["@mozilla.org/file/local;1"]
+                 .createInstance(Ci.nsILocalFile);
+    file.initWithPath(Services.crashmanager._submittedDumpsDir);
+    file.append(remoteID + ".txt");
+    if (!file.exists()) {
+      throw new Error("Report should have been received by the server");
+    }
+
+    file.remove(false);
+
+    let extra = getPropertyBagValue(subject, "extra");
+    if (!(extra instanceof Ci.nsIPropertyBag2)) {
+      throw new Error("extra was not a Ci.nsIPropertyBag2");
+    }
+
+    info("Iterating crash report extra keys");
+    let enumerator = extra.enumerator;
+    while (enumerator.hasMoreElements()) {
+      let key = enumerator.getNext().QueryInterface(Ci.nsIProperty).name;
+      let value = extra.getPropertyAsAString(key);
+      if (key in expectedExtra) {
+        if (expectedExtra[key] == null) {
+          ok(false, `Got unexpected key ${key} with value ${value}`);
+        } else {
+          is(value, expectedExtra[key],
+             `Crash report had the right extra value for ${key}`);
+        }
+      }
+    }
+  });
+}
+
+
+/**
+ * For an nsIPropertyBag, returns the value for a given
+ * key.
+ *
+ * @param bag
+ *        The nsIPropertyBag to retrieve the value from
+ * @param key
+ *        The key that we want to get the value for from the
+ *        bag
+ * @returns The value corresponding to the key from the bag,
+ *          or null if the value could not be retrieved (for
+ *          example, if no value is set at that key).
+*/
+function getPropertyBagValue(bag, key) {
+  try {
+    let val = bag.getProperty(key);
+    return val;
+  } catch (e) {
+    if (e.result != Cr.NS_ERROR_FAILURE) {
+      throw e;
+    }
+  }
+
+  return null;
+}
--- a/browser/base/content/test/webrtc/browser.ini
+++ b/browser/base/content/test/webrtc/browser.ini
@@ -4,9 +4,8 @@ support-files =
   get_user_media_content_script.js
   head.js
 
 [browser_devices_get_user_media.js]
 skip-if = (os == "linux" && debug) # linux: bug 976544
 [browser_devices_get_user_media_anim.js]
 [browser_devices_get_user_media_in_frame.js]
 [browser_devices_get_user_media_tear_off_tab.js]
-skip-if = e10s # Bug 1315042
--- a/browser/base/content/test/webrtc/browser_devices_get_user_media.js
+++ b/browser/base/content/test/webrtc/browser_devices_get_user_media.js
@@ -19,18 +19,19 @@ var gTests = [
     let promise = promisePopupNotificationShown("webRTC-shareDevices");
     yield promiseRequestDevice(true, true);
     yield promise;
     yield expectObserverCalled("getUserMedia:request");
 
     is(PopupNotifications.getNotification("webRTC-shareDevices").anchorID,
        "webRTC-shareDevices-notification-icon", "anchored to device icon");
     checkDeviceSelectors(true, true);
-    is(PopupNotifications.panel.firstChild.getAttribute("popupid"),
-       "webRTC-shareDevices", "panel using devices icon");
+    let iconclass =
+      PopupNotifications.panel.firstChild.getAttribute("iconclass");
+    ok(iconclass.includes("camera-icon"), "panel using devices icon");
 
     let indicator = promiseIndicatorWindow();
     yield promiseMessage("ok", () => {
       PopupNotifications.panel.firstChild.button.click();
     });
     yield expectObserverCalled("getUserMedia:response:allow");
     yield expectObserverCalled("recording-device-events");
     is((yield getMediaCaptureState()), "CameraAndMicrophone",
@@ -48,18 +49,19 @@ var gTests = [
     let promise = promisePopupNotificationShown("webRTC-shareDevices");
     yield promiseRequestDevice(true);
     yield promise;
     yield expectObserverCalled("getUserMedia:request");
 
     is(PopupNotifications.getNotification("webRTC-shareDevices").anchorID,
        "webRTC-shareMicrophone-notification-icon", "anchored to mic icon");
     checkDeviceSelectors(true);
-    is(PopupNotifications.panel.firstChild.getAttribute("popupid"),
-       "webRTC-shareMicrophone", "panel using microphone icon");
+    let iconclass =
+      PopupNotifications.panel.firstChild.getAttribute("iconclass");
+    ok(iconclass.includes("microphone-icon"), "panel using microphone icon");
 
     let indicator = promiseIndicatorWindow();
     yield promiseMessage("ok", () => {
       PopupNotifications.panel.firstChild.button.click();
     });
     yield expectObserverCalled("getUserMedia:response:allow");
     yield expectObserverCalled("recording-device-events");
     is((yield getMediaCaptureState()), "Microphone",
@@ -77,18 +79,19 @@ var gTests = [
     let promise = promisePopupNotificationShown("webRTC-shareDevices");
     yield promiseRequestDevice(false, true);
     yield promise;
     yield expectObserverCalled("getUserMedia:request");
 
     is(PopupNotifications.getNotification("webRTC-shareDevices").anchorID,
        "webRTC-shareDevices-notification-icon", "anchored to device icon");
     checkDeviceSelectors(false, true);
-    is(PopupNotifications.panel.firstChild.getAttribute("popupid"),
-       "webRTC-shareDevices", "panel using devices icon");
+    let iconclass =
+      PopupNotifications.panel.firstChild.getAttribute("iconclass");
+    ok(iconclass.includes("camera-icon"), "panel using devices icon");
 
     let indicator = promiseIndicatorWindow();
     yield promiseMessage("ok", () => {
       PopupNotifications.panel.firstChild.button.click();
     });
     yield expectObserverCalled("getUserMedia:response:allow");
     yield expectObserverCalled("recording-device-events");
     is((yield getMediaCaptureState()), "Camera", "expected camera to be shared");
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -51,16 +51,21 @@ file, You can obtain one at http://mozil
                     class="autocomplete-result-popupset"/>
       <children includes="toolbarbutton"/>
     </content>
 
     <implementation implements="nsIObserver, nsIDOMEventListener">
       <field name="AppConstants" readonly="true">
         (Components.utils.import("resource://gre/modules/AppConstants.jsm", {})).AppConstants;
       </field>
+
+      <field name="ExtensionSearchHandler" readonly="true">
+        (Components.utils.import("resource://gre/modules/ExtensionSearchHandler.jsm", {})).ExtensionSearchHandler;
+      </field>
+
       <constructor><![CDATA[
         this._prefs = Components.classes["@mozilla.org/preferences-service;1"]
                                 .getService(Components.interfaces.nsIPrefService)
                                 .getBranch("browser.urlbar.");
 
         this._prefs.addObserver("", this, false);
         this.clickSelectsAll = this._prefs.getBoolPref("clickSelectsAll");
         this.doubleClickSelectsAll = this._prefs.getBoolPref("doubleClickSelectsAll");
@@ -169,16 +174,20 @@ file, You can obtain one at http://mozil
                 returnValue = action.params.displayUrl;
                 break;
               }
               case "keyword": // Fall through.
               case "searchengine": {
                 returnValue = action.params.input;
                 break;
               }
+              case "extension": {
+                returnValue = action.params.content;
+                break;
+              }
             }
           } else {
             let originalUrl = ReaderMode.getOriginalUrl(aValue);
             if (originalUrl) {
               returnValue = originalUrl;
             }
           }
 
@@ -473,16 +482,23 @@ file, You can obtain one at http://mozil
                   action.params.engineName,
                   action.params.searchSuggestion || action.params.searchQuery,
                   event,
                   where,
                   openUILinkParams,
                   actionDetails
                 );
                 break;
+              case "extension":
+                this.handleRevert();
+                // Give the extension control of handling the command.
+                let searchString = action.params.content;
+                let keyword = action.params.keyword;
+                this.ExtensionSearchHandler.handleInputEntered(keyword, searchString, where);
+                return;
             }
           } else {
             // This is a fallback for add-ons and old testing code that directly
             // set value and try to confirm it. UnifiedComplete should always
             // resolve to a valid url.
             try {
               new URL(url);
             } catch (ex) {
@@ -590,17 +606,17 @@ file, You can obtain one at http://mozil
         <parameter name="searchActionDetails"/>
         <body><![CDATA[
           let engine =
             typeof(engineOrEngineName) == "string" ?
               Services.search.getEngineByName(engineOrEngineName) :
               engineOrEngineName;
           let isOneOff = this.popup.oneOffSearchButtons
               .maybeRecordTelemetry(event, openUILinkWhere, openUILinkParams);
-          // Infer the type of the even which triggered the search.
+          // Infer the type of the event which triggered the search.
           let eventType = "unknown";
           if (event instanceof KeyboardEvent) {
             eventType = "key";
           } else if (event instanceof MouseEvent) {
             eventType = "mouse";
           }
           // Augment the search action details object.
           let details = searchActionDetails || {};
@@ -1168,16 +1184,19 @@ file, You can obtain one at http://mozil
         }
       ]]></handler>
 
       <handler event="blur"><![CDATA[
         if (event.originalTarget == this.inputField) {
           this._clearNoActions();
           this.formatValue();
         }
+        if (ExtensionSearchHandler.hasActiveInputSession()) {
+          ExtensionSearchHandler.handleInputCancelled();
+        }
       ]]></handler>
 
       <handler event="dragstart" phase="capturing"><![CDATA[
         // Drag only if the gesture starts from the input field.
         if (this.inputField != event.originalTarget &&
             !(this.inputField.compareDocumentPosition(event.originalTarget) &
               Node.DOCUMENT_POSITION_CONTAINED_BY))
           return;
--- a/browser/base/moz.build
+++ b/browser/base/moz.build
@@ -17,16 +17,17 @@ MOCHITEST_CHROME_MANIFESTS += [
 BROWSER_CHROME_MANIFESTS += [
     'content/test/alerts/browser.ini',
     'content/test/general/browser.ini',
     'content/test/newtab/browser.ini',
     'content/test/plugins/browser.ini',
     'content/test/popupNotifications/browser.ini',
     'content/test/referrer/browser.ini',
     'content/test/social/browser.ini',
+    'content/test/tabcrashed/browser.ini',
     'content/test/tabPrompts/browser.ini',
     'content/test/tabs/browser.ini',
     'content/test/urlbar/browser.ini',
     'content/test/webrtc/browser.ini',
 ]
 
 DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION']
 DEFINES['MOZ_APP_VERSION_DISPLAY'] = CONFIG['MOZ_APP_VERSION_DISPLAY']
--- a/browser/components/contextualidentity/test/browser/.eslintrc.js
+++ b/browser/components/contextualidentity/test/browser/.eslintrc.js
@@ -1,11 +1,11 @@
 "use strict";
 
 module.exports = {
   "extends": [
     "../../../../../testing/mochitest/browser.eslintrc.js"
   ],
 
   "rules": {
-    "no-undef": 2
+    "no-undef": "error"
   }
 };
--- a/browser/components/contextualidentity/test/browser/browser.ini
+++ b/browser/components/contextualidentity/test/browser/browser.ini
@@ -9,16 +9,17 @@ support-files =
 
 [browser_aboutURLs.js]
 [browser_eme.js]
 [browser_favicon.js]
 [browser_forgetaboutsite.js]
 [browser_forgetAPI_cookie_getCookiesWithOriginAttributes.js]
 [browser_forgetAPI_EME_forgetThisSite.js]
 [browser_forgetAPI_quota_clearStoragesForPrincipal.js]
+[browser_newtabButton.js]
 [browser_usercontext.js]
 [browser_usercontextid_tabdrop.js]
 skip-if = os == "mac" || os == "win" # Intermittent failure - bug 1268276
 [browser_windowName.js]
 tags = openwindow
 [browser_windowOpen.js]
 tags = openwindow
 [browser_serviceworkers.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/contextualidentity/test/browser/browser_newtabButton.js
@@ -0,0 +1,34 @@
+"use strict";
+
+// Testing that when the user opens the add tab menu and clicks menu items
+// the correct context id is opened
+
+add_task(function* test() {
+  yield SpecialPowers.pushPrefEnv({"set": [
+      ["privacy.userContext.enabled", true]
+  ]});
+
+  let newTab = document.getElementById('tabbrowser-tabs');
+  let newTabButton = document.getAnonymousElementByAttribute(newTab, "anonid", "tabs-newtab-button");
+  ok(newTabButton, "New tab button exists");
+  ok(!newTabButton.hidden, "New tab button is visible");
+  let popup = document.getAnonymousElementByAttribute(newTab, "anonid", "newtab-popup");
+
+  for (let i = 1; i <= 4; i++) {
+    let popupShownPromise = BrowserTestUtils.waitForEvent(popup, "popupshown");
+    EventUtils.synthesizeMouseAtCenter(newTabButton, {type: "mousedown"});
+
+    yield popupShownPromise;
+    let contextIdItem = popup.querySelector(`menuitem[data-usercontextid="${i}"]`);
+
+    ok(contextIdItem, `User context id ${i} exists`);
+
+    let waitForTabPromise = BrowserTestUtils.waitForNewTab(gBrowser);
+    EventUtils.synthesizeMouseAtCenter(contextIdItem, {});
+
+    let tab = yield waitForTabPromise;
+
+    is(tab.getAttribute('usercontextid'), i, `New tab has UCI equal ${i}`);
+    yield BrowserTestUtils.removeTab(tab);
+  }
+});
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/ext-c-omnibox.js
@@ -0,0 +1,32 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+Cu.import("resource://gre/modules/ExtensionUtils.jsm");
+
+var {
+  runSafeSyncWithoutClone,
+  SingletonEventManager,
+} = ExtensionUtils;
+
+extensions.registerSchemaAPI("omnibox", "addon_child", context => {
+  return {
+    omnibox: {
+      onInputChanged: new SingletonEventManager(context, "omnibox.onInputChanged", fire => {
+        let listener = (text, id) => {
+          runSafeSyncWithoutClone(fire, text, suggestions => {
+            // TODO: Switch to using callParentFunctionNoReturn once bug 1314903 is fixed.
+            context.childManager.callParentAsyncFunction("omnibox_internal.addSuggestions", [
+              id,
+              suggestions,
+            ]);
+          });
+        };
+        context.childManager.getParentEvent("omnibox_internal.onInputChanged").addListener(listener);
+        return () => {
+          context.childManager.getParentEvent("omnibox_internal.onInputChanged").removeListener(listener);
+        };
+      }).api(),
+    },
+  };
+});
--- a/browser/components/extensions/ext-contextMenus.js
+++ b/browser/components/extensions/ext-contextMenus.js
@@ -218,18 +218,16 @@ var gMenuBuilder = {
 function contextMenuObserver(subject, topic, data) {
   subject = subject.wrappedJSObject;
   gMenuBuilder.build(subject);
 }
 
 function getContexts(contextData) {
   let contexts = new Set(["all"]);
 
-  contexts.add("page");
-
   if (contextData.inFrame) {
     contexts.add("frame");
   }
 
   if (contextData.isTextSelected) {
     contexts.add("selection");
   }
 
@@ -248,16 +246,20 @@ function getContexts(contextData) {
   if (contextData.onVideo) {
     contexts.add("video");
   }
 
   if (contextData.onAudio) {
     contexts.add("audio");
   }
 
+  if (contexts.size == 1) {
+    contexts.add("page");
+  }
+
   return contexts;
 }
 
 function MenuItem(extension, createProperties, isRoot = false) {
   this.extension = extension;
   this.children = [];
   this.parent = null;
   this.tabManager = TabManager.for(extension);
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/ext-omnibox.js
@@ -0,0 +1,104 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+Cu.import("resource://gre/modules/ExtensionUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "ExtensionSearchHandler",
+                                  "resource://gre/modules/ExtensionSearchHandler.jsm");
+var {
+  SingletonEventManager,
+} = ExtensionUtils;
+
+// WeakMap[extension -> keyword]
+let gKeywordMap = new WeakMap();
+
+/* eslint-disable mozilla/balanced-listeners */
+extensions.on("manifest_omnibox", (type, directive, extension, manifest) => {
+  let keyword = manifest.omnibox.keyword;
+  try {
+    // This will throw if the keyword is already registered.
+    ExtensionSearchHandler.registerKeyword(keyword, extension);
+    gKeywordMap.set(extension, keyword);
+  } catch (e) {
+    extension.manifestError(e.message);
+  }
+});
+
+extensions.on("shutdown", (type, extension) => {
+  let keyword = gKeywordMap.get(extension);
+  if (keyword) {
+    ExtensionSearchHandler.unregisterKeyword(keyword);
+    gKeywordMap.delete(extension);
+  }
+});
+/* eslint-enable mozilla/balanced-listeners */
+
+extensions.registerSchemaAPI("omnibox", "addon_parent", context => {
+  let {extension} = context;
+  return {
+    omnibox: {
+      setDefaultSuggestion(suggestion) {
+        let keyword = gKeywordMap.get(extension);
+        try {
+          // This will throw if the keyword failed to register.
+          ExtensionSearchHandler.setDefaultSuggestion(keyword, suggestion);
+        } catch (e) {
+          return Promise.reject(e.message);
+        }
+      },
+
+      onInputStarted: new SingletonEventManager(context, "omnibox.onInputStarted", fire => {
+        let listener = (eventName) => {
+          fire();
+        };
+        extension.on(ExtensionSearchHandler.MSG_INPUT_STARTED, listener);
+        return () => {
+          extension.off(ExtensionSearchHandler.MSG_INPUT_STARTED, listener);
+        };
+      }).api(),
+
+      onInputCancelled: new SingletonEventManager(context, "omnibox.onInputCancelled", fire => {
+        let listener = (eventName) => {
+          fire();
+        };
+        extension.on(ExtensionSearchHandler.MSG_INPUT_CANCELLED, listener);
+        return () => {
+          extension.off(ExtensionSearchHandler.MSG_INPUT_CANCELLED, listener);
+        };
+      }).api(),
+
+      onInputEntered: new SingletonEventManager(context, "omnibox.onInputEntered", fire => {
+        let listener = (eventName, text, disposition) => {
+          fire(text, disposition);
+        };
+        extension.on(ExtensionSearchHandler.MSG_INPUT_ENTERED, listener);
+        return () => {
+          extension.off(ExtensionSearchHandler.MSG_INPUT_ENTERED, listener);
+        };
+      }).api(),
+    },
+
+    omnibox_internal: {
+      addSuggestions(id, suggestions) {
+        let keyword = gKeywordMap.get(extension);
+        try {
+          ExtensionSearchHandler.addSuggestions(keyword, id, suggestions);
+        } catch (e) {
+          // Silently fail because the extension developer can not know for sure if the user
+          // has already invalidated the callback when asynchronously providing suggestions.
+        }
+      },
+
+      onInputChanged: new SingletonEventManager(context, "omnibox_internal.onInputChanged", fire => {
+        let listener = (eventName, text, id) => {
+          fire(text, id);
+        };
+        extension.on(ExtensionSearchHandler.MSG_INPUT_CHANGED, listener);
+        return () => {
+          extension.off(ExtensionSearchHandler.MSG_INPUT_CHANGED, listener);
+        };
+      }).api(),
+    },
+  };
+});
--- a/browser/components/extensions/extensions-browser.manifest
+++ b/browser/components/extensions/extensions-browser.manifest
@@ -1,28 +1,31 @@
 # scripts
 category webextension-scripts bookmarks chrome://browser/content/ext-bookmarks.js
 category webextension-scripts browserAction chrome://browser/content/ext-browserAction.js
 category webextension-scripts commands chrome://browser/content/ext-commands.js
 category webextension-scripts contextMenus chrome://browser/content/ext-contextMenus.js
 category webextension-scripts desktop-runtime chrome://browser/content/ext-desktop-runtime.js
 category webextension-scripts history chrome://browser/content/ext-history.js
+category webextension-scripts omnibox chrome://browser/content/ext-omnibox.js
 category webextension-scripts pageAction chrome://browser/content/ext-pageAction.js
 category webextension-scripts sessions chrome://browser/content/ext-sessions.js
 category webextension-scripts tabs chrome://browser/content/ext-tabs.js
 category webextension-scripts utils chrome://browser/content/ext-utils.js
 category webextension-scripts windows chrome://browser/content/ext-windows.js
 
 # scripts that must run in the same process as addon code.
 category webextension-scripts-addon contextMenus chrome://browser/content/ext-c-contextMenus.js
+category webextension-scripts-addon omnibox chrome://browser/content/ext-c-omnibox.js
 category webextension-scripts-addon tabs chrome://browser/content/ext-c-tabs.js
 
 # schemas
 category webextension-schemas bookmarks chrome://browser/content/schemas/bookmarks.json
 category webextension-schemas browser_action chrome://browser/content/schemas/browser_action.json
 category webextension-schemas commands chrome://browser/content/schemas/commands.json
 category webextension-schemas context_menus chrome://browser/content/schemas/context_menus.json
 category webextension-schemas context_menus_internal chrome://browser/content/schemas/context_menus_internal.json
 category webextension-schemas history chrome://browser/content/schemas/history.json
+category webextension-schemas omnibox chrome://browser/content/schemas/omnibox.json
 category webextension-schemas page_action chrome://browser/content/schemas/page_action.json
 category webextension-schemas sessions chrome://browser/content/schemas/sessions.json
 category webextension-schemas tabs chrome://browser/content/schemas/tabs.json
 category webextension-schemas windows chrome://browser/content/schemas/windows.json
--- a/browser/components/extensions/jar.mn
+++ b/browser/components/extensions/jar.mn
@@ -13,15 +13,17 @@ browser.jar:
 #endif
     content/browser/extension.svg
     content/browser/ext-bookmarks.js
     content/browser/ext-browserAction.js
     content/browser/ext-commands.js
     content/browser/ext-contextMenus.js
     content/browser/ext-desktop-runtime.js
     content/browser/ext-history.js
+    content/browser/ext-omnibox.js
     content/browser/ext-pageAction.js
     content/browser/ext-sessions.js
     content/browser/ext-tabs.js
     content/browser/ext-utils.js
     content/browser/ext-windows.js
     content/browser/ext-c-contextMenus.js
+    content/browser/ext-c-omnibox.js
     content/browser/ext-c-tabs.js
--- a/browser/components/extensions/schemas/jar.mn
+++ b/browser/components/extensions/schemas/jar.mn
@@ -4,12 +4,13 @@
 
 browser.jar:
     content/browser/schemas/bookmarks.json
     content/browser/schemas/browser_action.json
     content/browser/schemas/commands.json
     content/browser/schemas/context_menus.json
     content/browser/schemas/context_menus_internal.json
     content/browser/schemas/history.json
+    content/browser/schemas/omnibox.json
     content/browser/schemas/page_action.json
     content/browser/schemas/sessions.json
     content/browser/schemas/tabs.json
     content/browser/schemas/windows.json
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/schemas/omnibox.json
@@ -0,0 +1,248 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+[
+  {
+    "namespace": "manifest",
+    "types": [
+      {
+        "$extend": "WebExtensionManifest",
+        "properties": {
+          "omnibox": {
+            "type": "object",
+            "additionalProperties": { "$ref": "UnrecognizedProperty" },
+            "properties": {
+              "keyword": {
+                "type": "string",
+                "pattern": "^[^?\\s:]([^\\s:]*[^/\\s:])?$"
+              }
+            },
+            "optional": true
+          }
+        }
+      }
+    ]
+  },
+  {
+    "namespace": "omnibox",
+    "description": "The omnibox API allows you to register a keyword with Firefox's address bar.",
+    "permissions": ["manifest:omnibox"],
+    "types": [
+      {
+        "id": "DescriptionStyleType",
+        "type": "string",
+        "description": "The style type.",
+        "enum": ["url", "match", "dim"]
+      },
+      {
+        "id": "OnInputEnteredDisposition",
+        "type": "string",
+        "enum": ["currentTab", "newForegroundTab", "newBackgroundTab"],
+        "description": "The window disposition for the omnibox query. This is the recommended context to display results. For example, if the omnibox command is to navigate to a certain URL, a disposition of 'newForegroundTab' means the navigation should take place in a new selected tab."
+      },
+      {
+        "id": "SuggestResult",
+        "type": "object",
+        "description": "A suggest result.",
+        "properties": {
+          "content": {
+            "type": "string",
+            "minLength": 1,
+            "description": "The text that is put into the URL bar, and that is sent to the extension when the user chooses this entry."
+          },
+          "description": {
+            "type": "string",
+            "minLength": 1,
+            "description": "The text that is displayed in the URL dropdown. Can contain XML-style markup for styling. The supported tags are 'url' (for a literal URL), 'match' (for highlighting text that matched what the user's query), and 'dim' (for dim helper text). The styles can be nested, eg. <dim><match>dimmed match</match></dim>. You must escape the five predefined entities to display them as text: stackoverflow.com/a/1091953/89484 "
+          },
+          "descriptionStyles": {
+            "optional": true,
+            "unsupported": true,
+            "type": "array",
+            "description": "An array of style ranges for the description, as provided by the extension.",
+            "items": {
+              "type": "object",
+              "description": "The style ranges for the description, as provided by the extension.",
+              "properties": {
+                "offset": { "type": "integer" },
+                "type": { "description": "The style type", "$ref": "DescriptionStyleType"},
+                "length": { "type": "integer", "optional": true }
+              }
+            }
+          },
+          "descriptionStylesRaw": {
+            "optional": true,
+            "unsupported": true,
+            "type": "array",
+            "description": "An array of style ranges for the description, as provided by ToValue().",
+            "items": {
+              "type": "object",
+              "description": "The style ranges for the description, as provided by ToValue().",
+              "properties": {
+                "offset": { "type": "integer" },
+                "type": { "type": "integer" }
+              }
+            }
+          }
+        }
+      },
+      {
+        "id": "DefaultSuggestResult",
+        "type": "object",
+        "description": "A suggest result.",
+        "properties": {
+          "description": {
+            "type": "string",
+            "minLength": 1,
+            "description": "The text that is displayed in the URL dropdown."
+          },
+          "descriptionStyles": {
+            "optional": true,
+            "unsupported": true,
+            "type": "array",
+            "description": "An array of style ranges for the description, as provided by the extension.",
+            "items": {
+              "type": "object",
+              "description": "The style ranges for the description, as provided by the extension.",
+              "properties": {
+                "offset": { "type": "integer" },
+                "type": { "description": "The style type", "$ref": "DescriptionStyleType"},
+                "length": { "type": "integer", "optional": true }
+              }
+            }
+          },
+          "descriptionStylesRaw": {
+            "optional": true,
+            "unsupported": true,
+            "type": "array",
+            "description": "An array of style ranges for the description, as provided by ToValue().",
+            "items": {
+              "type": "object",
+              "description": "The style ranges for the description, as provided by ToValue().",
+              "properties": {
+                "offset": { "type": "integer" },
+                "type": { "type": "integer" }
+              }
+            }
+          }
+        }
+      }
+    ],
+    "functions": [
+      {
+        "name": "setDefaultSuggestion",
+        "type": "function",
+        "description": "Sets the description and styling for the default suggestion. The default suggestion is the text that is displayed in the first suggestion row underneath the URL bar.",
+        "parameters": [
+          {
+            "name": "suggestion",
+            "$ref": "DefaultSuggestResult",
+            "description": "A partial SuggestResult object, without the 'content' parameter."
+          }
+        ]
+      }
+    ],
+    "events": [
+      {
+        "name": "onInputStarted",
+        "type": "function",
+        "description": "User has started a keyword input session by typing the extension's keyword. This is guaranteed to be sent exactly once per input session, and before any onInputChanged events.",
+        "parameters": []
+      },
+      {
+        "name": "onInputChanged",
+        "type": "function",
+        "description": "User has changed what is typed into the omnibox.",
+        "parameters": [
+          {
+            "type": "string",
+            "name": "text"
+          },
+          {
+            "name": "suggest",
+            "type": "function",
+            "description": "A callback passed to the onInputChanged event used for sending suggestions back to the browser.",
+            "parameters": [
+              {
+                "name": "suggestResults",
+                "type": "array",
+                "description": "Array of suggest results",
+                "items": {
+                  "$ref": "SuggestResult"
+                }
+              }
+            ]
+          }
+        ]
+      },
+      {
+        "name": "onInputEntered",
+        "type": "function",
+        "description": "User has accepted what is typed into the omnibox.",
+        "parameters": [
+          {
+            "type": "string",
+            "name": "text"
+          },
+          {
+            "name": "disposition",
+            "$ref": "OnInputEnteredDisposition"
+          }
+        ]
+      },
+      {
+        "name": "onInputCancelled",
+        "type": "function",
+        "description": "User has ended the keyword input session without accepting the input.",
+        "parameters": []
+      }
+    ]
+  },
+  {
+    "namespace": "omnibox_internal",
+    "description": "The internal namespace used by the omnibox API.",
+    "defaultContexts": ["addon_parent_only"],
+    "functions": [
+      {
+        "name": "addSuggestions",
+        "type": "function",
+        "async": "callback",
+        "description": "Internal function used by omnibox.onInputChanged for adding search suggestions",
+        "parameters": [
+          {
+            "name": "id",
+            "type": "integer",
+            "description": "The ID of the callback received by onInputChangedInternal"
+          },
+          {
+            "name": "suggestResults",
+            "type": "array",
+            "description": "Array of suggest results",
+            "items": {
+              "$ref": "omnibox.SuggestResult"
+            }
+          },
+          {
+            "type": "function",
+            "name": "callback",
+            "optional": true,
+            "parameters": []
+          }
+        ]
+      }
+    ],
+    "events": [
+      {
+        "name": "onInputChanged",
+        "type": "function",
+        "description": "Identical to omnibox.onInputChanged except no 'suggest' callback is provided.",
+        "parameters": [
+          {
+            "type": "string",
+            "name": "text"
+          }
+        ]
+      }
+    ]
+  }
+]
\ No newline at end of file
--- a/browser/components/extensions/test/browser/browser.ini
+++ b/browser/components/extensions/test/browser/browser.ini
@@ -40,16 +40,17 @@ tags = webextensions
 [browser_ext_contextMenus_radioGroups.js]
 [browser_ext_contextMenus_uninstall.js]
 [browser_ext_contextMenus_urlPatterns.js]
 [browser_ext_currentWindow.js]
 [browser_ext_getViews.js]
 [browser_ext_incognito_popup.js]
 [browser_ext_lastError.js]
 [browser_ext_legacy_extension_context_contentscript.js]
+[browser_ext_omnibox.js]
 [browser_ext_optionsPage_privileges.js]
 [browser_ext_pageAction_context.js]
 [browser_ext_pageAction_popup.js]
 [browser_ext_pageAction_popup_resize.js]
 [browser_ext_pageAction_simple.js]
 [browser_ext_pageAction_title.js]
 [browser_ext_popup_api_injection.js]
 [browser_ext_popup_background.js]
--- a/browser/components/extensions/test/browser/browser_ext_browserAction_disabled.js
+++ b/browser/components/extensions/test/browser/browser_ext_browserAction_disabled.js
@@ -36,30 +36,33 @@ add_task(function* testDisabled() {
       browser.test.sendMessage("ready");
     },
   });
 
   yield extension.startup();
   yield extension.awaitMessage("ready");
 
   yield clickBrowserAction(extension);
+  yield new Promise(resolve => setTimeout(resolve, 0));
 
   extension.sendMessage("check-clicked", true);
   yield extension.awaitMessage("next-test");
 
   extension.sendMessage("disable");
   yield extension.awaitMessage("next-test");
 
   yield clickBrowserAction(extension);
+  yield new Promise(resolve => setTimeout(resolve, 0));
 
   extension.sendMessage("check-clicked", false);
   yield extension.awaitMessage("next-test");
 
   extension.sendMessage("enable");
   yield extension.awaitMessage("next-test");
 
   yield clickBrowserAction(extension);
+  yield new Promise(resolve => setTimeout(resolve, 0));
 
   extension.sendMessage("check-clicked", true);
   yield extension.awaitMessage("next-test");
 
   yield extension.unload();
 });
--- a/browser/components/extensions/test/browser/browser_ext_contextMenus.js
+++ b/browser/components/extensions/test/browser/browser_ext_contextMenus.js
@@ -11,35 +11,40 @@ add_task(function* () {
 
   let extension = ExtensionTestUtils.loadExtension({
     manifest: {
       "permissions": ["contextMenus"],
     },
 
     background: function() {
       browser.contextMenus.create({
-        id: "clickme",
+        id: "clickme-image",
         title: "Click me!",
         contexts: ["image"],
       });
+      browser.contextMenus.create({
+        id: "clickme-page",
+        title: "Click me!",
+        contexts: ["page"],
+      });
       browser.test.notifyPass();
     },
   });
 
   yield extension.startup();
   yield extension.awaitFinish();
 
   let contentAreaContextMenu = yield openContextMenu("#img1");
   let item = contentAreaContextMenu.getElementsByAttribute("label", "Click me!");
   is(item.length, 1, "contextMenu item for image was found");
   yield closeContextMenu();
 
   contentAreaContextMenu = yield openContextMenu("body");
   item = contentAreaContextMenu.getElementsByAttribute("label", "Click me!");
-  is(item.length, 0, "no contextMenu item for image was found");
+  is(item.length, 1, "contextMenu item for page was found");
   yield closeContextMenu();
 
   yield extension.unload();
 
   yield BrowserTestUtils.removeTab(tab1);
 });
 
 add_task(function* () {
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_omnibox.js
@@ -0,0 +1,286 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+function* setup() {
+  const SUGGEST_URLBAR_PREF = "browser.urlbar.suggest.searches";
+  Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, false);
+
+  registerCleanupFunction(() => {
+    Services.prefs.clearUserPref(SUGGEST_URLBAR_PREF);
+  });
+}
+
+add_task(function* () {
+  let keyword = "test";
+
+  let extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      "omnibox": {
+        "keyword": keyword,
+      },
+    },
+
+    background: function() {
+      browser.omnibox.onInputStarted.addListener(() => {
+        browser.test.sendMessage("on-input-started-fired");
+      });
+
+      let synchronous = true;
+      let suggestions = null;
+      let suggestCallback = null;
+
+      browser.omnibox.onInputChanged.addListener((text, suggest) => {
+        if (synchronous && suggestions) {
+          suggest(suggestions);
+        } else {
+          suggestCallback = suggest;
+        }
+        browser.test.sendMessage("on-input-changed-fired", {text});
+      });
+
+      browser.omnibox.onInputCancelled.addListener(() => {
+        browser.test.sendMessage("on-input-cancelled-fired");
+      });
+
+      browser.omnibox.onInputEntered.addListener((text, disposition) => {
+        browser.test.sendMessage("on-input-entered-fired", {text, disposition});
+      });
+
+      browser.test.onMessage.addListener((msg, data) => {
+        switch (msg) {
+          case "set-suggestions":
+            suggestions = data.suggestions;
+            browser.test.sendMessage("suggestions-set");
+            break;
+          case "set-default-suggestion":
+            browser.omnibox.setDefaultSuggestion(data.suggestion);
+            browser.test.sendMessage("default-suggestion-set");
+            break;
+          case "set-synchronous":
+            synchronous = data.synchronous;
+            break;
+          case "test-multiple-suggest-calls":
+            suggestions.forEach(suggestion => suggestCallback([suggestion]));
+            browser.test.sendMessage("test-ready");
+            break;
+          case "test-suggestions-after-delay":
+            Promise.resolve().then(() => {
+              suggestCallback(suggestions);
+              browser.test.sendMessage("test-ready");
+            });
+            break;
+        }
+      });
+    },
+  });
+
+  function* expectEvent(event, expected = {}) {
+    let actual = yield extension.awaitMessage(event);
+    if (expected.text) {
+      is(actual.text, expected.text,
+        `Expected "${event}" to have fired with text: "${expected.text}".`);
+    }
+    if (expected.disposition) {
+      is(actual.disposition, expected.disposition,
+        `Expected "${event}" to have fired with disposition: "${expected.disposition}".`);
+    }
+  }
+
+  function* startInputSession() {
+    gURLBar.focus();
+    gURLBar.value = keyword;
+    EventUtils.synthesizeKey(" ", {});
+    yield expectEvent("on-input-started-fired");
+    EventUtils.synthesizeKey("t", {});
+    yield expectEvent("on-input-changed-fired", {text: "t"});
+    return "t";
+  }
+
+  function* testInputEvents() {
+    gURLBar.focus();
+
+    // Start an input session by typing in <keyword><space>.
+    for (let letter of keyword) {
+      EventUtils.synthesizeKey(letter, {});
+    }
+    EventUtils.synthesizeKey(" ", {});
+    yield expectEvent("on-input-started-fired");
+
+    // We should expect input changed events now that the keyword is active.
+    EventUtils.synthesizeKey("b", {});
+    yield expectEvent("on-input-changed-fired", {text: "b"});
+
+    EventUtils.synthesizeKey("c", {});
+    yield expectEvent("on-input-changed-fired", {text: "bc"});
+
+    EventUtils.synthesizeKey("VK_BACK_SPACE", {});
+    yield expectEvent("on-input-changed-fired", {text: "b"});
+
+    // Even though the input is <keyword><space> We should not expect an
+    // input started event to fire since the keyword is active.
+    EventUtils.synthesizeKey("VK_BACK_SPACE", {});
+    yield expectEvent("on-input-changed-fired", {text: ""});
+
+    // Make the keyword inactive by hitting backspace.
+    EventUtils.synthesizeKey("VK_BACK_SPACE", {});
+    yield expectEvent("on-input-cancelled-fired");
+
+    // Activate the keyword by typing a space.
+    // Expect onInputStarted to fire.
+    EventUtils.synthesizeKey(" ", {});
+    yield expectEvent("on-input-started-fired");
+
+    // onInputChanged should fire even if a space is entered.
+    EventUtils.synthesizeKey(" ", {});
+    yield expectEvent("on-input-changed-fired", {text: " "});
+
+    // The active session should cancel if the input blurs.
+    gURLBar.blur();
+    yield expectEvent("on-input-cancelled-fired");
+  }
+
+  function* testHeuristicResult(expectedText, setDefaultSuggestion) {
+    if (setDefaultSuggestion) {
+      extension.sendMessage("set-default-suggestion", {
+        suggestion: {
+          description: expectedText,
+        },
+      });
+      yield extension.awaitMessage("default-suggestion-set");
+    }
+
+    let text = yield startInputSession();
+
+    let item = gURLBar.popup.richlistbox.children[0];
+
+    is(item.getAttribute("title"), expectedText,
+      `Expected heuristic result to have title: "${expectedText}".`);
+
+    is(item.getAttribute("displayurl"), `${keyword} ${text}`,
+      `Expected heuristic result to have displayurl: "${keyword} ${text}".`);
+
+    EventUtils.synthesizeMouseAtCenter(item, {});
+
+    yield expectEvent("on-input-entered-fired", {
+      text,
+      disposition: "currentTab",
+    });
+  }
+
+  function* testDisposition(suggestionIndex, expectedDisposition, expectedText) {
+    yield startInputSession();
+
+    // Select the suggestion.
+    for (let i = 0; i < suggestionIndex; i++) {
+      EventUtils.synthesizeKey("VK_DOWN", {});
+    }
+
+    let item = gURLBar.popup.richlistbox.children[suggestionIndex];
+    if (expectedDisposition == "currentTab") {
+      EventUtils.synthesizeMouseAtCenter(item, {});
+    } else if (expectedDisposition == "newForegroundTab") {
+      EventUtils.synthesizeMouseAtCenter(item, {accelKey: true});
+    } else if (expectedDisposition == "newBackgroundTab") {
+      EventUtils.synthesizeMouseAtCenter(item, {shiftKey: true, accelKey: true});
+    }
+
+    yield expectEvent("on-input-entered-fired", {
+      text: expectedText,
+      disposition: expectedDisposition,
+    });
+  }
+
+  function* testSuggestions(info) {
+    extension.sendMessage("set-synchronous", {synchronous: false});
+
+    function expectSuggestion({content, description}, index) {
+      let item = gURLBar.popup.richlistbox.children[index + 1]; // Skip the heuristic result.
+
+      ok(!!item, "Expected item to exist");
+      is(item.getAttribute("title"), description,
+        `Expected suggestion to have title: "${description}".`);
+
+      is(item.getAttribute("displayurl"), `${keyword} ${content}`,
+        `Expected suggestion to have displayurl: "${keyword} ${content}".`);
+    }
+
+    let text = yield startInputSession();
+
+    extension.sendMessage(info.test);
+    yield extension.awaitMessage("test-ready");
+
+    info.suggestions.forEach(expectSuggestion);
+
+    EventUtils.synthesizeMouseAtCenter(gURLBar.popup.richlistbox.children[0], {});
+    yield expectEvent("on-input-entered-fired", {
+      text,
+      disposition: "currentTab",
+    });
+  }
+
+  yield setup();
+  yield extension.startup();
+
+  yield testInputEvents();
+
+  // Test the heuristic result with default suggestions.
+  yield testHeuristicResult("Generated extension", false /* setDefaultSuggestion */);
+  yield testHeuristicResult("hello world", true /* setDefaultSuggestion */);
+  yield testHeuristicResult("foo bar", true /* setDefaultSuggestion */);
+
+  let suggestions = [
+    {content: "a", description: "select a"},
+    {content: "b", description: "select b"},
+    {content: "c", description: "select c"},
+  ];
+
+  extension.sendMessage("set-suggestions", {suggestions});
+  yield extension.awaitMessage("suggestions-set");
+
+  // Test each suggestion and search disposition.
+  yield testDisposition(1, "currentTab", suggestions[0].content);
+  yield testDisposition(2, "newForegroundTab", suggestions[1].content);
+  yield testDisposition(3, "newBackgroundTab", suggestions[2].content);
+
+  extension.sendMessage("set-suggestions", {suggestions});
+  yield extension.awaitMessage("suggestions-set");
+
+  // Test adding suggestions asynchronously.
+  yield testSuggestions({
+    test: "test-multiple-suggest-calls",
+    skipHeuristic: true,
+    suggestions,
+  });
+  yield testSuggestions({
+    test: "test-suggestions-after-delay",
+    skipHeuristic: true,
+    suggestions,
+  });
+
+  // Start monitoring the console.
+  SimpleTest.waitForExplicitFinish();
+  let waitForConsole = new Promise(resolve => {
+    SimpleTest.monitorConsole(resolve, [{
+      message: new RegExp(`The keyword provided is already registered: "${keyword}"`),
+    }]);
+  });
+
+  // Try registering another extension with the same keyword
+  let extension2 = ExtensionTestUtils.loadExtension({
+    manifest: {
+      "omnibox": {
+        "keyword": keyword,
+      },
+    },
+  });
+
+  yield extension2.startup();
+
+  // Stop monitoring the console and confirm the correct errors are logged.
+  SimpleTest.endMonitorConsole();
+  yield waitForConsole;
+
+  yield extension2.unload();
+  yield extension.unload();
+});
--- a/browser/components/extensions/test/browser/browser_ext_webNavigation_urlbar_transitions.js
+++ b/browser/components/extensions/test/browser/browser_ext_webNavigation_urlbar_transitions.js
@@ -5,16 +5,27 @@
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
                                   "resource://gre/modules/PlacesUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesTestUtils",
                                   "resource://testing-common/PlacesTestUtils.jsm");
 
 const SUGGEST_URLBAR_PREF = "browser.urlbar.suggest.searches";
 const TEST_ENGINE_BASENAME = "searchSuggestionEngine.xml";
 
+function* promiseAutocompleteResultPopup(inputText) {
+  gURLBar.focus();
+  gURLBar.value = inputText;
+  gURLBar.controller.startSearch(inputText);
+  yield promisePopupShown(gURLBar.popup);
+  yield BrowserTestUtils.waitForCondition(() => {
+    return gURLBar.controller.searchStatus >=
+      Ci.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH;
+  });
+}
+
 function* addBookmark(bookmark) {
   if (bookmark.keyword) {
     yield PlacesUtils.keywords.insert({
       keyword: bookmark.keyword,
       url: bookmark.url,
     });
   }
 
@@ -137,27 +148,19 @@ add_task(function* test_webnavigation_ur
     title: "Bookmark To Click",
     url: "http://example.com/?q=bookmark",
   });
 
   yield extension.startup();
 
   yield extension.awaitMessage("ready");
 
-  gURLBar.focus();
-  gURLBar.value = "Bookmark To Click";
-  gURLBar.controller.startSearch("Bookmark To Click");
-
-  let item;
+  yield promiseAutocompleteResultPopup("Bookmark To Click");
 
-  yield BrowserTestUtils.waitForCondition(() => {
-    item = gURLBar.popup.richlistbox.getItemAtIndex(1);
-    return item;
-  });
-
+  let item = gURLBar.popup.richlistbox.getItemAtIndex(1);
   item.click();
   yield extension.awaitFinish("webNavigation.from_address_bar.auto_bookmark");
 
   yield extension.unload();
   info("extension unloaded");
 });
 
 add_task(function* test_webnavigation_urlbar_keyword_transition() {
@@ -190,23 +193,17 @@ add_task(function* test_webnavigation_ur
     url: "http://example.com/?q=%s",
     keyword: "testkw",
   });
 
   yield extension.startup();
 
   yield extension.awaitMessage("ready");
 
-  gURLBar.focus();
-  gURLBar.value = "testkw search";
-  gURLBar.controller.startSearch("testkw search");
-
-  yield BrowserTestUtils.waitForCondition(() => {
-    return gURLBar.popup.input.controller.matchCount;
-  });
+  yield promiseAutocompleteResultPopup("testkw search");
 
   let item = gURLBar.popup.richlistbox.getItemAtIndex(0);
   item.click();
 
   yield extension.awaitFinish("webNavigation.from_address_bar.keyword");
 
   yield extension.unload();
   info("extension unloaded");
@@ -237,24 +234,17 @@ add_task(function* test_webnavigation_ur
     },
   });
 
   yield extension.startup();
 
   yield extension.awaitMessage("ready");
 
   yield prepareSearchEngine();
-
-  gURLBar.focus();
-  gURLBar.value = "foo";
-  gURLBar.controller.startSearch("foo");
-
-  yield BrowserTestUtils.waitForCondition(() => {
-    return gURLBar.popup.input.controller.matchCount;
-  });
+  yield promiseAutocompleteResultPopup("foo");
 
   let item = gURLBar.popup.richlistbox.getItemAtIndex(0);
   item.click();
 
   yield extension.awaitFinish("webNavigation.from_address_bar.generated");
 
   yield extension.unload();
   info("extension unloaded");
--- a/browser/components/extensions/test/browser/browser_ext_windows_create_tabId.js
+++ b/browser/components/extensions/test/browser/browser_ext_windows_create_tabId.js
@@ -91,24 +91,29 @@ add_task(function* testWindowCreate() {
       browser.test.log("Try to create a window with an invalid tabId");
       await browser.test.assertRejects(
         browser.windows.create({tabId: 0}),
         /Invalid tab ID: 0/,
         "Create call failed as expected");
 
 
       browser.test.log("Try to create a window with two URLs");
-      [, , window] = await Promise.all([
+      let readyPromise = Promise.all([
         // tabs.onUpdated can be invoked between the call of windows.create and
         // the invocation of its callback/promise, so set up the listeners
         // before creating the window.
         promiseTabUpdated("http://example.com/"),
         promiseTabUpdated("http://example.org/"),
-        browser.windows.create({url: ["http://example.com/", "http://example.org/"]}),
       ]);
+
+      await new Promise(resolve => setTimeout(resolve, 0));
+
+      window = await browser.windows.create({url: ["http://example.com/", "http://example.org/"]});
+      await readyPromise;
+
       browser.test.assertEq(2, window.tabs.length, "2 tabs were opened in new window");
       browser.test.assertEq("about:blank", window.tabs[0].url, "about:blank, page not loaded yet");
       browser.test.assertEq("about:blank", window.tabs[1].url, "about:blank, page not loaded yet");
 
       window = await browser.windows.get(window.id, {populate: true});
 
       browser.test.assertEq(2, window.tabs.length, "2 tabs were opened in new window");
       browser.test.assertEq("http://example.com/", window.tabs[0].url, "Correct URL was loaded in tab 1");
--- a/browser/components/extensions/test/xpcshell/test_ext_bookmarks.js
+++ b/browser/components/extensions/test/xpcshell/test_ext_bookmarks.js
@@ -101,25 +101,25 @@ function backgroundScript() {
   browser.bookmarks.onMoved.addListener((id, info) => {
     collectedEvents.push({event: "onMoved", id, info});
   });
 
   browser.bookmarks.onRemoved.addListener((id, info) => {
     collectedEvents.push({event: "onRemoved", id, info});
   });
 
-  browser.bookmarks.get(["not-a-bookmark-guid"]).then(expectedError, error => {
+  browser.bookmarks.get(["not-a-bookmark-guid"]).then(expectedError, invalidGuidError => {
     browser.test.assertTrue(
-      error.message.includes("Invalid value for property 'guid': not-a-bookmark-guid"),
+      invalidGuidError.message.includes("Invalid value for property 'guid': not-a-bookmark-guid"),
       "Expected error thrown when trying to get a bookmark using an invalid guid"
     );
 
-    return browser.bookmarks.get([nonExistentId]).then(expectedError, error => {
+    return browser.bookmarks.get([nonExistentId]).then(expectedError, nonExistentIdError => {
       browser.test.assertTrue(
-        error.message.includes("Bookmark not found"),
+        nonExistentIdError.message.includes("Bookmark not found"),
         "Expected error thrown when trying to get a bookmark using a non-existent Id"
       );
     });
   }).then(() => {
     return browser.bookmarks.search({});
   }).then(results => {
     initialBookmarkCount = results.length;
     return browser.bookmarks.create({title: "test bookmark", url: "http://example.org"});
@@ -176,17 +176,17 @@ function backgroundScript() {
       browser.test.assertTrue(
         error.message.includes("Invalid bookmark:"),
         "Expected error thrown when trying update with an invalid url"
       );
       return browser.bookmarks.getTree();
     });
   }).then(results => {
     browser.test.assertEq(1, results.length, "getTree returns one result");
-    let bookmark = results[0].children.find(bookmark => bookmark.id == unsortedId);
+    let bookmark = results[0].children.find(bookmarkItem => bookmarkItem.id == unsortedId);
     browser.test.assertEq(
         "Other Bookmarks",
         bookmark.title,
         "Folder returned from getTree has the expected title"
     );
 
     return browser.bookmarks.create({parentId: "invalid"}).then(expectedError, error => {
       browser.test.assertTrue(
@@ -244,36 +244,36 @@ function backgroundScript() {
       }
     }
     let folderResult = results[2];
     createdFolderId = folderResult.id;
     return Promise.all([
       browser.bookmarks.create({title: "Mozilla", url: "http://allizom.org/", parentId: createdFolderId}),
       browser.bookmarks.create({title: "Mozilla Corporation", url: "http://allizom.com/", parentId: createdFolderId}),
       browser.bookmarks.create({title: "Firefox", url: "http://allizom.org/firefox/", parentId: createdFolderId}),
-    ]).then(results => {
+    ]).then(newBookmarks => {
       browser.test.assertEq(3, collectedEvents.length, "3 expected events received");
-      checkOnCreated(results[2].id, createdFolderId, 0, "Firefox", "http://allizom.org/firefox/", results[2].dateAdded);
-      checkOnCreated(results[1].id, createdFolderId, 0, "Mozilla Corporation", "http://allizom.com/", results[1].dateAdded);
-      checkOnCreated(results[0].id, createdFolderId, 0, "Mozilla", "http://allizom.org/", results[0].dateAdded);
+      checkOnCreated(newBookmarks[2].id, createdFolderId, 0, "Firefox", "http://allizom.org/firefox/", newBookmarks[2].dateAdded);
+      checkOnCreated(newBookmarks[1].id, createdFolderId, 0, "Mozilla Corporation", "http://allizom.com/", newBookmarks[1].dateAdded);
+      checkOnCreated(newBookmarks[0].id, createdFolderId, 0, "Mozilla", "http://allizom.org/", newBookmarks[0].dateAdded);
 
       return browser.bookmarks.create({
         title: "About Mozilla",
         url: "http://allizom.org/about/",
         parentId: createdFolderId,
         index: 1,
       });
     }).then(result => {
       browser.test.assertEq(1, collectedEvents.length, "1 expected events received");
       checkOnCreated(result.id, createdFolderId, 1, "About Mozilla", "http://allizom.org/about/", result.dateAdded);
 
       // returns all items on empty object
       return browser.bookmarks.search({});
-    }).then(results => {
-      browser.test.assertTrue(results.length >= 9, "At least as many bookmarks as added were returned by search({})");
+    }).then(bookmarksSearchResults => {
+      browser.test.assertTrue(bookmarksSearchResults.length >= 9, "At least as many bookmarks as added were returned by search({})");
 
       return Promise.resolve().then(() => {
         return browser.bookmarks.remove(createdFolderId);
       }).then(expectedError, error => {
         browser.test.assertTrue(
           error.message.includes("Cannot remove a non-empty folder"),
           "Expected error thrown when trying to remove a non-empty folder"
         );
@@ -520,20 +520,20 @@ function backgroundScript() {
     let startBookmarkCount = results.length;
 
     return browser.bookmarks.search({title: "Mozilla Folder"}).then(result => {
       return browser.bookmarks.removeTree(result[0].id);
     }).then(() => {
       browser.test.assertEq(1, collectedEvents.length, "1 expected events received");
       checkOnRemoved(createdFolderId, bookmarkGuids.unfiledGuid, 1);
 
-      return browser.bookmarks.search({}).then(results => {
+      return browser.bookmarks.search({}).then(searchResults => {
         browser.test.assertEq(
           startBookmarkCount - 4,
-          results.length,
+          searchResults.length,
           "Expected number of results returned after removeTree");
       });
     });
   }).then(() => {
     return browser.bookmarks.create({title: "Empty Folder"});
   }).then(result => {
     let emptyFolderId = result.id;
 
--- a/browser/components/extensions/test/xpcshell/test_ext_history.js
+++ b/browser/components/extensions/test/xpcshell/test_ext_history.js
@@ -58,19 +58,19 @@ add_task(function* test_delete() {
   yield extension.startup();
   yield extension.awaitMessage("ready");
   yield PlacesTestUtils.clearHistory();
 
   let historyClearedCount;
   let visits = [];
   let visitDate = new Date(1999, 9, 9, 9, 9).getTime();
 
-  function pushVisit(visits) {
+  function pushVisit(subvisits) {
     visitDate += 1000;
-    visits.push({date: new Date(visitDate)});
+    subvisits.push({date: new Date(visitDate)});
   }
 
   // Add 5 visits for one uri and 3 visits for 3 others
   for (let i = 0; i < 4; ++i) {
     let visit = {
       url: `${BASE_URL}${i}`,
       title: "visit " + i,
       visits: [],
@@ -161,29 +161,29 @@ add_task(function* test_search() {
       url: MOZILLA_VISIT_URL,
       title: `test visit for ${MOZILLA_VISIT_URL}`,
       visits: [
         {date: new Date(Number(REFERENCE_DATE) - 3000)},
       ],
     },
   ];
 
-  function background(REFERENCE_DATE) {
+  function background(BGSCRIPT_REFERENCE_DATE) {
     const futureTime = Date.now() + 24 * 60 * 60 * 1000;
 
     browser.test.onMessage.addListener(msg => {
       browser.history.search({text: ""}).then(results => {
         browser.test.sendMessage("empty-search", results);
         return browser.history.search({text: "mozilla.com"});
       }).then(results => {
         browser.test.sendMessage("text-search", results);
         return browser.history.search({text: "example.com", maxResults: 1});
       }).then(results => {
         browser.test.sendMessage("max-results-search", results);
-        return browser.history.search({text: "", startTime: REFERENCE_DATE - 2000, endTime: REFERENCE_DATE - 1000});
+        return browser.history.search({text: "", startTime: BGSCRIPT_REFERENCE_DATE - 2000, endTime: BGSCRIPT_REFERENCE_DATE - 1000});
       }).then(results => {
         browser.test.sendMessage("date-range-search", results);
         return browser.history.search({text: "", startTime: futureTime});
       }).then(results => {
         browser.test.assertEq(0, results.length, "no results returned for late start time");
         return browser.history.search({text: "", endTime: 0});
       }).then(results => {
         browser.test.assertEq(0, results.length, "no results returned for early end time");
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/xpcshell/test_ext_manifest_omnibox.js
@@ -0,0 +1,61 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+function* testKeyword(params) {
+  let normalized = yield ExtensionTestUtils.normalizeManifest({
+    "omnibox": {
+      "keyword": params.keyword,
+    },
+  });
+
+  if (params.expectError) {
+    let expectedError = (
+      String.raw`omnibox.keyword: String "${params.keyword}" ` +
+      String.raw`must match /^[^?\s:]([^\s:]*[^/\s:])?$/`
+    );
+    ok(normalized.error.includes(expectedError),
+       `The manifest error ${JSON.stringify(normalized.error)} ` +
+       `must contain ${JSON.stringify(expectedError)}`);
+  } else {
+    equal(normalized.error, undefined, "Should not have an error");
+    equal(normalized.errors.length, 0, "Should not have warnings");
+  }
+}
+
+add_task(function* test_manifest_commands() {
+  // accepted single character keywords
+  yield testKeyword({keyword: "a", expectError: false});
+  yield testKeyword({keyword: "-", expectError: false});
+  yield testKeyword({keyword: "嗨", expectError: false});
+  yield testKeyword({keyword: "*", expectError: false});
+  yield testKeyword({keyword: "/", expectError: false});
+
+  // rejected single character keywords
+  yield testKeyword({keyword: "?", expectError: true});
+  yield testKeyword({keyword: " ", expectError: true});
+  yield testKeyword({keyword: ":", expectError: true});
+
+  // accepted multi-character keywords
+  yield testKeyword({keyword: "aa", expectError: false});
+  yield testKeyword({keyword: "http", expectError: false});
+  yield testKeyword({keyword: "f?a", expectError: false});
+  yield testKeyword({keyword: "fa?", expectError: false});
+  yield testKeyword({keyword: "f/x", expectError: false});
+  yield testKeyword({keyword: "/fx", expectError: false});
+
+  // rejected multi-character keywords
+  yield testKeyword({keyword: " a", expectError: true});
+  yield testKeyword({keyword: "a ", expectError: true});
+  yield testKeyword({keyword: "  ", expectError: true});
+  yield testKeyword({keyword: " a ", expectError: true});
+  yield testKeyword({keyword: "?fx", expectError: true});
+  yield testKeyword({keyword: "fx/", expectError: true});
+  yield testKeyword({keyword: "f:x", expectError: true});
+  yield testKeyword({keyword: "fx:", expectError: true});
+  yield testKeyword({keyword: "f x", expectError: true});
+
+  // miscellaneous tests
+  yield testKeyword({keyword: "こんにちは", expectError: false});
+  yield testKeyword({keyword: "http://", expectError: true});
+});
--- a/browser/components/extensions/test/xpcshell/test_ext_manifest_permissions.js
+++ b/browser/components/extensions/test/xpcshell/test_ext_manifest_permissions.js
@@ -1,19 +1,19 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 /* globals chrome */
 
 function* testPermission(options) {
-  function background(options) {
+  function background(bgOptions) {
     browser.test.sendMessage("typeof-namespace", {
-      browser: typeof browser[options.namespace],
-      chrome: typeof chrome[options.namespace],
+      browser: typeof browser[bgOptions.namespace],
+      chrome: typeof chrome[bgOptions.namespace],
     });
   }
 
   let extensionDetails = {
     background: `(${background})(${JSON.stringify(options)})`,
   };
 
   let extension = ExtensionTestUtils.loadExtension(extensionDetails);
--- a/browser/components/extensions/test/xpcshell/xpcshell.ini
+++ b/browser/components/extensions/test/xpcshell/xpcshell.ini
@@ -2,9 +2,10 @@
 head = head.js
 tail =
 firefox-appdir = browser
 tags = webextensions
 
 [test_ext_bookmarks.js]
 [test_ext_history.js]
 [test_ext_manifest_commands.js]
+[test_ext_manifest_omnibox.js]
 [test_ext_manifest_permissions.js]
--- a/browser/components/migration/.eslintrc.js
+++ b/browser/components/migration/.eslintrc.js
@@ -9,74 +9,74 @@ module.exports = { // eslint-disable-lin
     "Components": true,
     "dump": true,
     "Iterator": true
   },
 
   "env": { "browser": true },
 
   "rules": {
-    "block-scoped-var": 2,
-    // "brace-style": [1, "1tbs", {"allowSingleLine": true}],
-    "comma-dangle": 0,
-    "comma-spacing": [1, {"before": false, "after": true}],
-    "comma-style": [1, "last"],
-    // "complexity": 1,
-    "consistent-return": 2,
-    //"curly": 2,
-    "dot-notation": 2,
-    "eol-last": 2,
-    "indent": [1, 2, {"SwitchCase": 1}],
-    // "key-spacing": [1, {"beforeColon": false, "afterColon": true}],
-    "keyword-spacing": 1,
-    "max-nested-callbacks": [2, 3],
-    "new-parens": 2,
-    "no-array-constructor": 2,
-    "no-cond-assign": 2,
-    "no-control-regex": 2,
-    "no-debugger": 2,
-    "no-delete-var": 2,
-    "no-dupe-args": 2,
-    "no-dupe-keys": 2,
-    "no-duplicate-case": 2,
-    "no-else-return": 2,
-    "no-eval": 2,
-    "no-extend-native": 2,
-    // "no-extra-bind": 2,
-    "no-extra-boolean-cast": 2,
-    "no-extra-semi": 1,
+    "block-scoped-var": "error",
+    // "brace-style": ["warn", "1tbs", {"allowSingleLine": true}],
+    "comma-dangle": "off",
+    "comma-spacing": ["warn", {"before": false, "after": true}],
+    "comma-style": ["warn", "last"],
+    // "complexity": "warn",
+    "consistent-return": "error",
+    //"curly": "error",
+    "dot-notation": "error",
+    "eol-last": "error",
+    "indent": ["warn", 2, {"SwitchCase": 1}],
+    // "key-spacing": ["warn", {"beforeColon": false, "afterColon": true}],
+    "keyword-spacing": "warn",
+    "max-nested-callbacks": ["error", 3],
+    "new-parens": "error",
+    "no-array-constructor": "error",
+    "no-cond-assign": "error",
+    "no-control-regex": "error",
+    "no-debugger": "error",
+    "no-delete-var": "error",
+    "no-dupe-args": "error",
+    "no-dupe-keys": "error",
+    "no-duplicate-case": "error",
+    "no-else-return": "error",
+    "no-eval": "error",
+    "no-extend-native": "error",
+    // "no-extra-bind": "error",
+    "no-extra-boolean-cast": "error",
+    "no-extra-semi": "warn",
     "no-fallthrough": ["error", { "commentPattern": ".*[Ii]ntentional(?:ly)?\\s+fall(?:ing)?[\\s-]*through.*" }],
-    "no-lonely-if": 2,
-    "no-mixed-spaces-and-tabs": 2,
-    "no-multi-spaces": 1,
-    "no-multi-str": 1,
-    "no-native-reassign": 2,
-    "no-nested-ternary": 2,
-    "no-redeclare": 2,
-    "no-return-assign": 2,
-    "no-self-compare": 2,
-    "no-sequences": 2,
-    "no-shadow": 1,
-    "no-shadow-restricted-names": 2,
-    // "no-spaced-func": 1,
-    "no-throw-literal": 2,
-    "no-trailing-spaces": 2,
-    "no-undef": 2,
-    "no-unneeded-ternary": 2,
-    "no-unreachable": 2,
+    "no-lonely-if": "error",
+    "no-mixed-spaces-and-tabs": "error",
+    "no-multi-spaces": "warn",
+    "no-multi-str": "warn",
+    "no-native-reassign": "error",
+    "no-nested-ternary": "error",
+    "no-redeclare": "error",
+    "no-return-assign": "error",
+    "no-self-compare": "error",
+    "no-sequences": "error",
+    "no-shadow": "warn",
+    "no-shadow-restricted-names": "error",
+    // "no-spaced-func": "warn",
+    "no-throw-literal": "error",
+    "no-trailing-spaces": "error",
+    "no-undef": "error",
+    "no-unneeded-ternary": "error",
+    "no-unreachable": "error",
     "no-unused-vars": ["error", { "varsIgnorePattern": "^C[ciur]$" }],
-    "no-with": 2,
-    "padded-blocks": [1, "never"],
+    "no-with": "error",
+    "padded-blocks": ["warn", "never"],
     "quotes": ["error", "double", { "avoidEscape": true, "allowTemplateLiterals": true }],
-    "semi": [2, "always", {"omitLastInOneLineBlock": true }],
-    "semi-spacing": [1, {"before": false, "after": true}],
-    "space-before-blocks": [1, "always"],
-    // "space-before-function-paren": [1, "never"],
-    "space-in-parens": [1, "never"],
-    "space-infix-ops": [1, {"int32Hint": true}],
-    // "space-unary-ops": [1, { "words": true, "nonwords": false }],
-    "strict": [2, "global"],
-    "use-isnan": 2,
-    "valid-typeof": 2,
-    "yoda": 2
+    "semi": ["error", "always", {"omitLastInOneLineBlock": true }],
+    "semi-spacing": ["warn", {"before": false, "after": true}],
+    "space-before-blocks": ["warn", "always"],
+    // "space-before-function-paren": ["warn", "never"],
+    "space-in-parens": ["warn", "never"],
+    "space-infix-ops": ["warn", {"int32Hint": true}],
+    // "space-unary-ops": ["warn", { "words": true, "nonwords": false }],
+    "strict": ["error", "global"],
+    "use-isnan": "error",
+    "valid-typeof": "error",
+    "yoda": "error"
   }
 };
 
--- a/browser/components/migration/MSMigrationUtils.jsm
+++ b/browser/components/migration/MSMigrationUtils.jsm
@@ -559,17 +559,17 @@ Cookies.prototype = {
       } catch (ex) {
         Components.utils.reportError("Unable to migrate cookie: " + ex);
         success = false;
       } finally {
         aCallback(success);
       }
     };
     fileReader.addEventListener("loadend", onLoadEnd, false);
-    fileReader.readAsText(new File(aFile));
+    fileReader.readAsText(File.createFromNsIFile(aFile));
   },
 
   /**
    * Parses a cookie file buffer and returns an array of the contained cookies.
    *
    * The cookie file format is a newline-separated-values with a "*" used as
    * delimeter between multiple records.
    * Each cookie has the following fields:
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -416,16 +416,17 @@ BrowserGlue.prototype = {
       history: 2,
       keyword: 3,
       searchengine: 4,
       searchsuggestion: 5,
       switchtab: 6,
       tag: 7,
       visiturl: 8,
       remotetab: 9,
+      extension: 10,
     };
     if (actionType in buckets) {
       Services.telemetry
               .getHistogramById("FX_URLBAR_SELECTED_RESULT_TYPE")
               .add(buckets[actionType]);
     } else {
       Cu.reportError("Unknown FX_URLBAR_SELECTED_RESULT_TYPE type: " +
                      actionType);
--- a/browser/components/places/tests/unit/test_PUIU_makeTransaction.js
+++ b/browser/components/places/tests/unit/test_PUIU_makeTransaction.js
@@ -28,28 +28,28 @@ function waitForBookmarkNotification(aNo
                                                     index: aIndex,
                                                     type: aItemType,
                                                     url: aURI ? aURI.spec : null,
                                                     title: aTitle });
     },
     onItemRemoved: function onItemRemoved() {
       return this.validate(arguments.callee.name, arguments);
     },
-    onItemChanged: function onItemChanged(aItemId, aProperty, aIsAnno,
-                                          aNewValue, aLastModified, aItemType)
+    onItemChanged: function onItemChanged(id, property, aIsAnno,
+                                          aNewValue, aLastModified, type)
     {
       return this.validate(arguments.callee.name,
-                           { id: aItemId,
+                           { id,
                              get index() {
                                return PlacesUtils.bookmarks.getItemIndex(this.id);
                              },
-                             type: aItemType,
-                             property: aProperty,
+                             type,
+                             property,
                              get url() {
-                               return aItemType == PlacesUtils.bookmarks.TYPE_BOOKMARK ?
+                               return type == PlacesUtils.bookmarks.TYPE_BOOKMARK ?
                                       PlacesUtils.bookmarks.getBookmarkURI(this.id).spec :
                                       null;
                              },
                              get title() {
                                return PlacesUtils.bookmarks.getItemTitle(this.id);
                              },
                            });
     },
@@ -116,51 +116,51 @@ add_test(function test_text_paste()
   );
   PlacesUtils.transactionManager.doTransaction(txn);
 });
 
 add_test(function test_container()
 {
   const TEST_TITLE = "Places folder"
 
-  waitForBookmarkNotification("onItemChanged", function(aData)
+  waitForBookmarkNotification("onItemChanged", function(aChangedData)
   {
-    do_check_eq(aData.title, TEST_TITLE);
-    do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_FOLDER);
-    do_check_eq(aData.index, 1);
+    do_check_eq(aChangedData.title, TEST_TITLE);
+    do_check_eq(aChangedData.type, PlacesUtils.bookmarks.TYPE_FOLDER);
+    do_check_eq(aChangedData.index, 1);
 
-    waitForBookmarkNotification("onItemAdded", function(aData)
+    waitForBookmarkNotification("onItemAdded", function(aAddedData)
     {
-      do_check_eq(aData.title, TEST_TITLE);
-      do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_FOLDER);
-      do_check_eq(aData.index, 2);
-      let id = aData.id;
+      do_check_eq(aAddedData.title, TEST_TITLE);
+      do_check_eq(aAddedData.type, PlacesUtils.bookmarks.TYPE_FOLDER);
+      do_check_eq(aAddedData.index, 2);
+      let id = aAddedData.id;
 
-      waitForBookmarkNotification("onItemMoved", function(aData)
+      waitForBookmarkNotification("onItemMoved", function(aMovedData)
       {
-        do_check_eq(aData.id, id);
-        do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_FOLDER);
-        do_check_eq(aData.index, 1);
+        do_check_eq(aMovedData.id, id);
+        do_check_eq(aMovedData.type, PlacesUtils.bookmarks.TYPE_FOLDER);
+        do_check_eq(aMovedData.index, 1);
 
         run_next_test();
       });
 
       let txn = PlacesUIUtils.makeTransaction(
-        wrapNodeByIdAndParent(aData.id, PlacesUtils.unfiledBookmarksFolderId),
+        wrapNodeByIdAndParent(aAddedData.id, PlacesUtils.unfiledBookmarksFolderId),
         0, // Unused for real nodes.
         PlacesUtils.unfiledBookmarksFolderId,
         1, // Move to position 1.
         false
       );
       PlacesUtils.transactionManager.doTransaction(txn);
     });
 
     try {
     let txn = PlacesUIUtils.makeTransaction(
-      wrapNodeByIdAndParent(aData.id, PlacesUtils.unfiledBookmarksFolderId),
+      wrapNodeByIdAndParent(aChangedData.id, PlacesUtils.unfiledBookmarksFolderId),
       0, // Unused for real nodes.
       PlacesUtils.unfiledBookmarksFolderId,
       PlacesUtils.bookmarks.DEFAULT_INDEX,
       true
     );
     PlacesUtils.transactionManager.doTransaction(txn);
     } catch (ex) {
       do_throw(ex);
@@ -176,49 +176,49 @@ add_test(function test_container()
   PlacesUtils.annotations.setItemAnnotation(id, "random-anno",
                                             "random-value", 0,
                                             PlacesUtils.annotations.EXPIRE_NEVER);
 });
 
 
 add_test(function test_separator()
 {
-  waitForBookmarkNotification("onItemChanged", function(aData)
+  waitForBookmarkNotification("onItemChanged", function(aChangedData)
   {
-    do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_SEPARATOR);
-    do_check_eq(aData.index, 3);
+    do_check_eq(aChangedData.type, PlacesUtils.bookmarks.TYPE_SEPARATOR);
+    do_check_eq(aChangedData.index, 3);
 
-    waitForBookmarkNotification("onItemAdded", function(aData)
+    waitForBookmarkNotification("onItemAdded", function(aAddedData)
     {
-      do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_SEPARATOR);
-      do_check_eq(aData.index, 4);
-      let id = aData.id;
+      do_check_eq(aAddedData.type, PlacesUtils.bookmarks.TYPE_SEPARATOR);
+      do_check_eq(aAddedData.index, 4);
+      let id = aAddedData.id;
 
-      waitForBookmarkNotification("onItemMoved", function(aData)
+      waitForBookmarkNotification("onItemMoved", function(aMovedData)
       {
-        do_check_eq(aData.id, id);
-        do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_SEPARATOR);
-        do_check_eq(aData.index, 1);
+        do_check_eq(aMovedData.id, id);
+        do_check_eq(aMovedData.type, PlacesUtils.bookmarks.TYPE_SEPARATOR);
+        do_check_eq(aMovedData.index, 1);
 
         run_next_test();
       });
 
       let txn = PlacesUIUtils.makeTransaction(
-        wrapNodeByIdAndParent(aData.id, PlacesUtils.unfiledBookmarksFolderId),
+        wrapNodeByIdAndParent(aAddedData.id, PlacesUtils.unfiledBookmarksFolderId),
         0, // Unused for real nodes.
         PlacesUtils.unfiledBookmarksFolderId,
         1, // Move to position 1.
         false
       );
       PlacesUtils.transactionManager.doTransaction(txn);
     });
 
     try {
     let txn = PlacesUIUtils.makeTransaction(
-      wrapNodeByIdAndParent(aData.id, PlacesUtils.unfiledBookmarksFolderId),
+      wrapNodeByIdAndParent(aChangedData.id, PlacesUtils.unfiledBookmarksFolderId),
       0, // Unused for real nodes.
       PlacesUtils.unfiledBookmarksFolderId,
       PlacesUtils.bookmarks.DEFAULT_INDEX,
       true
     );
     PlacesUtils.transactionManager.doTransaction(txn);
     } catch (ex) {
       do_throw(ex);
@@ -232,53 +232,53 @@ add_test(function test_separator()
                                             PlacesUtils.annotations.EXPIRE_NEVER);
 });
 
 add_test(function test_bookmark()
 {
   const TEST_URL = "http://places.moz.org/"
   const TEST_TITLE = "Places bookmark"
 
-  waitForBookmarkNotification("onItemChanged", function(aData)
+  waitForBookmarkNotification("onItemChanged", function(aChangedData)
   {
-    do_check_eq(aData.title, TEST_TITLE);
-    do_check_eq(aData.url, TEST_URL);
-    do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_BOOKMARK);
-    do_check_eq(aData.index, 5);
+    do_check_eq(aChangedData.title, TEST_TITLE);
+    do_check_eq(aChangedData.url, TEST_URL);
+    do_check_eq(aChangedData.type, PlacesUtils.bookmarks.TYPE_BOOKMARK);
+    do_check_eq(aChangedData.index, 5);
 
-    waitForBookmarkNotification("onItemAdded", function(aData)
+    waitForBookmarkNotification("onItemAdded", function(aAddedData)
     {
-      do_check_eq(aData.title, TEST_TITLE);
-      do_check_eq(aData.url, TEST_URL);
-      do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_BOOKMARK);
-      do_check_eq(aData.index, 6);
-      let id = aData.id;
+      do_check_eq(aAddedData.title, TEST_TITLE);
+      do_check_eq(aAddedData.url, TEST_URL);
+      do_check_eq(aAddedData.type, PlacesUtils.bookmarks.TYPE_BOOKMARK);
+      do_check_eq(aAddedData.index, 6);
+      let id = aAddedData.id;
 
-      waitForBookmarkNotification("onItemMoved", function(aData)
+      waitForBookmarkNotification("onItemMoved", function(aMovedData)
       {
-        do_check_eq(aData.id, id);
-        do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_BOOKMARK);
-        do_check_eq(aData.index, 1);
+        do_check_eq(aMovedData.id, id);
+        do_check_eq(aMovedData.type, PlacesUtils.bookmarks.TYPE_BOOKMARK);
+        do_check_eq(aMovedData.index, 1);
 
         run_next_test();
       });
 
       let txn = PlacesUIUtils.makeTransaction(
-        wrapNodeByIdAndParent(aData.id, PlacesUtils.unfiledBookmarksFolderId),
+        wrapNodeByIdAndParent(aAddedData.id, PlacesUtils.unfiledBookmarksFolderId),
         0, // Unused for real nodes.
         PlacesUtils.unfiledBookmarksFolderId,
         1, // Move to position 1.
         false
       );
       PlacesUtils.transactionManager.doTransaction(txn);
     });
 
     try {
     let txn = PlacesUIUtils.makeTransaction(
-      wrapNodeByIdAndParent(aData.id, PlacesUtils.unfiledBookmarksFolderId),
+      wrapNodeByIdAndParent(aChangedData.id, PlacesUtils.unfiledBookmarksFolderId),
       0, // Unused for real nodes.
       PlacesUtils.unfiledBookmarksFolderId,
       PlacesUtils.bookmarks.DEFAULT_INDEX,
       true
     );
     PlacesUtils.transactionManager.doTransaction(txn);
     } catch (ex) {
       do_throw(ex);
@@ -297,34 +297,34 @@ add_test(function test_bookmark()
                                             PlacesUtils.annotations.EXPIRE_NEVER);
 });
 
 add_test(function test_visit()
 {
   const TEST_URL = "http://places.moz.org/"
   const TEST_TITLE = "Places bookmark"
 
-  waitForBookmarkNotification("onItemAdded", function(aData)
+  waitForBookmarkNotification("onItemAdded", function(aAddedData)
   {
-    do_check_eq(aData.title, TEST_TITLE);
-    do_check_eq(aData.url, TEST_URL);
-    do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_BOOKMARK);
-    do_check_eq(aData.index, 7);
+    do_check_eq(aAddedData.title, TEST_TITLE);
+    do_check_eq(aAddedData.url, TEST_URL);
+    do_check_eq(aAddedData.type, PlacesUtils.bookmarks.TYPE_BOOKMARK);
+    do_check_eq(aAddedData.index, 7);
 
-    waitForBookmarkNotification("onItemAdded", function(aData)
+    waitForBookmarkNotification("onItemAdded", function(aAddedData2)
     {
-      do_check_eq(aData.title, TEST_TITLE);
-      do_check_eq(aData.url, TEST_URL);
-      do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_BOOKMARK);
-      do_check_eq(aData.index, 8);
+      do_check_eq(aAddedData2.title, TEST_TITLE);
+      do_check_eq(aAddedData2.url, TEST_URL);
+      do_check_eq(aAddedData2.type, PlacesUtils.bookmarks.TYPE_BOOKMARK);
+      do_check_eq(aAddedData2.index, 8);
       run_next_test();
     });
 
     try {
-    let node = wrapNodeByIdAndParent(aData.id, PlacesUtils.unfiledBookmarksFolderId);
+    let node = wrapNodeByIdAndParent(aAddedData.id, PlacesUtils.unfiledBookmarksFolderId);
     // Simulate a not-bookmarked node, will copy it to a new bookmark.
     node.id = -1;
     let txn = PlacesUIUtils.makeTransaction(
       node,
       0, // Unused for real nodes.
       PlacesUtils.unfiledBookmarksFolderId,
       PlacesUtils.bookmarks.DEFAULT_INDEX,
       true
--- a/browser/components/search/test/browser_oneOffContextMenu_setDefault.js
+++ b/browser/components/search/test/browser_oneOffContextMenu_setDefault.js
@@ -1,14 +1,15 @@
 "use strict";
 
 const TEST_ENGINE_NAME = "Foo";
 const TEST_ENGINE_BASENAME = "testEngine.xml";
 const SEARCHBAR_BASE_ID = "searchbar-engine-one-off-item-";
 const URLBAR_BASE_ID = "urlbar-engine-one-off-item-";
+const ONEOFF_URLBAR_PREF = "browser.urlbar.oneOffSearches";
 
 const searchbar = document.getElementById("searchbar");
 const urlbar = document.getElementById("urlbar");
 const searchPopup = document.getElementById("PopupSearchAutoComplete");
 const urlbarPopup = document.getElementById("PopupAutoCompleteRichResult");
 const searchIcon = document.getAnonymousElementByAttribute(
   searchbar, "anonid", "searchbar-search-button"
 );
@@ -55,16 +56,21 @@ add_task(function* test_searchBarChangeE
                "Should now have the original engine's name for the tooltip");
   Assert.equal(oneOffButton.image, originalEngine.iconURI.spec,
                "Should now have the original engine's uri for the image");
 
   yield promiseClosePopup(searchPopup);
 });
 
 add_task(function* test_urlBarChangeEngine() {
+  Services.prefs.setBoolPref(ONEOFF_URLBAR_PREF, true);
+  registerCleanupFunction(function* () {
+    Services.prefs.clearUserPref(ONEOFF_URLBAR_PREF);
+  });
+
   // Ensure the engine is reset.
   resetEngine();
 
   let oneOffButton = yield openPopupAndGetEngineButton(false, urlbarPopup,
                                                        urlBarOneOffBinding,
                                                        URLBAR_BASE_ID);
 
   const setDefaultEngineMenuItem = document.getAnonymousElementByAttribute(
--- a/browser/components/sessionstore/test/browser_crashedTabs.js
+++ b/browser/components/sessionstore/test/browser_crashedTabs.js
@@ -387,17 +387,18 @@ add_task(function* test_hide_restore_all
 
   // Crash the tab
   yield BrowserTestUtils.crashBrowser(browser);
 
   let doc = browser.contentDocument;
   let restoreAllButton = doc.getElementById("restoreAll");
   let restoreOneButton = doc.getElementById("restoreTab");
 
-  is(restoreAllButton.getAttribute("hidden"), "true", "Restore All button should be hidden");
+  let restoreAllStyles = window.getComputedStyle(restoreAllButton);
+  is(restoreAllStyles.display, "none", "Restore All button should be hidden");
   ok(restoreOneButton.classList.contains("primary"), "Restore Tab button should have the primary class");
 
   let newTab2 = gBrowser.addTab();
   gBrowser.selectedTab = newTab;
 
   browser.loadURI(PAGE_2);
   yield promiseBrowserLoaded(browser);
 
@@ -416,17 +417,18 @@ add_task(function* test_hide_restore_all
   // Crash the first tab.
   yield BrowserTestUtils.crashBrowser(browser);
   yield otherBrowserReady;
 
   doc = browser.contentDocument;
   restoreAllButton = doc.getElementById("restoreAll");
   restoreOneButton = doc.getElementById("restoreTab");
 
-  ok(!restoreAllButton.hasAttribute("hidden"), "Restore All button should not be hidden");
+  restoreAllStyles = window.getComputedStyle(restoreAllButton);
+  isnot(restoreAllStyles.display, "none", "Restore All button should not be hidden");
   ok(!(restoreOneButton.classList.contains("primary")), "Restore Tab button should not have the primary class");
 
   yield BrowserTestUtils.closeWindow(win2);
   gBrowser.removeTab(newTab);
   gBrowser.removeTab(newTab2);
 });
 
 add_task(function* test_aboutcrashedtabzoom() {
--- a/browser/config/tooltool-manifests/linux32/releng.manifest
+++ b/browser/config/tooltool-manifests/linux32/releng.manifest
@@ -11,27 +11,27 @@
 "size": 11189216,
 "digest": "18bc52b0599b1308b667e282abb45f47597bfc98a5140cfcab8da71dacf89dd76d0dee22a04ce26fe7ad1f04e2d6596991f9e5b01fd2aaaab5542965f596b0e6",
 "algorithm": "sha512",
 "filename": "gtk3.tar.xz",
 "setup": "setup.sh",
 "unpack": true
 },
 {
-"version": "rustc 1.12.0 (3191fbae9 2016-09-23) repack x86_64+i586",
-"size": 102403884,
-"digest": "a7c1512d955d3030bcc1ebddfbf512f7b11b66e31634726deab78d0403fc0ceadd603d32b08c1a5025d3e9ee4ff48ddcf5eaba33468bb2161cfb9fb1a557affa",
+"version": "rustc 1.13.0 (2c6933acc 2016-11-07) repack x86_64+i586",
+"size": 68921028,
+"digest": "9a9ceccc02d4be445ffa64617683419a4f47990b1f2689980ac8db13d6369435ef4af1a3714d77377fb7b3b0ec213856ab7144ff22cbe0881d49aed44d82c0fc",
 "algorithm": "sha512",
 "filename": "rustc.tar.xz",
 "unpack": true
 },
 {
-"version": "cargo 0.13.0-nightly (e713e7f 2016-08-31)",
-"size": 3245716,
-"digest": "d5bb0d88ce7bb1b5a316d7a8ca6341672f5ee8008fa7754511bf53fabd54c0770e95397232896d6087547891f1143f6968d8b1e106e39800b43defeb0025c7c0",
+"version": "cargo 0.13.0-nightly (eca9e15 2016-11-01) repack",
+"size": 3027932,
+"digest": "a5c99eeb12b3b9b49632c259c762e34ec13cf72dadf90a0608b8ab1dc66b36cb114c5b45f71d326e12d31d9e88a41b029e6a728ca64cef392c0a8d211c2fe191",
 "algorithm": "sha512",
 "filename": "cargo.tar.xz",
 "unpack": true
 },
 {
 "size": 167175,
 "digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
 "algorithm": "sha512",
--- a/browser/config/tooltool-manifests/linux64/hazard.manifest
+++ b/browser/config/tooltool-manifests/linux64/hazard.manifest
@@ -19,19 +19,19 @@
 "digest" : "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
 "unpack" : true,
 "setup" : "setup.sh",
 "algorithm" : "sha512",
 "filename" : "gtk3.tar.xz",
 "size" : 12072532
 },
 {
-"version": "rustc 1.12.0 (3191fbae9 2016-09-23) repack",
-"size": 102403884,
-"digest": "a7c1512d955d3030bcc1ebddfbf512f7b11b66e31634726deab78d0403fc0ceadd603d32b08c1a5025d3e9ee4ff48ddcf5eaba33468bb2161cfb9fb1a557affa",
+"version": "rustc 1.13.0 (2c6933acc 2016-11-07) repack",
+"size": 68921028,
+"digest": "9a9ceccc02d4be445ffa64617683419a4f47990b1f2689980ac8db13d6369435ef4af1a3714d77377fb7b3b0ec213856ab7144ff22cbe0881d49aed44d82c0fc",
 "algorithm": "sha512",
 "filename": "rustc.tar.xz",
 "unpack": true
 },
 {
 "filename" : "sccache.tar.bz2",
 "algorithm" : "sha512",
 "digest" : "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
--- a/browser/config/tooltool-manifests/linux64/releng.manifest
+++ b/browser/config/tooltool-manifests/linux64/releng.manifest
@@ -11,27 +11,27 @@
 "size": 12072532,
 "digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
 "algorithm": "sha512",
 "filename": "gtk3.tar.xz",
 "setup": "setup.sh",
 "unpack": true
 },
 {
-"version": "rustc 1.12.0 (3191fbae9 2016-09-23) repack",
-"size": 102403884,
-"digest": "a7c1512d955d3030bcc1ebddfbf512f7b11b66e31634726deab78d0403fc0ceadd603d32b08c1a5025d3e9ee4ff48ddcf5eaba33468bb2161cfb9fb1a557affa",
+"version": "rustc 1.13.0 (2c6933acc 2016-11-07) repack",
+"size": 68921028,
+"digest": "9a9ceccc02d4be445ffa64617683419a4f47990b1f2689980ac8db13d6369435ef4af1a3714d77377fb7b3b0ec213856ab7144ff22cbe0881d49aed44d82c0fc",
 "algorithm": "sha512",
 "filename": "rustc.tar.xz",
 "unpack": true
 },
 {
-"version": "cargo 0.13.0-nightly (e713e7f 2016-08-31)",
-"size": 3245716,
-"digest": "d5bb0d88ce7bb1b5a316d7a8ca6341672f5ee8008fa7754511bf53fabd54c0770e95397232896d6087547891f1143f6968d8b1e106e39800b43defeb0025c7c0",
+"version": "cargo 0.13.0-nightly (eca9e15 2016-11-01) repack",
+"size": 3027932,
+"digest": "a5c99eeb12b3b9b49632c259c762e34ec13cf72dadf90a0608b8ab1dc66b36cb114c5b45f71d326e12d31d9e88a41b029e6a728ca64cef392c0a8d211c2fe191",
 "algorithm": "sha512",
 "filename": "cargo.tar.xz",
 "unpack": true
 },
 {
 "size": 167175,
 "digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
 "algorithm": "sha512",
--- a/browser/config/tooltool-manifests/macosx64/cross-releng.manifest
+++ b/browser/config/tooltool-manifests/macosx64/cross-releng.manifest
@@ -19,19 +19,19 @@
 "size": 35215976, 
 "visibility": "internal", 
 "digest": "8be736545ddab25ebded188458ce974d5c9a7e29f3c50d2ebfbcb878f6aff853dd2ff5a3528bdefc64396a10101a1b50fd2fe52000140df33643cebe1ea759da", 
 "algorithm": "sha512", 
 "unpack": true,
 "filename": "MacOSX10.7.sdk.tar.bz2"
 },
 {
-"version": "cargo 0.13.0-nightly (e713e7f 2016-08-31)",
-"size": 3245716,
-"digest": "d5bb0d88ce7bb1b5a316d7a8ca6341672f5ee8008fa7754511bf53fabd54c0770e95397232896d6087547891f1143f6968d8b1e106e39800b43defeb0025c7c0",
+"version": "cargo 0.13.0-nightly (eca9e15 2016-11-01) repack",
+"size": 3027932,
+"digest": "a5c99eeb12b3b9b49632c259c762e34ec13cf72dadf90a0608b8ab1dc66b36cb114c5b45f71d326e12d31d9e88a41b029e6a728ca64cef392c0a8d211c2fe191",
 "algorithm": "sha512",
 "filename": "cargo.tar.xz",
 "unpack": true
 },
 {
 "size": 167175,
 "digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
 "algorithm": "sha512",
@@ -50,16 +50,16 @@
 "size": 188880, 
 "visibility": "public", 
 "digest": "1ffddd43efb03aed897ee42035d9d8d758a8d66ab6c867599ef755e1a586768fc22011ce03698af61454920b00fe8bed08c9a681e7bd324d7f8f78c026c83943", 
 "algorithm": "sha512", 
 "unpack": true,
 "filename": "genisoimage.tar.xz"
 },
 {
-"version": "rustc 1.12.0 (3191fbae9 2016-09-23) repack",
-"size": 179757256,
-"digest": "26bbd6a34beab36620634f7eafe63281e3398ae4673b3a4d49e1da4eae0467bc6efc2471ef842682db527ad137e702b74c68f278025c60c8bb69d244cff1e6b6",
+"version": "rustc 1.13.0 (2c6933acc 2016-11-07) repack",
+"size": 119642844,
+"digest": "b219c07d78819b9ea930024205ac905f89b958948fbfb3146864724bf4994401911fdb1636d6f32e46de1f587f4ee9ae7975a886bfacc5f0bde8ea5955b4e42a",
 "algorithm": "sha512",
 "filename": "rustc.tar.xz",
 "unpack": true
 }
 ]
--- a/browser/config/tooltool-manifests/macosx64/releng.manifest
+++ b/browser/config/tooltool-manifests/macosx64/releng.manifest
@@ -3,27 +3,27 @@
 "version": "clang 3.8.0",
 "size": 133060926,
 "digest": "aff5ad3ac2d41db19d1ba0df5f97b189a7d7e1b6af8c56e22c2b0cced84d75fa98394ded6a4ba5713652e6684a0a46f47aeccf87991f9e849bf8d7d82e564f6f",
 "algorithm": "sha512",
 "filename": "clang.tar.bz2",
 "unpack": true
 },
 {
-"version": "rustc 1.12.0 (3191fbae9 2016-09-23) repack",
-"size": 152905062,
-"digest": "1fb64d68ad41e5ca444a5a91f752efec154957d22bdf078adbc7b6a1cdbeefbadbc618de96cc46540a33849d43ac95a520a463d4f852e1a5a1f636d7079d969f",
+"version": "rustc 1.13.0 (2c6933acc 2016-11-07) repack",
+"size": 104593379,
+"digest": "9cbc4a6d4d647dd79629e97c0e7b177443d30e669ccd761ab520728d8c2b7e1cc4ab38ec444c1957649338c4088861db3bfe4f840ec3fedcc01f9f1a74da200a",
 "algorithm": "sha512",
 "filename": "rustc.tar.bz2",
 "unpack": true
 },
 {
-"version": "cargo 0.13.0-nightly (e713e7f 2016-08-31)",
-"size": 2715131,
-"digest": "f037d2bbbeccb2c95519e083d6d9eecb5cb06a510e849b5721d6933a6c2428203b93ed3d20d3f20329f4d4eee17177d762f051b1ae79fee97d93b84611f3df66",
+"version": "cargo 0.13.0-nightly (eca9e15 2016-11-01) repack",
+"size": 2351877,
+"digest": "76283ceda49015f66b03d18b3c28f70ed4baa09accdfc17b2ec935c7af3e9471d140256a33737563baa2545c34e556a125ade6d4858b9226b8c770dbd7c0756f",
 "algorithm": "sha512",
 "filename": "cargo.tar.bz2",
 "unpack": true
 },
 {
 "version": "cctools port from commit hash db1f8d906cb28, ld only",
 "size": 634496,
 "digest": "037f31fcf29e7bb7fada0d2bdd5e95c7d4cb2692f2a5c98ed6f6a7561b9d81622d015f0d12b291d3667719655f1369e8ce8a0a4a4773aa0ee4753e04a8821173",
--- a/browser/config/tooltool-manifests/win32/build-clang-cl.manifest
+++ b/browser/config/tooltool-manifests/win32/build-clang-cl.manifest
@@ -1,27 +1,27 @@
 [
 {
 "size": 266240,
 "digest": "bb345b0e700ffab4d09436981f14b5de84da55a3f18a7f09ebc4364a4488acdeab8d46f447b12ac70f2da1444a68b8ce8b8675f0dae2ccf845e966d1df0f0869",
 "algorithm": "sha512",
 "filename": "mozmake.exe"
 },
 {
-"version": "rustc 1.12.0 (3191fbae9 2016-09-23) repack",
-"size": 89434100,
-"digest": "4da0efd2c36c77f29846f328d9f3c095a7b7e0dfd94f76b3159d441aae02b25007a475a979fb5bf313cf8fecb22fec81684871809effcb6b514419bc3854f398",
+"version": "rustc 1.13.0 (2c6933acc 2016-11-07) repack",
+"size": 58997576,
+"digest": "be97bb7f60fea39b9b0411b7ce247036a9373b01ed8cc60f30ed3c6254473ab7ef1881f222f10845253e0608c6f3d21add0871d0485d9de413297906d5c5409c",
 "algorithm": "sha512",
 "filename": "rustc.tar.bz2",
 "unpack": true
 },
 {
-"version": "cargo 0.13.0-nightly (e713e7f 2016-08-31)",
-"size": 2402000,
-"digest": "56f12f7ac437742ed717ce0ccfb0b4134160948e45d73016e48d9033567e5b01a171ac95dd7965eb007702c31da73274b5913281655f461f611ddeee37181ecc",
+"version": "cargo 0.13.0-nightly (eca9e15 2016-11-01) repack",
+"size": 2214397,
+"digest": "4f378fc4178d72d9e0434fca3df342d9dd7619c7c524ec6aedeee78a19583f2a675dfc54224be87030d72a36cef77f997e5275fe1cebac065c38949fa464d842",
 "algorithm": "sha512",
 "filename": "cargo.tar.bz2",
 "unpack": true
 },
 {
 "size": 167175,
 "digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
 "algorithm": "sha512",
--- a/browser/config/tooltool-manifests/win32/clang.manifest
+++ b/browser/config/tooltool-manifests/win32/clang.manifest
@@ -1,19 +1,19 @@
 [
 {
 "size": 266240,
 "digest": "bb345b0e700ffab4d09436981f14b5de84da55a3f18a7f09ebc4364a4488acdeab8d46f447b12ac70f2da1444a68b8ce8b8675f0dae2ccf845e966d1df0f0869",
 "algorithm": "sha512",
 "filename": "mozmake.exe"
 },
 {
-"version": "rustc 1.12.0 (3191fbae9 2016-09-23) repack",
-"size": 89434100,
-"digest": "4da0efd2c36c77f29846f328d9f3c095a7b7e0dfd94f76b3159d441aae02b25007a475a979fb5bf313cf8fecb22fec81684871809effcb6b514419bc3854f398",
+"version": "rustc 1.13.0 (2c6933acc 2016-11-07) repack",
+"size": 58997576,
+"digest": "be97bb7f60fea39b9b0411b7ce247036a9373b01ed8cc60f30ed3c6254473ab7ef1881f222f10845253e0608c6f3d21add0871d0485d9de413297906d5c5409c",
 "algorithm": "sha512",
 "filename": "rustc.tar.bz2",
 "unpack": true
 },
 {
 "size": 167175,
 "digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
 "algorithm": "sha512",
--- a/browser/config/tooltool-manifests/win32/releng.manifest
+++ b/browser/config/tooltool-manifests/win32/releng.manifest
@@ -1,27 +1,27 @@
 [
 {
 "size": 266240,
 "digest": "bb345b0e700ffab4d09436981f14b5de84da55a3f18a7f09ebc4364a4488acdeab8d46f447b12ac70f2da1444a68b8ce8b8675f0dae2ccf845e966d1df0f0869",
 "algorithm": "sha512",
 "filename": "mozmake.exe"
 },
 {
-"version": "rustc 1.12.0 (3191fbae9 2016-09-23) repack",
-"size": 89434100,
-"digest": "4da0efd2c36c77f29846f328d9f3c095a7b7e0dfd94f76b3159d441aae02b25007a475a979fb5bf313cf8fecb22fec81684871809effcb6b514419bc3854f398",
+"version": "rustc 1.13.0 (2c6933acc 2016-11-07) repack",
+"size": 58997576,
+"digest": "be97bb7f60fea39b9b0411b7ce247036a9373b01ed8cc60f30ed3c6254473ab7ef1881f222f10845253e0608c6f3d21add0871d0485d9de413297906d5c5409c",
 "algorithm": "sha512",
 "filename": "rustc.tar.bz2",
 "unpack": true
 },
 {
-"version": "cargo 0.13.0-nightly (e713e7f 2016-08-31)",
-"size": 2402000,
-"digest": "56f12f7ac437742ed717ce0ccfb0b4134160948e45d73016e48d9033567e5b01a171ac95dd7965eb007702c31da73274b5913281655f461f611ddeee37181ecc",
+"version": "cargo 0.13.0-nightly (eca9e15 2016-11-01) repack",
+"size": 2214397,
+"digest": "4f378fc4178d72d9e0434fca3df342d9dd7619c7c524ec6aedeee78a19583f2a675dfc54224be87030d72a36cef77f997e5275fe1cebac065c38949fa464d842",
 "algorithm": "sha512",
 "filename": "cargo.tar.bz2",
 "unpack": true
 },
 {
 "size": 167175,
 "digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
 "algorithm": "sha512",
--- a/browser/config/tooltool-manifests/win64/clang.manifest
+++ b/browser/config/tooltool-manifests/win64/clang.manifest
@@ -1,19 +1,19 @@
 [
 {
 "size": 266240,
 "digest": "bb345b0e700ffab4d09436981f14b5de84da55a3f18a7f09ebc4364a4488acdeab8d46f447b12ac70f2da1444a68b8ce8b8675f0dae2ccf845e966d1df0f0869",
 "algorithm": "sha512",
 "filename": "mozmake.exe"
 },
 {
-"version": "rustc 1.12.0 (3191fbae9 2016-09-23) repack",
-"size": 94812923,
-"digest": "f8ff01a44caf38711c352e49c06e8ef6bbac7836bed1050bb043f89ba70f70a11c88001f453baec0cbc56a013efb0fd6b16d612923d07e29b5d8d4512dbaab07",
+"version": "rustc 1.13.0 (2c6933acc 2016-11-07) repack",
+"size": 63966131,
+"digest": "a431492ca5ae3454e7d5de3962ff0b40d96f69a9046428a1fe310397a5dda9ba2f6b697958e8386b119d56b700563ffe1b58c63f84b527b2df320893306854cf",
 "algorithm": "sha512",
 "visibility": "public",
 "filename": "rustc.tar.bz2",
 "unpack": true
 },
 {
 "size": 167175,
 "digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
--- a/browser/config/tooltool-manifests/win64/releng.manifest
+++ b/browser/config/tooltool-manifests/win64/releng.manifest
@@ -1,28 +1,28 @@
 [
 {
 "size": 266240,
 "digest": "bb345b0e700ffab4d09436981f14b5de84da55a3f18a7f09ebc4364a4488acdeab8d46f447b12ac70f2da1444a68b8ce8b8675f0dae2ccf845e966d1df0f0869",
 "algorithm": "sha512",
 "filename": "mozmake.exe"
 },
 {
-"version": "rustc 1.12.0 (3191fbae9 2016-09-23) repack",
-"size": 94812923,
-"digest": "f8ff01a44caf38711c352e49c06e8ef6bbac7836bed1050bb043f89ba70f70a11c88001f453baec0cbc56a013efb0fd6b16d612923d07e29b5d8d4512dbaab07",
+"version": "rustc 1.13.0 (2c6933acc 2016-11-07) repack",
+"size": 63966131,
+"digest": "a431492ca5ae3454e7d5de3962ff0b40d96f69a9046428a1fe310397a5dda9ba2f6b697958e8386b119d56b700563ffe1b58c63f84b527b2df320893306854cf",
 "algorithm": "sha512",
 "visibility": "public",
 "filename": "rustc.tar.bz2",
 "unpack": true
 },
 {
-"version": "cargo 0.13.0-nightly (e713e7f 2016-08-31)",
-"size": 2677831,
-"digest": "eada1edd6142dcde907f14f23c08a2a0b86f108a8fb242f62be6573bbbe1d3b2a4a04c05465d561253d6a617e18cdabee3c87d8cef9a1b5bdd20fe835ef25ff1",
+"version": "cargo 0.13.0-nightly (eca9e15 2016-11-01) repack",
+"size": 2466539,
+"digest": "78b129bd5c933d77c1f09a24c57a652c7cf228fc986000c162f892a46a53fc0f56b8fe1ac924c7e5aaefc4728fd07b679fbf149feb4ed5f2f30c4fd2f776ab7e",
 "algorithm": "sha512",
 "filename": "cargo.tar.bz2",
 "unpack": true
 },
 {
 "size": 167175,
 "digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
 "algorithm": "sha512",
--- a/browser/config/version.txt
+++ b/browser/config/version.txt
@@ -1,1 +1,1 @@
-52.0a1
+53.0a1
--- a/browser/config/version_display.txt
+++ b/browser/config/version_display.txt
@@ -1,1 +1,1 @@
-52.0a1
+53.0a1
new file mode 100644
--- /dev/null
+++ b/browser/docs/BrowserUsageTelemetry.rst
@@ -0,0 +1,28 @@
+.. _browserusagetelemetry:
+
+=======================
+Browser Usage Telemetry
+=======================
+
+The `BrowserUsageTelemetry.jsm <https://dxr.mozilla.org/mozilla-central/source/browser/modules/BrowserUsageTelemetry.jsm>`_ module is the main module for measurements regarding the browser usage (e.g. tab and window counts, search counts, ...).
+
+The measurements recording begins right after the ``SessionStore`` has finished restoring the session (i.e. restoring tabs/windows after Firefox starts).
+
+Search telemetry
+================
+This module exposes the ``recordSearch`` method, which serves as the main entry point for recording search related Telemetry. It records only the search *counts* per engine and the origin of the search, but nothing pertaining the search contents themselves.
+
+As the transition to the ``BrowserUsageTelemetry`` happens, the ``recordSearch`` calls are dispatched through `BrowserSearch.recordSearchInTelemetry <https://dxr.mozilla.org/mozilla-central/rev/3e73fd638e687a4d7f46613586e5156b8e2af846/browser/base/content/browser.js#3752>`_, that is called by all the search related UI components (urlbar, searchbar, context menu and about\:\* pages).
+
+A list of the components recording search Telemetry can be found using the following `DXR search <https://dxr.mozilla.org/mozilla-central/search?q=recordSearchInTelemetry>`_.
+
+Measured interactions
+=====================
+The usage telemetry module currently measures these interactions with the browser:
+
+- *tab and window engagement*: counts the number of non-private tabs and windows opened in a subsession, after the session is restored (see e.g. ``browser.engagement.max_concurrent_tab_count``);
+- *URI loads*: counts the number of page loads (doesn't track and send the addresses, just the counts) directly triggered by the users (see ``browser.engagement.total_uri_count``);
+- *navigation events*: at this time, this only counts the number of time a page load is triggered by a particular UI interaction (e.g. by searching through the URL bar, see ``browser.engagement.navigation.urlbar``).
+
+
+Please see `Scalars.yaml <https://dxr.mozilla.org/mozilla-central/source/toolkit/components/telemetry/Scalars.yaml>`_ for the full list of tracked interactions.
--- a/browser/docs/index.rst
+++ b/browser/docs/index.rst
@@ -4,8 +4,9 @@ Firefox
 
 This is the nascent documentation of the Firefox front-end code.
 
 .. toctree::
    :maxdepth: 1
 
    DirectoryLinksProvider
    UITelemetry
+   BrowserUsageTelemetry
--- a/browser/experiments/test/xpcshell/test_previous_provider.js
+++ b/browser/experiments/test/xpcshell/test_previous_provider.js
@@ -44,19 +44,19 @@ add_task(function* test_provider_basic()
 
   let provider = new Experiments.PreviousExperimentProvider(e);
   e._setPreviousExperimentsProvider(provider);
 
   let deferred = Promise.defer();
   provider.getAddonsByTypes(["experiment"], (addons) => {
     deferred.resolve(addons);
   });
-  let addons = yield deferred.promise;
-  Assert.ok(Array.isArray(addons), "getAddonsByTypes returns an Array.");
-  Assert.equal(addons.length, 0, "No previous add-ons returned.");
+  let experimentAddons = yield deferred.promise;
+  Assert.ok(Array.isArray(experimentAddons), "getAddonsByTypes returns an Array.");
+  Assert.equal(experimentAddons.length, 0, "No previous add-ons returned.");
 
   gManifestObject = {
     version: 1,
     experiments: [
       {
         id: EXPERIMENT1_ID,
         xpiURL: gDataRoot + EXPERIMENT1_XPI_NAME,
         xpiHash: EXPERIMENT1_XPI_SHA1,
@@ -70,18 +70,18 @@ add_task(function* test_provider_basic()
   };
 
   yield e.updateManifest();
 
   deferred = Promise.defer();
   provider.getAddonsByTypes(["experiment"], (addons) => {
     deferred.resolve(addons);
   });
-  addons = yield deferred.promise;
-  Assert.equal(addons.length, 0, "Still no previous experiment.");
+  experimentAddons = yield deferred.promise;
+  Assert.equal(experimentAddons.length, 0, "Still no previous experiment.");
 
   let experiments = yield e.getExperiments();
   Assert.equal(experiments.length, 1, "1 experiment present.");
   Assert.ok(experiments[0].active, "It is active.");
 
   // Deactivate it.
   defineNow(e._policy, new Date(gManifestObject.experiments[0].endTime * 1000 + 1000));
   yield e.updateManifest();
@@ -89,19 +89,19 @@ add_task(function* test_provider_basic()
   experiments = yield e.getExperiments();
   Assert.equal(experiments.length, 1, "1 experiment present.");
   Assert.equal(experiments[0].active, false, "It isn't active.");
 
   deferred = Promise.defer();
   provider.getAddonsByTypes(["experiment"], (addons) => {
     deferred.resolve(addons);
   });
-  addons = yield deferred.promise;
-  Assert.equal(addons.length, 1, "1 previous add-on known.");
-  Assert.equal(addons[0].id, EXPERIMENT1_ID, "ID matches expected.");
+  experimentAddons = yield deferred.promise;
+  Assert.equal(experimentAddons.length, 1, "1 previous add-on known.");
+  Assert.equal(experimentAddons[0].id, EXPERIMENT1_ID, "ID matches expected.");
 
   deferred = Promise.defer();
   provider.getAddonByID(EXPERIMENT1_ID, (addon) => {
     deferred.resolve(addon);
   });
   let addon = yield deferred.promise;
   Assert.ok(addon, "We got an add-on from its ID.");
   Assert.equal(addon.id, EXPERIMENT1_ID, "ID matches expected.");
@@ -110,20 +110,20 @@ add_task(function* test_provider_basic()
   Assert.equal(addon.type, "experiment", "Add-on is an experiment.");
   Assert.equal(addon.isActive, false, "Add-on is not active.");
   Assert.equal(addon.permissions, 0, "Add-on has no permissions.");
 
   deferred = Promise.defer();
   AddonManager.getAddonsByTypes(["experiment"], (addons) => {
     deferred.resolve(addons);
   });
-  addons = yield deferred.promise;
-  Assert.equal(addons.length, 1, "Got 1 experiment from add-on manager.");
-  Assert.equal(addons[0].id, EXPERIMENT1_ID, "ID matches expected.");
-  Assert.ok(addons[0].appDisabled, "It is a previous experiment add-on.");
+  experimentAddons = yield deferred.promise;
+  Assert.equal(experimentAddons.length, 1, "Got 1 experiment from add-on manager.");
+  Assert.equal(experimentAddons[0].id, EXPERIMENT1_ID, "ID matches expected.");
+  Assert.ok(experimentAddons[0].appDisabled, "It is a previous experiment add-on.");
 });
 
 add_task(function* test_active_and_previous() {
   // Building on the previous test, activate experiment 2.
   let e = Experiments.instance();
   let provider = new Experiments.PreviousExperimentProvider(e);
   e._setPreviousExperimentsProvider(provider);
 
@@ -148,27 +148,27 @@ add_task(function* test_active_and_previ
 
   let experiments = yield e.getExperiments();
   Assert.equal(experiments.length, 2, "2 experiments known.");
 
   let deferred = Promise.defer();
   provider.getAddonsByTypes(["experiment"], (addons) => {
     deferred.resolve(addons);
   });
-  let addons = yield deferred.promise;
-  Assert.equal(addons.length, 1, "1 previous experiment.");
+  let experimentAddons = yield deferred.promise;
+  Assert.equal(experimentAddons.length, 1, "1 previous experiment.");
 
   deferred = Promise.defer();
   AddonManager.getAddonsByTypes(["experiment"], (addons) => {
     deferred.resolve(addons);
   });
-  addons = yield deferred.promise;
-  Assert.equal(addons.length, 2, "2 experiment add-ons known.");
+  experimentAddons = yield deferred.promise;
+  Assert.equal(experimentAddons.length, 2, "2 experiment add-ons known.");
 
-  for (let addon of addons) {
+  for (let addon of experimentAddons) {
     if (addon.id == EXPERIMENT1_ID) {
       Assert.equal(addon.isActive, false, "Add-on is not active.");
       Assert.ok(addon.appDisabled, "Should be a previous experiment.");
     }
     else if (addon.id == EXPERIMENT2_ID) {
       Assert.ok(addon.isActive, "Add-on is active.");
       Assert.ok(!addon.appDisabled, "Should not be a previous experiment.");
     }
--- a/browser/extensions/e10srollout/bootstrap.js
+++ b/browser/extensions/e10srollout/bootstrap.js
@@ -12,17 +12,17 @@ Cu.import("resource://gre/modules/Update
 
  // The amount of people to be part of e10s
 const TEST_THRESHOLD = {
   "beta"    : 0.5,  // 50%
   "release" : 1.0,  // 100%
 };
 
 const ADDON_ROLLOUT_POLICY = {
-  "beta"    : "50allmpc", // Any WebExtension or addon with mpc = true
+  "beta"    : "51alladdons", // Any WebExtension or addon with mpc = true
   "release" : "50allmpc", // Any WebExtension or addon with mpc = true
 };
 
 const PREF_COHORT_SAMPLE       = "e10s.rollout.cohortSample";
 const PREF_COHORT_NAME         = "e10s.rollout.cohort";
 const PREF_E10S_OPTED_IN       = "browser.tabs.remote.autostart";
 const PREF_E10S_FORCE_ENABLED  = "browser.tabs.remote.force-enable";
 const PREF_E10S_FORCE_DISABLED = "browser.tabs.remote.force-disable";
@@ -165,20 +165,10 @@ function optedOut() {
 
 /* If this function returns a non-empty string, it
  * means that this particular user should be temporarily
  * disqualified due to some particular reason.
  * If a user shouldn't be disqualified, then an empty
  * string must be returned.
  */
 function getTemporaryDisqualification() {
-  let applicationLanguage =
-    Cc["@mozilla.org/chrome/chrome-registry;1"]
-      .getService(Ci.nsIXULChromeRegistry)
-      .getSelectedLocale("global")
-      .split("-")[0];
-
-  if (applicationLanguage == "ru") {
-    return "ru";
-  }
-
   return "";
 }
--- a/browser/extensions/e10srollout/install.rdf.in
+++ b/browser/extensions/e10srollout/install.rdf.in
@@ -5,17 +5,17 @@
 
 #filter substitution
 
 <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
      xmlns:em="http://www.mozilla.org/2004/em-rdf#">
 
   <Description about="urn:mozilla:install-manifest">
     <em:id>e10srollout@mozilla.org</em:id>
-    <em:version>1.5</em:version>
+    <em:version>1.6</em:version>
     <em:type>2</em:type>
     <em:bootstrap>true</em:bootstrap>
     <em:multiprocessCompatible>true</em:multiprocessCompatible>
 
     <!-- Target Application this theme can install into,
         with minimum and maximum supported versions. -->
     <em:targetApplication>
       <Description>
--- a/browser/extensions/formautofill/.eslintrc.js
+++ b/browser/extensions/formautofill/.eslintrc.js
@@ -7,468 +7,468 @@ module.exports = { // eslint-disable-lin
     "Components": true,
     "dump": true,
     "TextDecoder": false,
     "TextEncoder": false,
   },
 
   "rules": {
     // Rules from the mozilla plugin
-    "mozilla/balanced-listeners": 2,
-    "mozilla/no-aArgs": 1,
-    "mozilla/no-cpows-in-tests": 1,
-    "mozilla/var-only-at-top-level": 1,
+    "mozilla/balanced-listeners": "error",
+    "mozilla/no-aArgs": "warn",
+    "mozilla/no-cpows-in-tests": "warn",
+    "mozilla/var-only-at-top-level": "warn",
 
-    "valid-jsdoc": [2, {
+    "valid-jsdoc": ["error", {
       "prefer": {
         "return": "returns",
       },
       "preferType": {
         "Boolean": "boolean",
         "Number": "number",
         "String": "string",
         "bool": "boolean",
       },
       "requireParamDescription": false,
       "requireReturn": false,
       "requireReturnDescription": false,
     }],
 
     // Braces only needed for multi-line arrow function blocks
-    // "arrow-body-style": [2, "as-needed"],
+    // "arrow-body-style": ["error", "as-needed"],
 
     // Require spacing around =>
-    "arrow-spacing": 2,
+    "arrow-spacing": "error",
 
     // Always require spacing around a single line block
-    "block-spacing": 1,
+    "block-spacing": "warn",
 
     // Forbid spaces inside the square brackets of array literals.
-    "array-bracket-spacing": [2, "never"],
+    "array-bracket-spacing": ["error", "never"],
 
     // Forbid spaces inside the curly brackets of object literals.
-    "object-curly-spacing": [2, "never"],
+    "object-curly-spacing": ["error", "never"],
 
     // No space padding in parentheses
-    "space-in-parens": [2, "never"],
+    "space-in-parens": ["error", "never"],
 
     // Enforce one true brace style (opening brace on the same line) and avoid
     // start and end braces on the same line.
-    "brace-style": [2, "1tbs", {"allowSingleLine": true}],
+    "brace-style": ["error", "1tbs", {"allowSingleLine": true}],
 
     // No space before always a space after a comma
-    "comma-spacing": [2, {"before": false, "after": true}],
+    "comma-spacing": ["error", {"before": false, "after": true}],
 
     // Commas at the end of the line not the start
-    "comma-style": 2,
+    "comma-style": "error",
 
     // Don't require spaces around computed properties
-    "computed-property-spacing": [1, "never"],
+    "computed-property-spacing": ["warn", "never"],
 
     // Functions are not required to consistently return something or nothing
-    "consistent-return": 0,
+    "consistent-return": "off",
 
     // Require braces around blocks that start a new line
-    "curly": [2, "all"],
+    "curly": ["error", "all"],
 
     // Always require a trailing EOL
-    "eol-last": 2,
+    "eol-last": "error",
 
     // Require function* name()
-    "generator-star-spacing": [2, {"before": false, "after": true}],
+    "generator-star-spacing": ["error", {"before": false, "after": true}],
 
     // Two space indent
-    "indent": [2, 2, {"SwitchCase": 1}],
+    "indent": ["error", 2, {"SwitchCase": 1}],
 
     // Space after colon not before in property declarations
-    "key-spacing": [2, {"beforeColon": false, "afterColon": true, "mode": "minimum"}],
+    "key-spacing": ["error", {"beforeColon": false, "afterColon": true, "mode": "minimum"}],
 
     // Require spaces before and after finally, catch, etc.
-    "keyword-spacing": 2,
+    "keyword-spacing": "error",
 
     // Unix linebreaks
-    "linebreak-style": [2, "unix"],
+    "linebreak-style": ["error", "unix"],
 
     // Always require parenthesis for new calls
-    "new-parens": 2,
+    "new-parens": "error",
 
     // Use [] instead of Array()
-    "no-array-constructor": 2,
+    "no-array-constructor": "error",
 
     // No duplicate arguments in function declarations
-    "no-dupe-args": 2,
+    "no-dupe-args": "error",
 
     // No duplicate keys in object declarations
-    "no-dupe-keys": 2,
+    "no-dupe-keys": "error",
 
     // No duplicate cases in switch statements
-    "no-duplicate-case": 2,
+    "no-duplicate-case": "error",
 
     // If an if block ends with a return no need for an else block
-    // "no-else-return": 2,
+    // "no-else-return": "error",
 
     // Disallow empty statements. This will report an error for:
     // try { something(); } catch (e) {}
     // but will not report it for:
     // try { something(); } catch (e) { /* Silencing the error because ...*/ }
     // which is a valid use case.
-    "no-empty": 2,
+    "no-empty": "error",
 
     // No empty character classes in regex
-    "no-empty-character-class": 2,
+    "no-empty-character-class": "error",
 
     // Disallow empty destructuring
-    "no-empty-pattern": 2,
+    "no-empty-pattern": "error",
 
     // No assiging to exception variable
-    "no-ex-assign": 2,
+    "no-ex-assign": "error",
 
     // No using !! where casting to boolean is already happening
-    "no-extra-boolean-cast": 1,
+    "no-extra-boolean-cast": "warn",
 
     // No double semicolon
-    "no-extra-semi": 2,
+    "no-extra-semi": "error",
 
     // No overwriting defined functions
-    "no-func-assign": 2,
+    "no-func-assign": "error",
 
     // No invalid regular expresions
-    "no-invalid-regexp": 2,
+    "no-invalid-regexp": "error",
 
     // No odd whitespace characters
-    "no-irregular-whitespace": 2,
+    "no-irregular-whitespace": "error",
 
     // No single if block inside an else block
-    "no-lonely-if": 1,
+    "no-lonely-if": "warn",
 
     // No mixing spaces and tabs in indent
-    "no-mixed-spaces-and-tabs": [2, "smart-tabs"],
+    "no-mixed-spaces-and-tabs": ["error", "smart-tabs"],
 
     // Disallow use of multiple spaces (sometimes used to align const values,
     // array or object items, etc.). It's hard to maintain and doesn't add that
     // much benefit.
-    "no-multi-spaces": 1,
+    "no-multi-spaces": "warn",
 
     // No reassigning native JS objects
-    "no-native-reassign": 2,
+    "no-native-reassign": "error",
 
     // No (!foo in bar)
-    "no-negated-in-lhs": 2,
+    "no-negated-in-lhs": "error",
 
     // Nested ternary statements are confusing
-    "no-nested-ternary": 2,
+    "no-nested-ternary": "error",
 
     // Use {} instead of new Object()
-    "no-new-object": 2,
+    "no-new-object": "error",
 
     // No Math() or JSON()
-    "no-obj-calls": 2,
+    "no-obj-calls": "error",
 
     // No octal literals
-    "no-octal": 2,
+    "no-octal": "error",
 
     // No redeclaring variables
-    "no-redeclare": 2,
+    "no-redeclare": "error",
 
     // No unnecessary comparisons
-    "no-self-compare": 2,
+    "no-self-compare": "error",
 
     // No spaces between function name and parentheses
-    "no-spaced-func": 1,
+    "no-spaced-func": "warn",
 
     // No trailing whitespace
-    "no-trailing-spaces": 2,
+    "no-trailing-spaces": "error",
 
     // Error on newline where a semicolon is needed
-    "no-unexpected-multiline": 2,
+    "no-unexpected-multiline": "error",
 
     // No unreachable statements
-    "no-unreachable": 2,
+    "no-unreachable": "error",
 
     // No expressions where a statement is expected
-    "no-unused-expressions": 2,
+    "no-unused-expressions": "error",
 
     // No declaring variables that are never used
-    "no-unused-vars": [2, {"args": "none", "varsIgnorePattern": "^(Cc|Ci|Cr|Cu|EXPORTED_SYMBOLS)$"}],
+    "no-unused-vars": ["error", {"args": "none", "varsIgnorePattern": "^(Cc|Ci|Cr|Cu|EXPORTED_SYMBOLS)$"}],
 
     // No using variables before defined
-    "no-use-before-define": 2,
+    "no-use-before-define": "error",
 
     // No using with
-    "no-with": 2,
+    "no-with": "error",
 
     // Always require semicolon at end of statement
-    "semi": [2, "always"],
+    "semi": ["error", "always"],
 
     // Require space before blocks
-    "space-before-blocks": 2,
+    "space-before-blocks": "error",
 
     // Never use spaces before function parentheses
-    "space-before-function-paren": [2, {"anonymous": "never", "named": "never"}],
+    "space-before-function-paren": ["error", {"anonymous": "never", "named": "never"}],
 
-    // Require spaces around operators, except for a|0.
-    "space-infix-ops": [2, {"int32Hint": true}],
+    // Require spaces around operators, except for a|"off".
+    "space-infix-ops": ["error", {"int32Hint": true}],
 
     // ++ and -- should not need spacing
-    "space-unary-ops": [1, {"nonwords": false}],
+    "space-unary-ops": ["warn", {"nonwords": false}],
 
     // No comparisons to NaN
-    "use-isnan": 2,
+    "use-isnan": "error",
 
     // Only check typeof against valid results
-    "valid-typeof": 2,
+    "valid-typeof": "error",
 
     // Disallow using variables outside the blocks they are defined (especially
     // since only let and const are used, see "no-var").
-    "block-scoped-var": 2,
+    "block-scoped-var": "error",
 
     // Allow trailing commas for easy list extension.  Having them does not
     // impair readability, but also not required either.
-    "comma-dangle": [2, "always-multiline"],
+    "comma-dangle": ["error", "always-multiline"],
 
     // Warn about cyclomatic complexity in functions.
-    "complexity": 1,
+    "complexity": "warn",
 
     // Don't warn for inconsistent naming when capturing this (not so important
     // with auto-binding fat arrow functions).
-    // "consistent-this": [2, "self"],
+    // "consistent-this": ["error", "self"],
 
     // Don't require a default case in switch statements. Avoid being forced to
     // add a bogus default when you know all possible cases are handled.
-    "default-case": 0,
+    "default-case": "off",
 
     // Enforce dots on the next line with property name.
-    "dot-location": [2, "property"],
+    "dot-location": ["error", "property"],
 
     // Encourage the use of dot notation whenever possible.
-    "dot-notation": 2,
+    "dot-notation": "error",
 
     // Allow using == instead of ===, in the interest of landing something since
     // the devtools codebase is split on convention here.
-    "eqeqeq": 0,
+    "eqeqeq": "off",
 
     // Don't require function expressions to have a name.
     // This makes the code more verbose and hard to read. Our engine already
     // does a fantastic job assigning a name to the function, which includes
     // the enclosing function name, and worst case you have a line number that
     // you can just look up.
-    "func-names": 0,
+    "func-names": "off",
 
     // Allow use of function declarations and expressions.
-    "func-style": 0,
+    "func-style": "off",
 
     // Don't enforce the maximum depth that blocks can be nested. The complexity
     // rule is a better rule to check this.
-    "max-depth": 0,
+    "max-depth": "off",
 
     // Maximum length of a line.
     // Disabled because we exceed this in too many places.
-    "max-len": [0, 80],
+    "max-len": ["off", 80],
 
     // Maximum depth callbacks can be nested.
-    "max-nested-callbacks": [2, 4],
+    "max-nested-callbacks": ["error", 4],
 
     // Don't limit the number of parameters that can be used in a function.
-    "max-params": 0,
+    "max-params": "off",
 
     // Don't limit the maximum number of statement allowed in a function. We
     // already have the complexity rule that's a better measurement.
-    "max-statements": 0,
+    "max-statements": "off",
 
     // Don't require a capital letter for constructors, only check if all new
     // operators are followed by a capital letter. Don't warn when capitalized
     // functions are used without the new operator.
-    "new-cap": [0, {"capIsNew": false}],
+    "new-cap": ["off", {"capIsNew": false}],
 
     // Allow use of bitwise operators.
-    "no-bitwise": 0,
+    "no-bitwise": "off",
 
     // Disallow use of arguments.caller or arguments.callee.
-    "no-caller": 2,
+    "no-caller": "error",
 
     // Disallow the catch clause parameter name being the same as a variable in
     // the outer scope, to avoid confusion.
-    "no-catch-shadow": 0,
+    "no-catch-shadow": "off",
 
     // Disallow assignment in conditional expressions.
-    "no-cond-assign": 2,
+    "no-cond-assign": "error",
 
     // Disallow using the console API.
-    "no-console": 2,
+    "no-console": "error",
 
     // Allow using constant expressions in conditions like while (true)
-    "no-constant-condition": 0,
+    "no-constant-condition": "off",
 
     // Allow use of the continue statement.
-    "no-continue": 0,
+    "no-continue": "off",
 
     // Disallow control characters in regular expressions.
-    "no-control-regex": 2,
+    "no-control-regex": "error",
 
     // Disallow use of debugger.
-    "no-debugger": 2,
+    "no-debugger": "error",
 
     // Disallow deletion of variables (deleting properties is fine).
-    "no-delete-var": 2,
+    "no-delete-var": "error",
 
     // Allow division operators explicitly at beginning of regular expression.
-    "no-div-regex": 0,
+    "no-div-regex": "off",
 
     // Disallow use of eval(). We have other APIs to evaluate code in content.
-    "no-eval": 2,
+    "no-eval": "error",
 
     // Disallow adding to native types
-    "no-extend-native": 2,
+    "no-extend-native": "error",
 
     // Disallow unnecessary function binding.
-    "no-extra-bind": 2,
+    "no-extra-bind": "error",
 
     // Allow unnecessary parentheses, as they may make the code more readable.
-    "no-extra-parens": 0,
+    "no-extra-parens": "off",
 
     // Disallow fallthrough of case statements, except if there is a comment.
-    "no-fallthrough": 2,
+    "no-fallthrough": "error",
 
     // Allow the use of leading or trailing decimal points in numeric literals.
-    "no-floating-decimal": 0,
+    "no-floating-decimal": "off",
 
     // Allow comments inline after code.
-    "no-inline-comments": 0,
+    "no-inline-comments": "off",
 
     // Disallow use of labels for anything other then loops and switches.
-    "no-labels": [2, {"allowLoop": true}],
+    "no-labels": ["error", {"allowLoop": true}],
 
     // Disallow use of multiline strings (use template strings instead).
-    "no-multi-str": 1,
+    "no-multi-str": "warn",
 
     // Disallow multiple empty lines.
-    "no-multiple-empty-lines": [1, {"max": 2}],
+    "no-multiple-empty-lines": ["warn", {"max": 2}],
 
     // Allow reassignment of function parameters.
-    "no-param-reassign": 0,
+    "no-param-reassign": "off",
 
     // Allow string concatenation with __dirname and __filename (not a node env).
-    "no-path-concat": 0,
+    "no-path-concat": "off",
 
     // Allow use of unary operators, ++ and --.
-    "no-plusplus": 0,
+    "no-plusplus": "off",
 
     // Allow using process.env (not a node environment).
-    "no-process-env": 0,
+    "no-process-env": "off",
 
     // Allow using process.exit (not a node environment).
-    "no-process-exit": 0,
+    "no-process-exit": "off",
 
     // Disallow usage of __proto__ property.
-    "no-proto": 2,
+    "no-proto": "error",
 
     // Disallow multiple spaces in a regular expression literal.
-    "no-regex-spaces": 2,
+    "no-regex-spaces": "error",
 
     // Allow reserved words being used as object literal keys.
-    "no-reserved-keys": 0,
+    "no-reserved-keys": "off",
 
     // Don't restrict usage of specified node modules (not a node environment).
-    "no-restricted-modules": 0,
+    "no-restricted-modules": "off",
 
     // Disallow use of assignment in return statement. It is preferable for a
     // single line of code to have only one easily predictable effect.
-    "no-return-assign": 2,
+    "no-return-assign": "error",
 
     // Don't warn about declaration of variables already declared in the outer scope.
-    "no-shadow": 0,
+    "no-shadow": "off",
 
     // Disallow shadowing of names such as arguments.
-    "no-shadow-restricted-names": 2,
+    "no-shadow-restricted-names": "error",
 
     // Allow use of synchronous methods (not a node environment).
-    "no-sync": 0,
+    "no-sync": "off",
 
     // Allow the use of ternary operators.
-    "no-ternary": 0,
+    "no-ternary": "off",
 
     // Disallow throwing literals (eg. throw "error" instead of
     // throw new Error("error")).
-    "no-throw-literal": 2,
+    "no-throw-literal": "error",
 
     // Disallow use of undeclared variables unless mentioned in a /* global */
     // block. Note that globals from head.js are automatically imported in tests
     // by the import-headjs-globals rule form the mozilla eslint plugin.
-    "no-undef": 2,
+    "no-undef": "error",
 
     // Allow dangling underscores in identifiers (for privates).
-    "no-underscore-dangle": 0,
+    "no-underscore-dangle": "off",
 
     // Allow use of undefined variable.
-    "no-undefined": 0,
+    "no-undefined": "off",
 
     // Disallow the use of Boolean literals in conditional expressions.
-    "no-unneeded-ternary": 2,
+    "no-unneeded-ternary": "error",
 
     // We use var-only-at-top-level instead of no-var as we allow top level
     // vars.
-    "no-var": 0,
+    "no-var": "off",
 
     // Allow using TODO/FIXME comments.
-    "no-warning-comments": 0,
+    "no-warning-comments": "off",
 
     // Don't require method and property shorthand syntax for object literals.
     // We use this in the code a lot, but not consistently, and this seems more
     // like something to check at code review time.
-    "object-shorthand": 0,
+    "object-shorthand": "off",
 
     // Allow more than one variable declaration per function.
-    "one-var": 0,
+    "one-var": "off",
 
     // Disallow padding within blocks.
-    "padded-blocks": [1, "never"],
+    "padded-blocks": ["warn", "never"],
 
     // Don't require quotes around object literal property names.
-    "quote-props": 0,
+    "quote-props": "off",
 
     // Double quotes should be used.
-    "quotes": [1, "double", {"avoidEscape": true, "allowTemplateLiterals": true}],
+    "quotes": ["warn", "double", {"avoidEscape": true, "allowTemplateLiterals": true}],
 
     // Require use of the second argument for parseInt().
-    "radix": 2,
+    "radix": "error",
 
     // Enforce spacing after semicolons.
-    "semi-spacing": [2, {"before": false, "after": true}],
+    "semi-spacing": ["error", {"before": false, "after": true}],
 
     // Don't require to sort variables within the same declaration block.
     // Anyway, one-var is disabled.
-    "sort-vars": 0,
+    "sort-vars": "off",
 
     // Require a space immediately following the // in a line comment.
-    "spaced-comment": [2, "always"],
+    "spaced-comment": ["error", "always"],
 
     // Require "use strict" to be defined globally in the script.
-    "strict": [2, "global"],
+    "strict": ["error", "global"],
 
     // Allow vars to be declared anywhere in the scope.
-    "vars-on-top": 0,
+    "vars-on-top": "off",
 
     // Don't require immediate function invocation to be wrapped in parentheses.
-    "wrap-iife": 0,
+    "wrap-iife": "off",
 
     // Don't require regex literals to be wrapped in parentheses (which
     // supposedly prevent them from being mistaken for division operators).
-    "wrap-regex": 0,
+    "wrap-regex": "off",
 
     // Disallow Yoda conditions (where literal value comes first).
-    "yoda": 2,
+    "yoda": "error",
 
     // disallow use of eval()-like methods
-    "no-implied-eval": 2,
+    "no-implied-eval": "error",
 
     // Disallow function or variable declarations in nested blocks
-    "no-inner-declarations": 2,
+    "no-inner-declarations": "error",
 
     // Disallow usage of __iterator__ property
-    "no-iterator": 2,
+    "no-iterator": "error",
 
     // Disallow labels that share a name with a variable
-    "no-label-var": 2,
+    "no-label-var": "error",
 
     // Disallow creating new instances of String, Number, and Boolean
-    "no-new-wrappers": 2,
+    "no-new-wrappers": "error",
   },
 };
--- a/browser/extensions/pdfjs/README.mozilla
+++ b/browser/extensions/pdfjs/README.mozilla
@@ -1,3 +1,3 @@
 This is the pdf.js project output, https://github.com/mozilla/pdf.js
 
-Current extension version is: 1.6.304
+Current extension version is: 1.6.315
--- a/browser/extensions/pdfjs/content/build/pdf.js
+++ b/browser/extensions/pdfjs/content/build/pdf.js
@@ -19,18 +19,18 @@
   } else if (typeof exports !== 'undefined') {
     factory(exports);
   } else {
     factory(root['pdfjsDistBuildPdf'] = {});
   }
 }(this, function (exports) {
   // Use strict in our context only - users might not want it
   'use strict';
-  var pdfjsVersion = '1.6.304';
-  var pdfjsBuild = 'b4100ba';
+  var pdfjsVersion = '1.6.315';
+  var pdfjsBuild = 'a139c75';
   var pdfjsFilePath = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : null;
   var pdfjsLibs = {};
   (function pdfjsWrapper() {
     (function (root, factory) {
       factory(root.pdfjsSharedUtil = {});
     }(this, function (exports) {
       var globalScope = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : this;
       var FONT_IDENTITY_MATRIX = [
--- a/browser/extensions/pdfjs/content/build/pdf.worker.js
+++ b/browser/extensions/pdfjs/content/build/pdf.worker.js
@@ -19,18 +19,18 @@
   } else if (typeof exports !== 'undefined') {
     factory(exports);
   } else {
     factory(root['pdfjsDistBuildPdfWorker'] = {});
   }
 }(this, function (exports) {
   // Use strict in our context only - users might not want it
   'use strict';
-  var pdfjsVersion = '1.6.304';
-  var pdfjsBuild = 'b4100ba';
+  var pdfjsVersion = '1.6.315';
+  var pdfjsBuild = 'a139c75';
   var pdfjsFilePath = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : null;
   var pdfjsLibs = {};
   (function pdfjsWrapper() {
     (function (root, factory) {
       factory(root.pdfjsCoreArithmeticDecoder = {});
     }(this, function (exports) {
       /* This class implements the QM Coder decoding as defined in
        *   JPEG 2000 Part I Final Committee Draft Version 1.0
@@ -45074,16 +45074,39 @@
               }
               break;
             case 'Named':
               var namedAction = action.get('N');
               if (isName(namedAction)) {
                 resultObj.action = namedAction.name;
               }
               break;
+            case 'JavaScript':
+              var jsAction = action.get('JS'), js;
+              if (isStream(jsAction)) {
+                js = bytesToString(jsAction.getBytes());
+              } else if (isString(jsAction)) {
+                js = jsAction;
+              }
+              if (js) {
+                // Attempt to recover valid URLs from 'JS' entries with certain
+                // white-listed formats, e.g.
+                //  - window.open('http://example.com')
+                //  - app.launchURL('http://example.com', true)
+                var URL_OPEN_METHODS = [
+                  'app.launchURL',
+                  'window.open'
+                ];
+                var regex = new RegExp('^(?:' + URL_OPEN_METHODS.join('|') + ')' + '\\((?:\'|\")(\\S+)(?:\'|\")(?:,|\\))');
+                var jsUrl = regex.exec(stringToPDFString(js), 'i');
+                if (jsUrl && jsUrl[1]) {
+                  url = jsUrl[1];
+                  break;
+                }
+              }
             default:
               warn('Catalog_parseDestDictionary: Unrecognized link type "' + linkType + '".');
               break;
             }
           } else if (destDict.has('Dest')) {
             // Simple destination link.
             dest = destDict.get('Dest');
           }
--- a/browser/extensions/pdfjs/content/web/viewer.css
+++ b/browser/extensions/pdfjs/content/web/viewer.css
@@ -321,42 +321,16 @@ select {
   cursor: none;
 }
 
 .pdfPresentationMode.pdfPresentationModeControls > *,
 .pdfPresentationMode.pdfPresentationModeControls .textLayer > div {
   cursor: default;
 }
 
-/* outer/inner center provides horizontal center */
-.outerCenter {
-  pointer-events: none;
-  position: relative;
-}
-html[dir='ltr'] .outerCenter {
-  float: right;
-  right: 50%;
-}
-html[dir='rtl'] .outerCenter {
-  float: left;
-  left: 50%;
-}
-.innerCenter {
-  pointer-events: auto;
-  position: relative;
-}
-html[dir='ltr'] .innerCenter {
-  float: right;
-  right: -50%;
-}
-html[dir='rtl'] .innerCenter {
-  float: left;
-  left: -50%;
-}
-
 #outerContainer {
   width: 100%;
   height: 100%;
   position: relative;
 }
 
 #sidebarContainer {
   position: absolute;
@@ -660,34 +634,29 @@ html[dir='ltr'] .doorHangerRight:before 
   font-style: italic;
   color: #A6B7D0;
 }
 
 #findInput.notFound {
   background-color: rgb(255, 102, 102);
 }
 
-html[dir='ltr'] #toolbarViewerLeft {
-  margin-left: -1px;
-}
-html[dir='rtl'] #toolbarViewerRight {
-  margin-right: -1px;
+#toolbarViewerMiddle {
+  position: absolute;
+  left: 50%;
+  transform: translateX(-50%);
 }
 
 html[dir='ltr'] #toolbarViewerLeft,
 html[dir='rtl'] #toolbarViewerRight {
-  position: absolute;
-  top: 0;
-  left: 0;
+  float: left;
 }
 html[dir='ltr'] #toolbarViewerRight,
 html[dir='rtl'] #toolbarViewerLeft {
-  position: absolute;
-  top: 0;
-  right: 0;
+  float: right;
 }
 html[dir='ltr'] #toolbarViewerLeft > *,
 html[dir='ltr'] #toolbarViewerMiddle > *,
 html[dir='ltr'] #toolbarViewerRight > *,
 html[dir='ltr'] .findbar > * {
   position: relative;
   float: left;
 }
@@ -1953,48 +1922,57 @@ html[dir='rtl'] #documentPropertiesOverl
 }
 
 .visibleLargeView,
 .visibleMediumView,
 .visibleSmallView {
   display: none;
 }
 
-@media all and (max-width: 960px) {
-  html[dir='ltr'] #outerContainer.sidebarMoving .outerCenter,
-  html[dir='ltr'] #outerContainer.sidebarOpen .outerCenter {
-    float: left;
-    left: 205px;
-  }
-  html[dir='rtl'] #outerContainer.sidebarMoving .outerCenter,
-  html[dir='rtl'] #outerContainer.sidebarOpen .outerCenter {
-    float: right;
-    right: 205px;
+@media all and (max-width: 1040px) {
+  #outerContainer.sidebarMoving #toolbarViewerMiddle,
+  #outerContainer.sidebarOpen #toolbarViewerMiddle {
+    display: table;
+    margin: auto;
+    left: auto;
+    position: inherit;
+    transform: none;
   }
 }
 
-@media all and (max-width: 900px) {
+@media all and (max-width: 980px) {
+  .sidebarMoving .hiddenLargeView,
   .sidebarOpen .hiddenLargeView {
     display: none;
   }
+  .sidebarMoving .visibleLargeView,
   .sidebarOpen .visibleLargeView {
     display: inherit;
   }
 }
 
-@media all and (max-width: 860px) {
+@media all and (max-width: 900px) {
+  #toolbarViewerMiddle {
+    display: table;
+    margin: auto;
+    left: auto;
+    position: inherit;
+    transform: none;
+  }
+  .sidebarMoving .hiddenMediumView,
   .sidebarOpen .hiddenMediumView {
     display: none;
   }
+  .sidebarMoving .visibleMediumView,
   .sidebarOpen .visibleMediumView {
     display: inherit;
   }
 }
 
-@media all and (max-width: 770px) {
+@media all and (max-width: 840px) {
   #sidebarContainer {
     top: 32px;
     z-index: 100;
   }
   .loadingInProgress #sidebarContainer {
     top: 37px;
   }
   #sidebarContent {
@@ -2004,72 +1982,53 @@ html[dir='rtl'] #documentPropertiesOverl
 
   html[dir='ltr'] #outerContainer.sidebarOpen > #mainContainer {
     left: 0px;
   }
   html[dir='rtl'] #outerContainer.sidebarOpen > #mainContainer {
     right: 0px;
   }
 
-  html[dir='ltr'] .outerCenter {
-    float: left;
-    left: 205px;
-  }
-  html[dir='rtl'] .outerCenter {
-    float: right;
-    right: 205px;
-  }
-
   #outerContainer .hiddenLargeView,
   #outerContainer .hiddenMediumView {
     display: inherit;
   }
   #outerContainer .visibleLargeView,
   #outerContainer .visibleMediumView {
     display: none;
   }
 }
 
-@media all and (max-width: 700px) {
+@media all and (max-width: 770px) {
   #outerContainer .hiddenLargeView {
     display: none;
   }
   #outerContainer .visibleLargeView {
     display: inherit;
   }
 }
 
-@media all and (max-width: 660px) {
+@media all and (max-width: 700px) {
   #outerContainer .hiddenMediumView {
     display: none;
   }
   #outerContainer .visibleMediumView {
     display: inherit;
   }
 }
 
-@media all and (max-width: 600px) {
+@media all and (max-width: 640px) {
   .hiddenSmallView {
     display: none;
   }
   .visibleSmallView {
     display: inherit;
   }
-  html[dir='ltr'] #outerContainer.sidebarMoving .outerCenter,
-  html[dir='ltr'] #outerContainer.sidebarOpen .outerCenter,
-  html[dir='ltr'] .outerCenter {
-    left: 156px;
-  }
-  html[dir='rtl'] #outerContainer.sidebarMoving .outerCenter,
-  html[dir='rtl'] #outerContainer.sidebarOpen .outerCenter,
-  html[dir='rtl'] .outerCenter {
-    right: 156px;
-  }
   .toolbarButtonSpacer {
     width: 0;
   }
 }
 
-@media all and (max-width: 510px) {
+@media all and (max-width: 535px) {
   #scaleSelectContainer {
     display: none;
   }
 }
--- a/browser/extensions/pdfjs/content/web/viewer.html
+++ b/browser/extensions/pdfjs/content/web/viewer.html
@@ -189,45 +189,43 @@ See https://github.com/adobe-type-tools/
                 </a>
 
                 <div class="verticalToolbarSeparator hiddenSmallView"></div>
 
                 <button id="secondaryToolbarToggle" class="toolbarButton" title="Tools" tabindex="36" data-l10n-id="tools">
                   <span data-l10n-id="tools_label">Tools</span>
                 </button>
               </div>
-              <div class="outerCenter">
-                <div class="innerCenter" id="toolbarViewerMiddle">
-                  <div class="splitToolbarButton">
-                    <button id="zoomOut" class="toolbarButton zoomOut" title="Zoom Out" tabindex="21" data-l10n-id="zoom_out">
-                      <span data-l10n-id="zoom_out_label">Zoom Out</span>
-                    </button>
-                    <div class="splitToolbarButtonSeparator"></div>
-                    <button id="zoomIn" class="toolbarButton zoomIn" title="Zoom In" tabindex="22" data-l10n-id="zoom_in">
-                      <span data-l10n-id="zoom_in_label">Zoom In</span>
-                     </button>
-                  </div>
-                  <span id="scaleSelectContainer" class="dropdownToolbarButton">
-                    <select id="scaleSelect" title="Zoom" tabindex="23" data-l10n-id="zoom">
-                      <option id="pageAutoOption" title="" value="auto" selected="selected" data-l10n-id="page_scale_auto">Automatic Zoom</option>
-                      <option id="pageActualOption" title="" value="page-actual" data-l10n-id="page_scale_actual">Actual Size</option>
-                      <option id="pageFitOption" title="" value="page-fit" data-l10n-id="page_scale_fit">Fit Page</option>
-                      <option id="pageWidthOption" title="" value="page-width" data-l10n-id="page_scale_width">Full Width</option>
-                      <option id="customScaleOption" title="" value="custom" hidden="true"></option>
-                      <option title="" value="0.5" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 50 }'>50%</option>
-                      <option title="" value="0.75" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 75 }'>75%</option>
-                      <option title="" value="1" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 100 }'>100%</option>
-                      <option title="" value="1.25" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 125 }'>125%</option>
-                      <option title="" value="1.5" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 150 }'>150%</option>
-                      <option title="" value="2" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 200 }'>200%</option>
-                      <option title="" value="3" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 300 }'>300%</option>
-                      <option title="" value="4" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 400 }'>400%</option>
-                    </select>
-                  </span>
+              <div id="toolbarViewerMiddle">
+                <div class="splitToolbarButton">
+                  <button id="zoomOut" class="toolbarButton zoomOut" title="Zoom Out" tabindex="21" data-l10n-id="zoom_out">
+                    <span data-l10n-id="zoom_out_label">Zoom Out</span>
+                  </button>
+                  <div class="splitToolbarButtonSeparator"></div>
+                  <button id="zoomIn" class="toolbarButton zoomIn" title="Zoom In" tabindex="22" data-l10n-id="zoom_in">
+                    <span data-l10n-id="zoom_in_label">Zoom In</span>
+                   </button>
                 </div>
+                <span id="scaleSelectContainer" class="dropdownToolbarButton">
+                  <select id="scaleSelect" title="Zoom" tabindex="23" data-l10n-id="zoom">
+                    <option id="pageAutoOption" title="" value="auto" selected="selected" data-l10n-id="page_scale_auto">Automatic Zoom</option>
+                    <option id="pageActualOption" title="" value="page-actual" data-l10n-id="page_scale_actual">Actual Size</option>
+                    <option id="pageFitOption" title="" value="page-fit" data-l10n-id="page_scale_fit">Fit Page</option>
+                    <option id="pageWidthOption" title="" value="page-width" data-l10n-id="page_scale_width">Full Width</option>
+                    <option id="customScaleOption" title="" value="custom" disabled="disabled" hidden="true"></option>
+                    <option title="" value="0.5" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 50 }'>50%</option>
+                    <option title="" value="0.75" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 75 }'>75%</option>
+                    <option title="" value="1" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 100 }'>100%</option>
+                    <option title="" value="1.25" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 125 }'>125%</option>
+                    <option title="" value="1.5" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 150 }'>150%</option>
+                    <option title="" value="2" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 200 }'>200%</option>
+                    <option title="" value="3" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 300 }'>300%</option>
+                    <option title="" value="4" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 400 }'>400%</option>
+                  </select>
+                </span>
               </div>
             </div>
             <div id="loadingBar">
               <div class="progress">
                 <div class="glimmer">
                 </div>
               </div>
             </div>
--- a/browser/installer/windows/nsis/uninstaller.nsi
+++ b/browser/installer/windows/nsis/uninstaller.nsi
@@ -407,17 +407,17 @@ Section "Uninstall"
   ${EndIf}
   ${If} ${FileExists} "$INSTDIR\install.log"
     Delete /REBOOTOK "$INSTDIR\install.log"
   ${EndIf}
   ${If} ${FileExists} "$INSTDIR\update-settings.ini"
     Delete /REBOOTOK "$INSTDIR\update-settings.ini"
   ${EndIf}
 
-  ; Explictly remove empty webapprt dir in case it exists (bug 757978).
+  ; Explicitly remove empty webapprt dir in case it exists (bug 757978).
   RmDir "$INSTDIR\webapprt\components"
   RmDir "$INSTDIR\webapprt"
 
   ; Remove the installation directory if it is empty
   RmDir "$INSTDIR"
 
   ; If firefox.exe was successfully deleted yet we still need to restart to
   ; remove other files create a dummy firefox.exe.moz-delete to prevent the
--- a/browser/locales/en-US/chrome/browser/aboutTabCrashed.dtd
+++ b/browser/locales/en-US/chrome/browser/aboutTabCrashed.dtd
@@ -1,16 +1,30 @@
 <!-- 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/. -->
 
-<!ENTITY tabCrashed.header "Bad news first: This tab has crashed">
-<!ENTITY tabCrashed.message "Now for the good news: You can just close this tab, restore it or restore all your crashed tabs.">
-<!ENTITY tabCrashed.sendReport "Submit a crash report to help prevent more bad news">
-<!ENTITY tabCrashed.includeURL "Include the address of the page I was on">
-<!ENTITY tabCrashed.commentPlaceholder "Add a comment (comments are publicly visible)">
-<!ENTITY tabCrashed.emailPlaceholder "Enter your email address here">
-<!ENTITY tabCrashed.emailMe "Email me when more information is available">
-<!ENTITY tabCrashed.crashReporter "Mozilla Crash Reporter">
-<!ENTITY tabCrashed.reportSent "Crash report already submitted; thank you for helping make &brandShortName; better!">
 <!ENTITY tabCrashed.closeTab "Close This Tab">
 <!ENTITY tabCrashed.restoreTab "Restore This Tab">
 <!ENTITY tabCrashed.restoreAll "Restore All Crashed Tabs">
+
+<!-- LOCALIZATION NOTE (tabCrashed.header2): "Gah" is an English slang word
+     used to express surprise or frustration (or both at the same time).  We
+     are using it to communicate in an informal way that it is both
+     frustrating that your tab crashed and a surprise that we didn't want to
+     happen. If you have a similar word or short phrase that is not profane or
+     vulgar, use it. If not, feel free to skip the word in your
+     translation. -->
+<!ENTITY tabCrashed.header2 "Gah. Your tab just crashed.">
+<!ENTITY tabCrashed.offerHelp "We can help you!">
+<!ENTITY tabCrashed.single.offerHelpMessage "Choose &tabCrashed.restoreTab; to reload page content.">
+<!ENTITY tabCrashed.multiple.offerHelpMessage "Choose &tabCrashed.restoreTab; or &tabCrashed.restoreAll; to reload page content.">
+<!ENTITY tabCrashed.requestHelp "Will you help us?">
+<!ENTITY tabCrashed.requestHelpMessage "Crash reports help us diagnose problems and make &brandShortName; better.">
+<!ENTITY tabCrashed.requestReport "Report this tab">
+<!ENTITY tabCrashed.sendReport2 "Send a crash report for the tab you are viewing">
+<!ENTITY tabCrashed.commentPlaceholder2 "Optional comments (comments are publicly visible)">
+<!ENTITY tabCrashed.includeURL2 "Include page URL with this crash report">
+<!ENTITY tabCrashed.emailPlaceholder "Enter your email address here">
+<!ENTITY tabCrashed.emailMe "Email me when more information is available">
+<!ENTITY tabCrashed.reportSent "Crash report already submitted; thank you for helping make &brandShortName; better!">
+<!ENTITY tabCrashed.requestAutoSubmit "Request background tabs">
+<!ENTITY tabCrashed.autoSubmit "Update preferences to automatically submit backlogged crash reports (and get fewer messages like this from us in the future)">
\ No newline at end of file
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -387,16 +387,17 @@ These should match what Safari and other
 <!ENTITY customizeMenu.removeFromMenu.label "Remove from Menu">
 <!ENTITY customizeMenu.removeFromMenu.accesskey "R">
 <!ENTITY customizeMenu.addMoreItems.label "Add More Items…">
 <!ENTITY customizeMenu.addMoreItems.accesskey "A">
 
 <!ENTITY openCmd.commandkey           "l">
 <!ENTITY urlbar.placeholder2          "Search or enter address">
 <!ENTITY urlbar.accesskey             "d">
+<!ENTITY urlbar.extension.label       "Extension:">
 <!ENTITY urlbar.switchToTab.label     "Switch to tab:">
 
 <!ENTITY urlbar.searchSuggestionsNotification.question "Would you like to improve your search experience with suggestions?">
 <!ENTITY urlbar.searchSuggestionsNotification.learnMore "Learn more…">
 <!ENTITY urlbar.searchSuggestionsNotification.learnMore.accesskey "l">
 <!ENTITY urlbar.searchSuggestionsNotification.disable "No">
 <!ENTITY urlbar.searchSuggestionsNotification.disable.accesskey "n">
 <!ENTITY urlbar.searchSuggestionsNotification.enable "Yes">
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -736,24 +736,26 @@ decoder.noCodecs.message = To play video, you may need to install Microsoft’s Media Feature Pack.
 decoder.noCodecsVista.message = To play video, you may need to install Microsoft’s Platform Update Supplement for Windows Vista.
 decoder.noCodecsXP.message = To play video, you may need to enable Adobe’s Primetime Content Decryption Module.
 decoder.noCodecsLinux.message = To play video, you may need to install the required video codecs.
 decoder.noHWAcceleration.message = To improve video quality, you may need to install Microsoft’s Media Feature Pack.
 decoder.noHWAccelerationVista.message = To improve video quality, you may need to install Microsoft’s Platform Update Supplement for Windows Vista.
 decoder.noPulseAudio.message = To play audio, you may need to install the required PulseAudio software.
 decoder.unsupportedLibavcodec.message = libavcodec may be vulnerable or is not supported, and should be updated to play video.
 
-# LOCALIZATION NOTE (captivePortal.infoMessage):
-# This string is shown in a notification bar when we detect a captive portal is blocking network access
+# LOCALIZATION NOTE (captivePortal.infoMessage,
+#                    captivePortal.infoMessage2):
+# Shown in a notification bar when we detect a captive portal is blocking network access
 # and requires the user to log in before browsing. %1$S is replaced with brandShortName.
-captivePortal.infoMessage=This network may require you to login to use the internet. %1$S has opened the login page for you.
+captivePortal.infoMessage = This network may require you to login to use the internet. %1$S has opened the login page for you.
+captivePortal.infoMessage2 = This network may require you to login to use the internet.
 # LOCALIZATION NOTE (captivePortal.showLoginPage):
 # The label for a button shown in the info bar in all tabs except the login page tab.
 # The button shows the portal login page tab when clicked.
-captivePortal.showLoginPage=Show Login Page
+captivePortal.showLoginPage = Show Login Page
 
 permissions.remove.tooltip = Clear this permission and ask again
 
 # LOCALIZATION NOTE (aboutDialog.architecture.*):
 # The sixtyFourBit and thirtyTwoBit strings describe the architecture of the
 # current Firefox build: 32-bit or 64-bit. These strings are used in parentheses
 # between the Firefox version and the "What's new" link in the About dialog,
 # e.g.: "48.0.2 (32-bit) <What's new>" or "51.0a1 (2016-09-05) (64-bit)".
--- a/browser/locales/en-US/chrome/browser/tabbrowser.properties
+++ b/browser/locales/en-US/chrome/browser/tabbrowser.properties
@@ -39,11 +39,13 @@ tabs.closeSelectedTab.tooltip=Close tab 
 # %S is the keyboard shortcut for "Mute tab"
 tabs.muteAudio.tooltip=Mute tab (%S)
 # LOCALIZATION NOTE (tabs.unmuteAudio.tooltip):
 # %S is the keyboard shortcut for "Unmute tab"
 tabs.unmuteAudio.tooltip=Unmute tab (%S)
 tabs.muteAudio.background.tooltip=Mute tab
 tabs.unmuteAudio.background.tooltip=Unmute tab
 
+tabs.unblockAudio.tooltip=Play tab
+
 # LOCALIZATION NOTE (tabs.allowTabFocusByPromptForSite):
 # %S is the hostname of the site where dialogs are allowed to switch tabs
 tabs.allowTabFocusByPromptForSite=Allow dialogs from %S to take you to their tab
--- a/browser/locales/en-US/chrome/overrides/netError.dtd
+++ b/browser/locales/en-US/chrome/overrides/netError.dtd
@@ -46,16 +46,23 @@
 </ul>
 ">
 
 <!ENTITY generic.title "Oops.">
 <!ENTITY generic.longDesc "
 <p>&brandShortName; can’t load this page for some reason.</p>
 ">
 
+<!ENTITY captivePortal.title "Login to network">
+<!ENTITY captivePortal.longDesc "
+<p>This network may require you to login to access the internet.</p>
+">
+
+<!ENTITY openPortalLoginPage.label "Open Login Page">
+
 <!ENTITY malformedURI.title "The address isn’t valid">
 <!ENTITY malformedURI.longDesc "
 <ul>
   <li>Web addresses are usually written like
     <strong>http://www.example.com/</strong></li>
   <li>Make sure that you’re using forward slashes (i.e.
     <strong>/</strong>).</li>
 </ul>
--- a/browser/modules/ContentCrashHandlers.jsm
+++ b/browser/modules/ContentCrashHandlers.jsm
@@ -330,16 +330,22 @@ this.TabCrashHandler = {
    *        even if they are empty.
    */
   maybeSendCrashReport(message) {
     if (!AppConstants.MOZ_CRASHREPORTER)
       return;
 
     let browser = message.target.browser;
 
+    if (message.data.autoSubmit) {
+      // The user has opted in to autosubmitted backlogged
+      // crash reports in the future.
+      UnsubmittedCrashHandler.autoSubmit = true;
+    }
+
     let childID = this.browserMap.get(browser.permanentKey);
     let dumpID = this.childMap.get(childID);
     if (!dumpID)
       return
 
     if (!message.data.sendReport) {
       Services.telemetry.getHistogramById("FX_CONTENT_CRASH_NOT_SUBMITTED").add(1);
       this.prefs.setBoolPref("sendReport", false);
@@ -444,21 +450,31 @@ this.TabCrashHandler = {
     let dumpID = this.getDumpID(browser);
     if (!dumpID) {
       message.target.sendAsyncMessage("SetCrashReportAvailable", {
         hasReport: false,
       });
       return;
     }
 
+    let requestAutoSubmit = !UnsubmittedCrashHandler.autoSubmit;
+    let requestEmail = this.prefs.getBoolPref("requestEmail");
     let sendReport = this.prefs.getBoolPref("sendReport");
     let includeURL = this.prefs.getBoolPref("includeURL");
     let emailMe = this.prefs.getBoolPref("emailMe");
 
-    let data = { hasReport: true, sendReport, includeURL, emailMe };
+    let data = {
+      hasReport: true,
+      sendReport,
+      includeURL,
+      emailMe,
+      requestAutoSubmit,
+      requestEmail,
+    };
+
     if (emailMe) {
       data.email = this.prefs.getCharPref("email", "");
     }
 
     // Make sure to only count once even if there are multiple windows
     // that will all show about:tabcrashed.
     if (this._crashedTabCount == 1) {
       Services.telemetry.getHistogramById("FX_CONTENT_CRASH_PRESENTED").add(1);
--- a/browser/modules/test/browser_UsageTelemetry_urlbar.js
+++ b/browser/modules/test/browser_UsageTelemetry_urlbar.js
@@ -1,16 +1,17 @@
 "use strict";
 
 const SCALAR_URLBAR = "browser.engagement.navigation.urlbar";
 
 // The preference to enable suggestions in the urlbar.
 const SUGGEST_URLBAR_PREF = "browser.urlbar.suggest.searches";
 // The name of the search engine used to generate suggestions.
 const SUGGESTION_ENGINE_NAME = "browser_UsageTelemetry usageTelemetrySearchSuggestions.xml";
+const ONEOFF_URLBAR_PREF = "browser.urlbar.oneOffSearches";
 
 let searchInAwesomebar = Task.async(function* (inputText, win=window) {
   yield new Promise(r => waitForFocus(r, win));
   // Write the search query in the urlbar.
   win.gURLBar.focus();
   win.gURLBar.value = inputText;
   win.gURLBar.controller.startSearch(inputText);
   // Wait for the popup to show.
@@ -50,21 +51,25 @@ add_task(function* setup() {
   Services.search.currentEngine = engine;
 
   // And the first one-off engine.
   Services.search.moveEngine(engine, 0);
 
   // Enable search suggestions in the urlbar.
   Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, true);
 
+  // Enable the urlbar one-off buttons.
+  Services.prefs.setBoolPref(ONEOFF_URLBAR_PREF, true);
+
   // Make sure to restore the engine once we're done.
   registerCleanupFunction(function* () {
     Services.search.currentEngine = originalEngine;
     Services.search.removeEngine(engine);
     Services.prefs.clearUserPref(SUGGEST_URLBAR_PREF, true);
+    Services.prefs.clearUserPref(ONEOFF_URLBAR_PREF);
   });
 });
 
 add_task(function* test_simpleQuery() {
   // Let's reset the counts.
   Services.telemetry.clearScalars();
 
   let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
--- a/browser/modules/test/unit/social/head.js
+++ b/browser/modules/test/unit/social/head.js
@@ -59,22 +59,22 @@ function initApp() {
 
 function setManifestPref(manifest) {
   let string = Cc["@mozilla.org/supports-string;1"].
                createInstance(Ci.nsISupportsString);
   string.data = JSON.stringify(manifest);
   Services.prefs.setComplexValue("social.manifest." + manifest.origin, Ci.nsISupportsString, string);
 }
 
-function do_wait_observer(topic, cb) {
+function do_wait_observer(obsTopic, cb) {
   function observer(subject, topic, data) {
     Services.obs.removeObserver(observer, topic);
     cb();
   }
-  Services.obs.addObserver(observer, topic, false);
+  Services.obs.addObserver(observer, obsTopic, false);
 }
 
 function do_add_providers(cb) {
   // run only after social is already initialized
   SocialService.addProvider(manifests[0], function() {
     do_wait_observer("social:providers-changed", function() {
       do_check_eq(Social.providers.length, 2, "2 providers installed");
       do_execute_soon(cb);
--- a/browser/modules/test/xpcshell/test_DirectoryLinksProvider.js
+++ b/browser/modules/test/xpcshell/test_DirectoryLinksProvider.js
@@ -242,17 +242,17 @@ function run_test() {
   });
 }
 
 
 function setTimeout(fun, timeout) {
   let timer = Components.classes["@mozilla.org/timer;1"]
                         .createInstance(Components.interfaces.nsITimer);
   var event = {
-    notify: function (timer) {
+    notify: function () {
       fun();
     }
   };
   timer.initWithCallback(event, timeout,
                          Components.interfaces.nsITimer.TYPE_ONE_SHOT);
   return timer;
 }
 
@@ -1657,18 +1657,18 @@ add_task(function* test_inadjecentSites(
 
   // loading inadjacent sites list function
   function setInadjacentSites(sites) {
     let badSiteB64 = [];
     sites.forEach(site => {
       badSiteB64.push(DirectoryLinksProvider._generateHash(site));
     });
     let theList = {"domains": badSiteB64};
-    let dataURI = 'data:application/json,' + JSON.stringify(theList);
-    DirectoryLinksProvider._inadjacentSitesUrl = dataURI;
+    let uri = 'data:application/json,' + JSON.stringify(theList);
+    DirectoryLinksProvider._inadjacentSitesUrl = uri;
     return DirectoryLinksProvider._loadInadjacentSites();
   }
 
   // setup gLinks loader
   let gLinks = NewTabUtils.links;
   gLinks.addProvider(DirectoryLinksProvider);
 
   function updateNewTabCache() {
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -358,27 +358,16 @@ function prompt(aBrowser, aRequest) {
 
   let options = {
     eventCallback: function(aTopic, aNewBrowser) {
       if (aTopic == "swapping")
         return true;
 
       let chromeDoc = this.browser.ownerDocument;
 
-      if (aTopic == "shown") {
-        let popupId = "Devices";
-        if (requestTypes.length == 1 && (requestTypes[0] == "Microphone" ||
-                                         requestTypes[0] == "AudioCapture"))
-          popupId = "Microphone";
-        if (requestTypes.includes("Screen"))
-          popupId = "Screen";
-        chromeDoc.getElementById("webRTC-shareDevices-notification")
-                 .setAttribute("popupid", "webRTC-share" + popupId);
-      }
-
       // Clean-up video streams of screensharing previews.
       if ((aTopic == "dismissed" || aTopic == "removed") &&
           requestTypes.includes("Screen")) {
         let video = chromeDoc.getElementById("webRTC-previewVideo");
         video.deviceId = undefined;
         if (video.stream) {
           video.stream.getTracks().forEach(t => t.stop());
           video.stream = null;
@@ -666,21 +655,29 @@ function prompt(aBrowser, aRequest) {
         mm.sendAsyncMessage("webrtc:Allow", {callID: aRequest.callID,
                                              windowID: aRequest.windowID,
                                              devices: allowedDevices});
       };
       return false;
     }
   };
 
-  let anchorId = "webRTC-shareDevices-notification-icon";
-  if (requestTypes.length == 1 && requestTypes[0] == "Microphone")
-    anchorId = "webRTC-shareMicrophone-notification-icon";
+  let iconType = "Devices";
+  if (requestTypes.length == 1 && (requestTypes[0] == "Microphone" ||
+                                   requestTypes[0] == "AudioCapture"))
+    iconType = "Microphone";
   if (requestTypes.includes("Screen"))
-    anchorId = "webRTC-shareScreen-notification-icon";
+    iconType = "Screen";
+  let anchorId = "webRTC-share" + iconType + "-notification-icon";
+
+  let iconClass = iconType.toLowerCase();
+  if (iconClass == "devices")
+    iconClass = "camera";
+  options.popupIconClass = iconClass + "-icon";
+
   notification =
     chromeWin.PopupNotifications.show(aBrowser, "webRTC-shareDevices", message,
                                       anchorId, mainAction, secondaryActions,
                                       options);
   notification.callID = aRequest.callID;
 }
 
 function removePrompt(aBrowser, aCallId) {
--- a/browser/themes/shared/aboutTabCrashed.css
+++ b/browser/themes/shared/aboutTabCrashed.css
@@ -1,42 +1,79 @@
 /* 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-size: 1.25rem;
+}
+
 .title {
   background-image: url("chrome://browser/skin/tab-crashed.svg");
 }
 
+.title > h1,
+.offers {
+  margin-left: 14px;
+}
+
+.title > h1 {
+  /**
+   * Add commentary?
+   */
+  padding-right: 14px;
+}
+
+.container {
+  width: 45%;
+}
+
 #reportSent {
   font-weight: bold;
 }
 
-#crash-reporter-container {
-  width: 80%;
+#reportBox {
   background-color: var(--in-content-box-background-hover);
   margin: 24px 0;
   padding: 14px;
   border: 1px solid var(--in-content-box-border-color);
   border-radius: 2px;
 }
 
+#reportBox > h2:first-child {
+  margin-top: 0;
+}
+
 #crash-reporter-title {
   font-weight: bold;
   margin: 0 0 14px 0;
 }
 
 input[type="text"],
 textarea {
   width: 100%;
   box-sizing: border-box;
   resize: none;
 }
 
+input[type="text"],
+input[type="checkbox"] {
+  -moz-margin-start: 0px;
+}
+
 #options {
   list-style: none;
   margin-inline-start: 0;
 }
 
-input[type="text"],
-#options > li {
-  margin: 14px 0 0 0;
+#options > li,
+#email {
+  margin-top: 14px;
 }
+
+.checkbox-with-label {
+  display: flex;
+}
+
+.checkbox-with-label > label {
+  margin-top: auto;
+  margin-bottom: auto;
+}
\ No newline at end of file
--- a/browser/themes/shared/identity-block/identity-block.inc.css
+++ b/browser/themes/shared/identity-block/identity-block.inc.css
@@ -74,16 +74,23 @@
 
 #urlbar[actiontype="searchengine"] > #identity-box > #identity-icon {
   -moz-image-region: inherit;
   list-style-image: url(chrome://global/skin/icons/autocomplete-search.svg#search-icon);
   width: 16px;
   height: 16px;
 }
 
+#urlbar[actiontype="extension"] > #identity-box > #identity-icon {
+  -moz-image-region: inherit;
+  list-style-image: url(chrome://browser/skin/addons/addon-install-anchor.svg);
+  width: 16px;
+  height: 16px;
+}
+
 /* SHARING ICON */
 
 #sharing-icon {
   width: 16px;
   height: 16px;
   margin-inline-start: -16px;
   position: relative;
   display: none;
--- a/browser/themes/shared/notification-icons.inc.css
+++ b/browser/themes/shared/notification-icons.inc.css
@@ -108,18 +108,17 @@
 .login-icon {
   list-style-image: url(chrome://browser/skin/notification-icons.svg#login);
 }
 
 .popup-notification-icon[popupid="password"] {
   list-style-image: url(chrome://browser/skin/notification-icons.svg#login-detailed);
 }
 
-.camera-icon,
-.popup-notification-icon[popupid="webRTC-shareDevices"] {
+.camera-icon {
   list-style-image: url(chrome://browser/skin/notification-icons.svg#camera);
 }
 
 .camera-icon.in-use {
   list-style-image: url(chrome://browser/skin/notification-icons.svg#camera-sharing);
 }
 
 .camera-icon.blocked-permission-icon {
@@ -133,21 +132,20 @@
 .microphone-icon.in-use {
   list-style-image: url(chrome://browser/skin/notification-icons.svg#microphone-sharing);
 }
 
 .microphone-icon.blocked-permission-icon {
   list-style-image: url(chrome://browser/skin/notification-icons.svg#microphone-blocked);
 }
 
-.popup-notification-icon[popupid="webRTC-shareMicrophone"] {
+.popup-notification-icon.microphone-icon {
   list-style-image: url(chrome://browser/skin/notification-icons.svg#microphone-detailed);
 }
 
-.popup-notification-icon[popupid="webRTC-shareScreen"],
 .screen-icon {
   list-style-image: url(chrome://browser/skin/notification-icons.svg#screen);
 }
 
 .screen-icon.in-use {
   list-style-image: url(chrome://browser/skin/notification-icons.svg#screen-sharing);
 }
 
--- a/browser/themes/shared/tabbrowser/tab-audio-small.svg
+++ b/browser/themes/shared/tabbrowser/tab-audio-small.svg
@@ -36,9 +36,23 @@
   <g id="tab-audio-white" class="icon white">
     <path class="outline" d="M12.4,3.6l-1-0.6l-0.9,2.5H10V1.8c0-0.4-0.5-0.7-0.9-0.4L5.6,5H4C2.9,5,2,5.9,2,7v2c0,1.1,0.9,2,2,2h1.6l3.6,3.6 c0.3,0.3,0.9,0.1,0.9-0.4v-3.7h0.5l0.9,2.5l1-0.6C14,11.5,15,9.8,15,8S14,4.5,12.4,3.6z M9,13l-3-3H4c-0.6,0-1-0.4-1-1V7 c0-0.6,0.4-1,1-1h2l3-3V13z M10,9.5v-3c0.8,0,1.5,0.7,1.5,1.5S10.8,9.5,10,9.5z M11.9,11.5l-0.4-0.9C12.4,10,13,9.1,13,8 s-0.6-2-1.4-2.5l0.3-1C13.2,5.2,14,6.5,14,8S13.2,10.8,11.9,11.5z"/>
     <path d="M4,6C3.4,6,3,6.4,3,7v2c0,0.6,0.4,1,1,1h2l3,3V3L6,6H4z M10,6.5v3c0.8,0,1.5-0.7,1.5-1.5S10.8,6.5,10,6.5z M11.9,4.5 l-0.4,0.9C12.4,6,13,6.9,13,8s-0.6,2-1.4,2.5l0.4,0.9c1.2-0.7,2.1-2,2.1-3.5S13.2,5.2,11.9,4.5z"/>
   </g>
   <g id="tab-audio-white-muted" class="icon white">
     <path class="outline" d="M5.6,5H4C2.9,5,2,5.9,2,7v2c0,0.7,0.3,1.3,0.9,1.7l-1.8,1.8l2.5,2.5l3-3l2.6,2.6c0.3,0.3,0.9,0.1,0.9-0.4V8.5l3.9-3.9 l-2.5-2.5L10,3.5V1.8c0-0.4-0.5-0.7-0.9-0.4L5.6,5z"/>
     <path d="M11.5,3.5L9,5.9V3L6,6H4C3.4,6,3,6.4,3,7v2c0,0.6,0.4,1,1,1h0.9l-2.5,2.5l1.1,1.1l9-9L11.5,3.5z M9,13V9.7l-1.7,1.7L9,13z"/>
   </g>
+
+  <g id="tab-audio-blocked" class="icon">
+    <path class="outline" d="M8,1.2C4.3,1.2,1.2,4.3,1.2,8s3.1,6.8,6.8,6.8s6.8-3.1,6.8-6.8S11.7,1.2,8,1.2z M8,11.9
+      c-2.1,0-3.9-1.7-3.9-3.9c0-2.1,1.7-3.9,3.9-3.9s3.9,1.7,3.9,3.9C11.9,10.1,10.1,11.9,8,11.9z M11.1,7.3L6.6,4.6L5.4,3.9v1.4v5.3V12
+      l1.2-0.7L11,8.6L12.2,8L11.1,7.3z"/>
+    <path d="M8,2C4.7,2,2,4.7,2,8s2.7,6,6,6s6-2.7,6-6S11.3,2,8,2z M8,12.7c-2.6,0-4.7-2.1-4.7-4.7
+      S5.4,3.3,8,3.3s4.7,2.1,4.7,4.7S10.6,12.7,8,12.7z M10.7,8L6.2,5.3v5.4L10.7,8z"/>
+  </g>
+  <g id="tab-audio-white-blocked" class="icon">
+    <path class="outline" d="M8,0c3.3,0,6.4,2.2,7.5,5.3c1.1,3.1,0.1,6.7-2.5,8.9c-2.6,2.1-6.3,2.4-9.2,0.7
+      C1,13.1-0.5,9.8,0.1,6.5C0.9,2.8,4.2,0,8,0z"/>
+    <path d="M8,2C4.7,2,2,4.7,2,8s2.7,6,6,6s6-2.7,6-6S11.3,2,8,2z M8,12.7c-2.6,0-4.7-2.1-4.7-4.7
+      S5.4,3.3,8,3.3s4.7,2.1,4.7,4.7S10.6,12.7,8,12.7z M10.7,8L6.2,5.3v5.4L10.7,8z"/>
+  </g>
 </svg>
--- a/browser/themes/shared/tabbrowser/tab-audio.svg
+++ b/browser/themes/shared/tabbrowser/tab-audio.svg
@@ -7,9 +7,12 @@
     path:not(:target) {
       display: none;
     }
   </style>
 
   <path id="tab-audio" d="M4,5C2.9,5,2,5.9,2,7v2c0,1.1,0.9,2,2,2h1.2L9,14V2L5.2,5H4z M11,8c0-0.6-0.4-1-1-1v2C10.6,9,11,8.6,11,8z M13,8 c0-1.4-1-2.6-2.3-2.9L10.4,6C11.3,6.2,12,7,12,8s-0.7,1.8-1.6,2l0.4,0.9C12,10.6,13,9.4,13,8z M11.4,3.2l-0.4,0.9 C12.8,4.6,14,6.2,14,8s-1.2,3.4-2.9,3.8l0.4,0.9C13.5,12.2,15,10.3,15,8S13.5,3.8,11.4,3.2z"/>
 
   <path id="tab-audio-muted" d="M12.5,3.4L9,6.3V2L5.2,5H4C2.9,5,2,5.9,2,7v2c0,0.9,0.6,1.6,1.4,1.9l-1.9,1.5l1,1.2l11-9L12.5,3.4z M9,14v-4l-2.5,2L9,14z"/>
+
+  <path id="tab-audio-blocked" d="M8,0C3.6,0,0,3.6,0,8s3.6,8,8,8s8-3.6,8-8S12.4,0,8,0z M5.6,11.6l6-3.6l-6-3.6V11.6z M8,14.2
+  c-3.4,0-6.2-2.8-6.2-6.2S4.6,1.8,8,1.8s6.2,2.8,6.2,6.2S11.4,14.2,8,14.2z"/>
 </svg>
--- a/browser/themes/shared/tabs.inc.css
+++ b/browser/themes/shared/tabs.inc.css
@@ -134,43 +134,54 @@
   position: relative;
 }
 
 .tab-icon-overlay[crashed] {
   list-style-image: url("chrome://browser/skin/tabbrowser/crashed.svg");
 }
 
 .tab-icon-overlay[soundplaying],
-.tab-icon-overlay[muted]:not([crashed]) {
+.tab-icon-overlay[muted]:not([crashed]),
+.tab-icon-overlay[blocked]:not([crashed]) {
   border-radius: 10px;
 }
 
 .tab-icon-overlay[soundplaying]:hover,
-.tab-icon-overlay[muted]:not([crashed]):hover {
+.tab-icon-overlay[muted]:not([crashed]):hover,
+.tab-icon-overlay[blocked]:not([crashed]):hover {
   background-color: white;
 }
 
 .tab-icon-overlay[soundplaying] {
   list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio");
 }
 
 .tab-icon-overlay[muted]:not([crashed]) {
   list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-muted");
 }
 
+.tab-icon-overlay[blocked]:not([crashed]) {
+  list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-blocked");
+}
+
 #TabsToolbar[brighttext] .tab-icon-overlay[soundplaying]:not([selected]):not(:hover),
 .tab-icon-overlay[soundplaying][selected]:-moz-lwtheme-brighttext:not(:hover) {
   list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-white");
 }
 
 #TabsToolbar[brighttext] .tab-icon-overlay[muted]:not([crashed]):not([selected]):not(:hover),
 .tab-icon-overlay[muted][selected]:-moz-lwtheme-brighttext:not(:hover) {
   list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-white-muted");
 }
 
+#TabsToolbar[brighttext] .tab-icon-overlay[blocked]:not([crashed]):not([selected]):not(:hover),
+.tab-icon-overlay[blocked][selected]:-moz-lwtheme-brighttext:not(:hover) {
+  list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-white-blocked");
+}
+
 .tab-throbber[busy] {
   list-style-image: url("chrome://browser/skin/tabbrowser/connecting.png");
 }
 
 .tab-throbber[progress] {
   list-style-image: url("chrome://global/skin/icons/loading.png");
 }
 
@@ -188,38 +199,46 @@
 .tab-icon-sound {
   margin-inline-start: 4px;
   width: 16px;
   height: 16px;
   padding: 0;
 }
 
 .tab-icon-sound[soundplaying],
-.tab-icon-sound[muted] {
+.tab-icon-sound[muted],
+.tab-icon-sound[blocked] {
   list-style-image: url(chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio);
   filter: url(chrome://browser/skin/filters.svg#fill);
   fill: currentColor;
 }
 
 .tab-icon-sound[muted] {
   list-style-image: url(chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio-muted);
 }
 
+.tab-icon-sound[blocked] {
+  list-style-image: url(chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio-blocked);
+}
+
 .tab-icon-sound:-moz-lwtheme-darktext[soundplaying],
-.tab-icon-sound:-moz-lwtheme-darktext[muted] {
+.tab-icon-sound:-moz-lwtheme-darktext[muted],
+.tab-icon-sound:-moz-lwtheme-darktext[blocked] {
   filter: url(chrome://browser/skin/filters.svg#fill) drop-shadow(1px 1px 1px white);
 }
 
 .tab-icon-sound:-moz-lwtheme-brighttext[soundplaying],
-.tab-icon-sound:-moz-lwtheme-brighttext[muted] {
+.tab-icon-sound:-moz-lwtheme-brighttext[muted],
+.tab-icon-sound:-moz-lwtheme-brighttext[blocked] {
   filter: url(chrome://browser/skin/filters.svg#fill) drop-shadow(1px 1px 1px black);
 }
 
 .tab-icon-sound[soundplaying]:not(:hover),
-.tab-icon-sound[muted]:not(:hover) {
+.tab-icon-sound[muted]:not(:hover),
+.tab-icon-sound[blocked]:not(:hover) {
   opacity: .8;
 }
 
 .tab-icon-sound[soundplaying-scheduledremoval]:not(:hover),
 .tab-icon-overlay[soundplaying-scheduledremoval]:not(:hover) {
   transition: opacity .3s linear var(--soundplaying-removal-delay);
   opacity: 0;
 }
@@ -402,16 +421,17 @@
 .tabbrowser-tab {
   pointer-events: none;
 }
 
 .tab-background-middle,
 .tabs-newtab-button,
 .tab-icon-overlay[soundplaying],
 .tab-icon-overlay[muted]:not([crashed]),
+.tab-icon-overlay[blocked]:not([crashed]),
 .tab-icon-sound,
 .tab-close-button {
   pointer-events: auto;
 }
 
 /* Pinned tabs */
 
 /* Pinned tab separators need position: absolute when positioned (during overflow). */
@@ -525,17 +545,22 @@
 /* All tabs menupopup */
 
 .alltabs-item[tabIsVisible] {
   /* box-shadow instead of background-color to work around native styling */
   box-shadow: inset -5px 0 ThreeDShadow;
 }
 
 .alltabs-endimage[soundplaying],
-.alltabs-endimage[muted] {
+.alltabs-endimage[muted],
+.alltabs-endimage[blocked] {
   list-style-image: url(chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio);
   filter: url(chrome://browser/skin/filters.svg#fill);
   fill: currentColor;
 }
 
 .alltabs-endimage[muted] {
   list-style-image: url(chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio-muted);
 }
+
+.alltabs-endimage[blocked] {
+  list-style-image: url(chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio-blocked);
+}
--- a/build/autoconf/sanitize.m4
+++ b/build/autoconf/sanitize.m4
@@ -21,16 +21,21 @@ if test -n "$MOZ_ASAN"; then
           MOZ_CLANG_RT_ASAN_LIB=clang_rt.asan_dynamic-i386.dll
         fi
         # We use MOZ_PATH_PROG in order to get a Windows style path.
         MOZ_PATH_PROG(MOZ_CLANG_RT_ASAN_LIB_PATH, $MOZ_CLANG_RT_ASAN_LIB)
         if test -z "$MOZ_CLANG_RT_ASAN_LIB_PATH"; then
             AC_MSG_ERROR([Couldn't find $MOZ_CLANG_RT_ASAN_LIB.  It should be available in the same location as clang-cl.])
         fi
         AC_SUBST(MOZ_CLANG_RT_ASAN_LIB_PATH)
+        # Suppressing errors in recompiled code.
+        if test "$OS_ARCH" = "WINNT"; then
+            CFLAGS="-fsanitize-blacklist=$_topsrcdir/build/sanitizers/asan_blacklist_win.txt $CFLAGS"
+            CXXFLAGS="-fsanitize-blacklist=$_topsrcdir/build/sanitizers/asan_blacklist_win.txt $CXXFLAGS"
+        fi
     fi
     CFLAGS="-fsanitize=address $CFLAGS"
     CXXFLAGS="-fsanitize=address $CXXFLAGS"
     if test -z "$CLANG_CL"; then
         LDFLAGS="-fsanitize=address $LDFLAGS"
     fi
     AC_DEFINE(MOZ_ASAN)
     MOZ_PATH_PROG(LLVM_SYMBOLIZER, llvm-symbolizer)
--- a/build/docs/rust.rst
+++ b/build/docs/rust.rst
@@ -18,16 +18,17 @@ into Firefox.
    so Rust code cannot currently be used for required components.
 
 
 Linking Rust Crates into libxul
 ===============================
 
 Rust crates that you want to link into libxul should be listed in the
 ``dependencies`` section of `toolkit/library/rust/shared/Cargo.toml <https://dxr.mozilla.org/mozilla-central/source/toolkit/library/rust/shared/Cargo.toml>`_.
+You'll also need to add an ``extern crate`` reference to `toolkit/library/rust/shared/lib.rs <https://dxr.mozilla.org/mozilla-central/source/toolkit/library/rust/shared/lib.rs>`_.
 This ensures that the Rust code will be linked properly into libxul as well
 as the copy of libxul used for gtests.
 
 Linking Rust Crates into something else
 =======================================
 
 There currently is not any Rust code being linked into binaries other than
 libxul. If you would like to do so, you'll need to create a directory with
new file mode 100644
--- /dev/null
+++ b/build/sanitizers/asan_blacklist_win.txt
@@ -0,0 +1,26 @@
+# This is originally copied from Chromium tools/memory/asan/blacklist_win.txt.
+# The rules in this file are only applied at compile time. If you can modify the
+# source in question, consider function attributes to disable instrumentation.
+
+# Bug 1200740 - ASan crash due to child process function interceptions
+# Sandbox executes some of its code before the ASan RTL gets initialized and
+# maps shadow memory.  As a result, instrmented code tries to access unavailable
+# shadow memory and faults.
+fun:*TargetNtSetInformationThread@20
+fun:*TargetNtOpenThreadToken@20
+fun:*TargetNtOpenThreadTokenEx@24
+fun:*TargetNtMapViewOfSection@44
+fun:*AutoProtectMemory*sandbox*
+fun:*EatResolverThunk*sandbox*
+fun:*InterceptionAgent*sandbox*
+fun:*ResolverThunk*sandbox*
+fun:*Target*SandboxFactory*sandbox*
+fun:*ProcessState*sandbox*
+src:*pe_image.h
+src:*pe_image.cc
+src:*resolver_32.cc
+src:*filesystem_interception.cc
+src:*process_thread_interception.cc
+src:*registry_interception.cc
+src:*sandbox_nt_util.cc
+src:*sync_interception.cc
--- a/build/valgrind/mach_commands.py
+++ b/build/valgrind/mach_commands.py
@@ -108,16 +108,19 @@ class MachCommands(MachCommandBase):
                 '--vex-iropt-register-updates=allregs-at-mem-access',
                 '--gen-suppressions=all',
                 '--num-callers=36',
                 '--leak-check=full',
                 '--show-possibly-lost=no',
                 '--track-origins=yes',
                 '--trace-children=yes',
                 '-v',  # Enable verbosity to get the list of used suppressions
+                # Avoid excessive delays in the presence of spinlocks.
+                # See bug 1309851.
+                '--fair-sched=yes',
             ]
 
             for s in suppressions:
                 valgrind_args.append('--suppressions=' + s)
 
             supps_dir = os.path.join(build_dir, 'valgrind')
             supps_file1 = os.path.join(supps_dir, 'cross-architecture.sup')
             valgrind_args.append('--suppressions=' + supps_file1)
--- a/caps/BasePrincipal.cpp
+++ b/caps/BasePrincipal.cpp
@@ -319,16 +319,17 @@ OriginAttributes::SetFromGenericAttribut
   mAppId = aAttrs.mAppId;
   mInIsolatedMozBrowser = aAttrs.mInIsolatedMozBrowser;
   mAddonId = aAttrs.mAddonId;
   mUserContextId = aAttrs.mUserContextId;
   mPrivateBrowsingId = aAttrs.mPrivateBrowsingId;
   mFirstPartyDomain = aAttrs.mFirstPartyDomain;
 }
 
+/* static */
 bool
 OriginAttributes::IsFirstPartyEnabled()
 {
   // Cache the privacy.firstparty.isolate pref.
   static bool sFirstPartyIsolation = false;
   static bool sCachedFirstPartyPref = false;
   if (!sCachedFirstPartyPref) {
     sCachedFirstPartyPref = true;
--- a/caps/BasePrincipal.h
+++ b/caps/BasePrincipal.h
@@ -56,23 +56,23 @@ public:
                           nsACString& aOriginNoSuffix);
 
   // Helper function to match mIsPrivateBrowsing to existing private browsing
   // flags. Once all other flags are removed, this can be removed too.
   void SyncAttributesWithPrivateBrowsing(bool aInPrivateBrowsing);
 
   void SetFromGenericAttributes(const GenericOriginAttributes& aAttrs);
 
+  // check if "privacy.firstparty.isolate" is enabled.
+  static bool IsFirstPartyEnabled();
+
 protected:
   OriginAttributes() {}
   explicit OriginAttributes(const OriginAttributesDictionary& aOther)
     : OriginAttributesDictionary(aOther) {}
-
-  // check if "privacy.firstparty.isolate" is enabled.
-  bool IsFirstPartyEnabled();
 };
 
 class PrincipalOriginAttributes;
 class DocShellOriginAttributes;
 class NeckoOriginAttributes;
 
 // Various classes in Gecko contain OriginAttributes members, and those
 // OriginAttributes get propagated to other classes according to certain rules.
--- a/caps/nsScriptSecurityManager.cpp
+++ b/caps/nsScriptSecurityManager.cpp
@@ -798,25 +798,37 @@ nsScriptSecurityManager::CheckLoadURIWit
         // exception for foo: linking to view-source:foo for reftests...
         return NS_OK;
     }
 
     // If we get here, check all the schemes can link to each other, from the top down:
     nsCaseInsensitiveCStringComparator stringComparator;
     nsCOMPtr<nsIURI> currentURI = sourceURI;
     nsCOMPtr<nsIURI> currentOtherURI = aTargetURI;
+
+    bool denySameSchemeLinks = false;
+    rv = NS_URIChainHasFlags(aTargetURI, nsIProtocolHandler::URI_SCHEME_NOT_SELF_LINKABLE,
+                             &denySameSchemeLinks);
+    if (NS_FAILED(rv)) return rv;
+
     while (currentURI && currentOtherURI) {
         nsAutoCString scheme, otherScheme;
         currentURI->GetScheme(scheme);
         currentOtherURI->GetScheme(otherScheme);
 
-        // If schemes are not equal, check if the URI flags of the current
-        // target URI allow the current source URI to link to it.
+        // If schemes are not equal, or they're equal but the target URI
+        // is different from the source URI and doesn't always allow linking
+        // from the same scheme, check if the URI flags of the current target
+        // URI allow the current source URI to link to it.
         // The policy is specified by the protocol flags on both URIs.
-        if (!scheme.Equals(otherScheme, stringComparator)) {
+        bool equalExceptRef = false;
+        if (!scheme.Equals(otherScheme, stringComparator) ||
+            (denySameSchemeLinks &&
+             (!NS_SUCCEEDED(currentURI->EqualsExceptRef(currentOtherURI, &equalExceptRef)) ||
+              !equalExceptRef))) {
             return CheckLoadURIFlags(currentURI, currentOtherURI,
                                      sourceBaseURI, targetBaseURI, aFlags);
         }
         // Otherwise... check if we can nest another level:
         nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(currentURI);
         nsCOMPtr<nsINestedURI> nestedOtherURI = do_QueryInterface(currentOtherURI);
 
         // If schemes match and neither URI is nested further, we're OK.
--- a/config/milestone.txt
+++ b/config/milestone.txt
@@ -5,9 +5,9 @@
 #    x.x.x.x
 #    x.x.x+
 #
 # Referenced by milestone.py.
 # Hopefully I'll be able to automate replacement of *all*
 # hardcoded milestones in the tree from these two files.
 #--------------------------------------------------------
 
-52.0a1
+53.0a1
--- a/devtools/.eslintrc.js
+++ b/devtools/.eslintrc.js
@@ -32,38 +32,38 @@ module.exports = {
     "WebSocket": true,
     "XMLHttpRequest": true,
   },
   "rules": {
     // These are the rules that have been configured so far to match the
     // devtools coding style.
 
     // Rules from the mozilla plugin
-    "mozilla/no-aArgs": 1,
-    "mozilla/no-cpows-in-tests": 2,
-    "mozilla/no-single-arg-cu-import": 2,
+    "mozilla/no-aArgs": "warn",
+    "mozilla/no-cpows-in-tests": "error",
+    "mozilla/no-single-arg-cu-import": "error",
     // See bug 1224289.
-    "mozilla/reject-importGlobalProperties": 2,
+    "mozilla/reject-importGlobalProperties": "error",
     // devtools/shared/platform is special; see the README.md in that
     // directory for details.  We reject requires using explicit
     // subdirectories of this directory.
-    "mozilla/reject-some-requires": [2, "^devtools/shared/platform/(chome|content)/"],
-    "mozilla/var-only-at-top-level": 1,
+    "mozilla/reject-some-requires": ["error", "^devtools/shared/platform/(chome|content)/"],
+    "mozilla/var-only-at-top-level": "warn",
 
     // Rules from the React plugin
-    "react/display-name": 2,
-    "react/no-danger": 2,
-    "react/no-did-mount-set-state": 2,
-    "react/no-did-update-set-state": 2,
-    "react/no-direct-mutation-state": 2,
-    "react/no-unknown-property": 2,
-    "react/prefer-es6-class": [1, "never"],
+    "react/display-name": "error",
+    "react/no-danger": "error",
+    "react/no-did-mount-set-state": "error",
+    "react/no-did-update-set-state": "error",
+    "react/no-direct-mutation-state": "error",
+    "react/no-unknown-property": "error",
+    "react/prefer-es6-class": ["warn", "never"],
     // Disabled temporarily until errors are fixed.
-    "react/prop-types": 0,
-    "react/sort-comp": [2, {
+    "react/prop-types": "off",
+    "react/sort-comp": ["error", {
       order: [
         "lifecycle",
         "everything-else",
         "render"
       ],
       groups: {
         lifecycle: [
           "displayName",
@@ -86,387 +86,387 @@ module.exports = {
           "componentDidUpdate",
           "componentWillUnmount"
         ]
       }
     }],
 
     // Disallow using variables outside the blocks they are defined (especially
     // since only let and const are used, see "no-var").
-    "block-scoped-var": 2,
+    "block-scoped-var": "error",
     // Enforce one true brace style (opening brace on the same line) and avoid
     // start and end braces on the same line.
-    "brace-style": [2, "1tbs", {"allowSingleLine": false}],
+    "brace-style": ["error", "1tbs", {"allowSingleLine": false}],
     // Require camel case names
-    "camelcase": 2,
+    "camelcase": "error",
     // Allow trailing commas for easy list extension.  Having them does not
     // impair readability, but also not required either.
-    "comma-dangle": 0,
+    "comma-dangle": "off",
     // Enforce spacing before and after comma
-    "comma-spacing": [2, {"before": false, "after": true}],
+    "comma-spacing": ["error", {"before": false, "after": true}],
     // Enforce one true comma style.
-    "comma-style": [2, "last"],
+    "comma-style": ["error", "last"],
     // Warn about cyclomatic complexity in functions.
-    "complexity": [2, 35],
+    "complexity": ["error", 35],
     // Require return statements to either always or never specify values.
-    "consistent-return": 2,
+    "consistent-return": "error",
     // Don't warn for inconsistent naming when capturing this (not so important
     // with auto-binding fat arrow functions).
-    "consistent-this": 0,
+    "consistent-this": "off",
     // Enforce curly brace conventions for all control statements.
-    "curly": 2,
+    "curly": "error",
     // Don't require a default case in switch statements. Avoid being forced to
     // add a bogus default when you know all possible cases are handled.
-    "default-case": 0,
+    "default-case": "off",
     // Enforce dots on the next line with property name.
-    "dot-location": [2, "property"],
+    "dot-location": ["error", "property"],
     // Encourage the use of dot notation whenever possible.
-    "dot-notation": 2,
+    "dot-notation": "error",
     // Enforce newline at the end of file, with no multiple empty lines.
-    "eol-last": 2,
+    "eol-last": "error",
     // Allow using == instead of ===, in the interest of landing something since
     // the devtools codebase is split on convention here.
-    "eqeqeq": 0,
+    "eqeqeq": "off",
     // Don't require function expressions to have a name.
     // This makes the code more verbose and hard to read. Our engine already
     // does a fantastic job assigning a name to the function, which includes
     // the enclosing function name, and worst case you have a line number that
     // you can just look up.
-    "func-names": 0,
+    "func-names": "off",
     // Allow use of function declarations and expressions.
-    "func-style": 0,
+    "func-style": "off",
     // Deprecated, will be removed in 1.0.
-    "generator-star": 0,
+    "generator-star": "off",
     // Enforce the spacing around the * in generator functions.
-    "generator-star-spacing": [2, "after"],
+    "generator-star-spacing": ["error", "after"],
     // Deprecated, will be removed in 1.0.
-    "global-strict": 0,
+    "global-strict": "off",
     // Only useful in a node environment.
-    "handle-callback-err": 0,
+    "handle-callback-err": "off",
     // Tab width.
-    "indent": [2, 2, {"SwitchCase": 1}],
+    "indent": ["error", 2, {"SwitchCase": 1}],
     // Enforces spacing between keys and values in object literal properties.
-    "key-spacing": [2, {"beforeColon": false, "afterColon": true}],
+    "key-spacing": ["error", {"beforeColon": false, "afterColon": true}],
     // Enforces unix style line breaks.
-    "linebreak-style": [2, "unix"],
+    "linebreak-style": ["error", "unix"],
     // Don't enforce the maximum depth that blocks can be nested. The complexity
     // rule is a better rule to check this.
-    "max-depth": 0,
+    "max-depth": "off",
     // Maximum length of a line.
-    "max-len": [2, 90, 2, {
+    "max-len": ["error", 90, 2, {
       "ignoreUrls": true,
       "ignorePattern": "data:image\/|\\s*require\\s*\\(|^\\s*loader\\.lazy|-\\*-"
     }],
     // Maximum depth callbacks can be nested.
-    "max-nested-callbacks": [2, 3],
+    "max-nested-callbacks": ["error", 3],
     // Don't limit the number of parameters that can be used in a function.
-    "max-params": 0,
+    "max-params": "off",
     // Don't limit the maximum number of statement allowed in a function. We
     // already have the complexity rule that's a better measurement.
-    "max-statements": 0,
+    "max-statements": "off",
     // Require a capital letter for constructors, only check if all new
     // operators are followed by a capital letter. Don't warn when capitalized
     // functions are used without the new operator.
-    "new-cap": [2, {"capIsNew": false}],
+    "new-cap": ["error", {"capIsNew": false}],
     // Disallow the omission of parentheses when invoking a constructor with no
     // arguments.
-    "new-parens": 2,
+    "new-parens": "error",
     // Disallow use of the Array constructor.
-    "no-array-constructor": 2,
+    "no-array-constructor": "error",
     // Allow use of bitwise operators.
-    "no-bitwise": 0,
+    "no-bitwise": "off",
     // Disallow use of arguments.caller or arguments.callee.
-    "no-caller": 2,
+    "no-caller": "error",
     // Disallow the catch clause parameter name being the same as a variable in
     // the outer scope, to avoid confusion.
-    "no-catch-shadow": 2,
+    "no-catch-shadow": "error",
     // Deprecated, will be removed in 1.0.
-    "no-comma-dangle": 0,
+    "no-comma-dangle": "off",
     // Disallow assignment in conditional expressions.
-    "no-cond-assign": 2,
+    "no-cond-assign": "error",
     // Allow using the console API.
-    "no-console": 0,
+    "no-console": "off",
     // Allow using constant expressions in conditions like while (true)
-    "no-constant-condition": 0,
+    "no-constant-condition": "off",
     // Allow use of the continue statement.
-    "no-continue": 0,
+    "no-continue": "off",
     // Disallow control characters in regular expressions.
-    "no-control-regex": 2,
+    "no-control-regex": "error",
     // Disallow use of debugger.
-    "no-debugger": 2,
+    "no-debugger": "error",
     // Disallow deletion of variables (deleting properties is fine).
-    "no-delete-var": 2,
+    "no-delete-var": "error",
     // Allow division operators explicitly at beginning of regular expression.
-    "no-div-regex": 0,
+    "no-div-regex": "off",
     // Disallow duplicate arguments in functions.
-    "no-dupe-args": 2,
+    "no-dupe-args": "error",
     // Disallow duplicate keys when creating object literals.
-    "no-dupe-keys": 2,
+    "no-dupe-keys": "error",
     // Disallow a duplicate case label.
-    "no-duplicate-case": 2,
+    "no-duplicate-case": "error",
     // Disallow else after a return in an if. The else around the second return
     // here is useless:
     // if (something) { return false; } else { return true; }
-    "no-else-return": 2,
+    "no-else-return": "error",
     // Disallow empty statements. This will report an error for:
     // try { something(); } catch (e) {}
     // but will not report it for:
     // try { something(); } catch (e) { /* Silencing the error because ...*/ }
     // which is a valid use case.
-    "no-empty": 2,
+    "no-empty": "error",
     // Disallow the use of empty character classes in regular expressions.
-    "no-empty-character-class": 2,
+    "no-empty-character-class": "error",
     // Disallow use of eval(). We have other APIs to evaluate code in content.
-    "no-eval": 2,
+    "no-eval": "error",
     // Disallow assigning to the exception in a catch block.
-    "no-ex-assign": 2,
+    "no-ex-assign": "error",
     // Disallow adding to native types
-    "no-extend-native": 2,
+    "no-extend-native": "error",
     // Disallow unnecessary function binding.
-    "no-extra-bind": 2,
+    "no-extra-bind": "error",
     // Disallow double-negation boolean casts in a boolean context.
-    "no-extra-boolean-cast": 2,
+    "no-extra-boolean-cast": "error",
     // Allow unnecessary parentheses, as they may make the code more readable.
-    "no-extra-parens": 0,
+    "no-extra-parens": "off",
     // Disallow unnecessary semicolons.
-    "no-extra-semi": 2,
+    "no-extra-semi": "error",
     // Deprecated, will be removed in 1.0.
-    "no-extra-strict": 0,
+    "no-extra-strict": "off",
     // Disallow fallthrough of case statements, except if there is a comment.
-    "no-fallthrough": 2,
+    "no-fallthrough": "error",
     // Allow the use of leading or trailing decimal points in numeric literals.
-    "no-floating-decimal": 0,
+    "no-floating-decimal": "off",
     // Disallow comments inline after code.
-    "no-inline-comments": 2,
+    "no-inline-comments": "error",
     // Disallow if as the only statement in an else block.
-    "no-lonely-if": 2,
+    "no-lonely-if": "error",
     // Allow mixing regular variable and require declarations (not a node env).
-    "no-mixed-requires": 0,
+    "no-mixed-requires": "off",
     // Disallow mixed spaces and tabs for indentation.
-    "no-mixed-spaces-and-tabs": 2,
+    "no-mixed-spaces-and-tabs": "error",
     // Disallow use of multiple spaces (sometimes used to align const values,
     // array or object items, etc.). It's hard to maintain and doesn't add that
     // much benefit.
-    "no-multi-spaces": 2,
+    "no-multi-spaces": "error",
     // Disallow use of multiline strings (use template strings instead).
-    "no-multi-str": 2,
+    "no-multi-str": "error",
     // Disallow multiple empty lines.
-    "no-multiple-empty-lines": [2, {"max": 1}],
+    "no-multiple-empty-lines": ["error", {"max": 1}],
     // Disallow reassignments of native objects.
-    "no-native-reassign": 2,
+    "no-native-reassign": "error",
     // Disallow nested ternary expressions, they make the code hard to read.
-    "no-nested-ternary": 2,
+    "no-nested-ternary": "error",
     // Allow use of new operator with the require function.
-    "no-new-require": 0,
+    "no-new-require": "off",
     // Disallow use of octal literals.
-    "no-octal": 2,
+    "no-octal": "error",
     // Allow reassignment of function parameters.
-    "no-param-reassign": 0,
+    "no-param-reassign": "off",
     // Allow string concatenation with __dirname and __filename (not a node env).
-    "no-path-concat": 0,
+    "no-path-concat": "off",
     // Allow use of unary operators, ++ and --.
-    "no-plusplus": 0,
+    "no-plusplus": "off",
     // Allow using process.env (not a node environment).
-    "no-process-env": 0,
+    "no-process-env": "off",
     // Allow using process.exit (not a node environment).
-    "no-process-exit": 0,
+    "no-process-exit": "off",
     // Disallow usage of __proto__ property.
-    "no-proto": 2,
+    "no-proto": "error",
     // Disallow declaring the same variable more than once (we use let anyway).
-    "no-redeclare": 2,
+    "no-redeclare": "error",
     // Disallow multiple spaces in a regular expression literal.
-    "no-regex-spaces": 2,
+    "no-regex-spaces": "error",
     // Allow reserved words being used as object literal keys.
-    "no-reserved-keys": 0,
+    "no-reserved-keys": "off",
     // Don't restrict usage of specified node modules (not a node environment).
-    "no-restricted-modules": 0,
+    "no-restricted-modules": "off",
     // Disallow use of assignment in return statement. It is preferable for a
     // single line of code to have only one easily predictable effect.
-    "no-return-assign": 2,
+    "no-return-assign": "error",
     // Allow use of javascript: urls.
-    "no-script-url": 0,
+    "no-script-url": "off",
     // Disallow comparisons where both sides are exactly the same.
-    "no-self-compare": 2,
+    "no-self-compare": "error",
     // Disallow use of comma operator.
-    "no-sequences": 2,
+    "no-sequences": "error",
     // Warn about declaration of variables already declared in the outer scope.
     // This isn't an error because it sometimes is useful to use the same name
     // in a small helper function rather than having to come up with another
     // random name.
     // Still, making this a warning can help people avoid being confused.
-    "no-shadow": 2,
+    "no-shadow": "error",
     // Disallow shadowing of names such as arguments.
-    "no-shadow-restricted-names": 2,
+    "no-shadow-restricted-names": "error",
     // Deprecated, will be removed in 1.0.
-    "no-space-before-semi": 0,
+    "no-space-before-semi": "off",
     // Disallow space between function identifier and application.
-    "no-spaced-func": 2,
+    "no-spaced-func": "error",
     // Disallow sparse arrays, eg. let arr = [,,2].
     // Array destructuring is fine though:
     // for (let [, breakpointPromise] of aPromises)
-    "no-sparse-arrays": 2,
+    "no-sparse-arrays": "error",
     // Allow use of synchronous methods (not a node environment).
-    "no-sync": 0,
+    "no-sync": "off",
     // Allow the use of ternary operators.
-    "no-ternary": 0,
+    "no-ternary": "off",
     // Disallow throwing literals (eg. throw "error" instead of
     // throw new Error("error")).
-    "no-throw-literal": 2,
+    "no-throw-literal": "error",
     // Disallow trailing whitespace at the end of lines.
-    "no-trailing-spaces": 2,
+    "no-trailing-spaces": "error",
     // Disallow use of undeclared variables unless mentioned in a /*global */
     // block. Note that globals from head.js are automatically imported in tests
     // by the import-headjs-globals rule form the mozilla eslint plugin.
-    "no-undef": 2,
+    "no-undef": "error",
     // Allow dangling underscores in identifiers (for privates).
-    "no-underscore-dangle": 0,
+    "no-underscore-dangle": "off",
     // Allow use of undefined variable.
-    "no-undefined": 0,
+    "no-undefined": "off",
     // Disallow the use of Boolean literals in conditional expressions.
-    "no-unneeded-ternary": 2,
+    "no-unneeded-ternary": "error",
     // Disallow unreachable statements after a return, throw, continue, or break
     // statement.
-    "no-unreachable": 2,
+    "no-unreachable": "error",
     // Disallow global and local variables that aren't used, but allow unused
     // function arguments.
-    "no-unused-vars": [2, {"vars": "all", "args": "none"}],
+    "no-unused-vars": ["error", {"vars": "all", "args": "none"}],
     // Allow using variables before they are defined.
-    "no-use-before-define": 0,
+    "no-use-before-define": "off",
     // We use var-only-at-top-level instead of no-var as we allow top level
     // vars.
-    "no-var": 0,
+    "no-var": "off",
     // Allow using TODO/FIXME comments.
-    "no-warning-comments": 0,
+    "no-warning-comments": "off",
     // Disallow use of the with statement.
-    "no-with": 2,
+    "no-with": "error",
     // Don't require method and property shorthand syntax for object literals.
     // We use this in the code a lot, but not consistently, and this seems more
     // like something to check at code review time.
-    "object-shorthand": 0,
+    "object-shorthand": "off",
     // Allow more than one variable declaration per function.
-    "one-var": 0,
+    "one-var": "off",
     // Disallow padding within blocks.
-    "padded-blocks": [2, "never"],
+    "padded-blocks": ["error", "never"],
     // Don't require quotes around object literal property names.
-    "quote-props": 0,
+    "quote-props": "off",
     // Double quotes should be used.  Other quote characters can be used around strings
     // with embedded double quotes to avoid escaping them.  Template literals are allowed
     // mainly for building multi-line messages where only some lines use substitution.
-    "quotes": [2, "double", {"avoidEscape": true, "allowTemplateLiterals": true}],
+    "quotes": ["error", "double", {"avoidEscape": true, "allowTemplateLiterals": true}],
     // Require use of the second argument for parseInt().
-    "radix": 2,
+    "radix": "error",
     // Always require use of semicolons wherever they are valid.
-    "semi": [2, "always"],
+    "semi": ["error", "always"],
     // Enforce spacing after semicolons.
-    "semi-spacing": [2, {"before": false, "after": true}],
+    "semi-spacing": ["error", {"before": false, "after": true}],
     // Don't require to sort variables within the same declaration block.
     // Anyway, one-var is disabled.
-    "sort-vars": 0,
+    "sort-vars": "off",
     // Deprecated, will be removed in 1.0.
-    "space-after-function-name": 0,
+    "space-after-function-name": "off",
     // Require a space around all keywords.
-    "keyword-spacing": 2,
+    "keyword-spacing": "error",
     // Require a space before the start brace of a block.
-    "space-before-blocks": [2, "always"],
+    "space-before-blocks": ["error", "always"],
     // Deprecated, will be removed in 1.0.
-    "space-before-function-parentheses": 0,
+    "space-before-function-parentheses": "off",
     // Require space after keyword for anonymous functions, but disallow space
     // after name of named functions.
-    "space-before-function-paren": [2, {"anonymous": "always", "named": "never"}],
+    "space-before-function-paren": ["error", {"anonymous": "always", "named": "never"}],
     // Disable the rule that checks if spaces inside {} and [] are there or not.
-    // Our code is split on conventions, and it'd be nice to have 2 rules
+    // Our code is split on conventions, and it'd be nice to have "error" rules
     // instead, one for [] and one for {}. So, disabling until we write them.
-    "space-in-brackets": 0,
+    "space-in-brackets": "off",
     // Disallow spaces inside parentheses.
-    "space-in-parens": [2, "never"],
-    // Require spaces around operators, except for a|0.
-    "space-infix-ops": [2, {"int32Hint": true}],
+    "space-in-parens": ["error", "never"],
+    // Require spaces around operators, except for a|"off".
+    "space-infix-ops": ["error", {"int32Hint": true}],
     // Require spaces before/after unary operators (words on by default,
     // nonwords off by default).
-    "space-unary-ops": [2, { "words": true, "nonwords": false }],
+    "space-unary-ops": ["error", { "words": true, "nonwords": false }],
     // Deprecated, will be removed in 1.0.
-    "space-unary-word-ops": 0,
+    "space-unary-word-ops": "off",
     // Require a space immediately following the // in a line comment.
-    "spaced-comment": [2, "always"],
+    "spaced-comment": ["error", "always"],
     // Require "use strict" to be defined globally in the script.
-    "strict": [2, "global"],
+    "strict": ["error", "global"],
     // Disallow comparisons with the value NaN.
-    "use-isnan": 2,
+    "use-isnan": "error",
     // Warn about invalid JSDoc comments.
     // Disabled for now because of https://github.com/eslint/eslint/issues/2270
     // The rule fails on some jsdoc comments like in:
     // devtools/client/webconsole/console-output.js
-    "valid-jsdoc": 0,
+    "valid-jsdoc": "off",
     // Ensure that the results of typeof are compared against a valid string.
-    "valid-typeof": 2,
+    "valid-typeof": "error",
     // Allow vars to be declared anywhere in the scope.
-    "vars-on-top": 0,
+    "vars-on-top": "off",
     // Don't require immediate function invocation to be wrapped in parentheses.
-    "wrap-iife": 0,
+    "wrap-iife": "off",
     // Don't require regex literals to be wrapped in parentheses (which
     // supposedly prevent them from being mistaken for division operators).
-    "wrap-regex": 0,
+    "wrap-regex": "off",
     // Disallow Yoda conditions (where literal value comes first).
-    "yoda": 2,
+    "yoda": "error",
 
     // And these are the rules that haven't been discussed so far, and that are
     // disabled for now until we introduce them, one at a time.
 
     // Require for-in loops to have an if statement.
-    "guard-for-in": 0,
+    "guard-for-in": "off",
     // allow/disallow an empty newline after var statement
-    "newline-after-var": 0,
+    "newline-after-var": "off",
     // disallow the use of alert, confirm, and prompt
-    "no-alert": 0,
+    "no-alert": "off",
     // disallow comparisons to null without a type-checking operator
-    "no-eq-null": 0,
+    "no-eq-null": "off",
     // disallow overwriting functions written as function declarations
-    "no-func-assign": 0,
+    "no-func-assign": "off",
     // disallow use of eval()-like methods
-    "no-implied-eval": 0,
+    "no-implied-eval": "off",
     // disallow function or variable declarations in nested blocks
-    "no-inner-declarations": 0,
+    "no-inner-declarations": "off",
     // disallow invalid regular expression strings in the RegExp constructor
-    "no-invalid-regexp": 0,
+    "no-invalid-regexp": "off",
     // disallow irregular whitespace outside of strings and comments
-    "no-irregular-whitespace": 0,
+    "no-irregular-whitespace": "off",
     // disallow usage of __iterator__ property
-    "no-iterator": 0,
+    "no-iterator": "off",
     // disallow labels that share a name with a variable
-    "no-label-var": 0,
+    "no-label-var": "off",
     // disallow use of labeled statements
-    "no-labels": 2,
+    "no-labels": "error",
     // disallow unnecessary nested blocks
-    "no-lone-blocks": 0,
+    "no-lone-blocks": "off",
     // disallow creation of functions within loops
-    "no-loop-func": 0,
+    "no-loop-func": "off",
     // disallow negation of the left operand of an in expression
-    "no-negated-in-lhs": 0,
+    "no-negated-in-lhs": "off",
     // disallow use of new operator when not part of the assignment or
     // comparison
-    "no-new": 0,
+    "no-new": "off",
     // disallow use of new operator for Function object
-    "no-new-func": 0,
+    "no-new-func": "off",
     // disallow use of the Object constructor
-    "no-new-object": 0,
+    "no-new-object": "off",
     // disallows creating new instances of String,Number, and Boolean
-    "no-new-wrappers": 0,
+    "no-new-wrappers": "off",
     // disallow the use of object properties of the global object (Math and
     // JSON) as functions
-    "no-obj-calls": 0,
+    "no-obj-calls": "off",
     // disallow use of octal escape sequences in string literals, such as
     // var foo = "Copyright \251";
-    "no-octal-escape": 0,
+    "no-octal-escape": "off",
     // disallow use of undefined when initializing variables
-    "no-undef-init": 0,
+    "no-undef-init": "off",
     // disallow usage of expressions in statement position
-    "no-unused-expressions": 0,
+    "no-unused-expressions": "off",
     // disallow use of void operator
-    "no-void": 0,
+    "no-void": "off",
     // disallow wrapping of non-IIFE statements in parens
-    "no-wrap-func": 0,
+    "no-wrap-func": "off",
     // require assignment operator shorthand where possible or prohibit it
     // entirely
-    "operator-assignment": 0,
+    "operator-assignment": "off",
     // enforce operators to be placed before or after line breaks
-    "operator-linebreak": 0,
+    "operator-linebreak": "off",
   }
 };
--- a/devtools/client/aboutdebugging/components/aboutdebugging.js
+++ b/devtools/client/aboutdebugging/components/aboutdebugging.js
@@ -1,29 +1,34 @@
 /* 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/. */
 
 /* eslint-env browser */
 
 "use strict";
 
-const { createFactory, createClass, DOM: dom } =
+const { createFactory, createClass, DOM: dom, PropTypes } =
   require("devtools/client/shared/vendor/react");
 const Services = require("Services");
 
 const PanelMenu = createFactory(require("./panel-menu"));
 
 loader.lazyGetter(this, "AddonsPanel",
   () => createFactory(require("./addons/panel")));
 loader.lazyGetter(this, "TabsPanel",
   () => createFactory(require("./tabs/panel")));
 loader.lazyGetter(this, "WorkersPanel",
   () => createFactory(require("./workers/panel")));
 
+loader.lazyRequireGetter(this, "DebuggerClient",
+  "devtools/shared/client/main", true);
+loader.lazyRequireGetter(this, "Telemetry",
+  "devtools/client/shared/telemetry");
+
 const Strings = Services.strings.createBundle(
   "chrome://devtools/locale/aboutdebugging.properties");
 
 const panels = [{
   id: "addons",
   name: Strings.GetStringFromName("addons"),
   icon: "chrome://devtools/skin/images/debugging-addons.svg",
   component: AddonsPanel
@@ -39,16 +44,21 @@ const panels = [{
   component: WorkersPanel
 }];
 
 const defaultPanelId = "addons";
 
 module.exports = createClass({
   displayName: "AboutDebuggingApp",
 
+  propTypes: {
+    client: PropTypes.instanceOf(DebuggerClient).isRequired,
+    telemetry: PropTypes.instanceOf(Telemetry).isRequired
+  },
+
   getInitialState() {
     return {
       selectedPanelId: defaultPanelId
     };
   },
 
   componentDidMount() {
     window.addEventListener("hashchange", this.onHashChange);
--- a/devtools/client/aboutdebugging/components/addons/controls.js
+++ b/devtools/client/aboutdebugging/components/addons/controls.js
@@ -6,30 +6,34 @@
 /* globals AddonManager */
 
 "use strict";
 
 loader.lazyImporter(this, "AddonManager",
   "resource://gre/modules/AddonManager.jsm");
 
 const { Cc, Ci } = require("chrome");
-const { createFactory, createClass, DOM: dom } =
+const { createFactory, createClass, DOM: dom, PropTypes } =
   require("devtools/client/shared/vendor/react");
 const Services = require("Services");
 const AddonsInstallError = createFactory(require("./install-error"));
 
 const Strings = Services.strings.createBundle(
   "chrome://devtools/locale/aboutdebugging.properties");
 
 const MORE_INFO_URL = "https://developer.mozilla.org/docs/Tools" +
                       "/about:debugging#Enabling_add-on_debugging";
 
 module.exports = createClass({
   displayName: "AddonsControls",
 
+  propTypes: {
+    debugDisabled: PropTypes.bool
+  },
+
   getInitialState() {
     return {
       installError: null,
     };
   },
 
   onEnableAddonDebuggingChange(event) {
     let enabled = event.target.checked;
--- a/devtools/client/aboutdebugging/components/addons/install-error.js
+++ b/devtools/client/aboutdebugging/components/addons/install-error.js
@@ -1,20 +1,24 @@
 /* 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/. */
 
 /* eslint-env browser */
 "use strict";
 
-const { createClass, DOM: dom } = require("devtools/client/shared/vendor/react");
+const { createClass, DOM: dom, PropTypes } = require("devtools/client/shared/vendor/react");
 
 module.exports = createClass({
   displayName: "AddonsInstallError",
 
+  propTypes: {
+    error: PropTypes.string
+  },
+
   render() {
     if (!this.props.error) {
       return null;
     }
     let text = `There was an error during installation: ${this.props.error}`;
     return dom.div({ className: "addons-install-error" },
                    dom.div({ className: "warning" }),
                    dom.span({}, text));
--- a/devtools/client/aboutdebugging/components/addons/panel.js
+++ b/devtools/client/aboutdebugging/components/addons/panel.js
@@ -1,34 +1,42 @@
 /* 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 { AddonManager } = require("resource://gre/modules/AddonManager.jsm");
-const { createFactory, createClass, DOM: dom } =
+const { createFactory, createClass, DOM: dom, PropTypes } =
   require("devtools/client/shared/vendor/react");
 const Services = require("Services");
 
 const AddonsControls = createFactory(require("./controls"));
 const AddonTarget = createFactory(require("./target"));
 const PanelHeader = createFactory(require("../panel-header"));
 const TargetList = createFactory(require("../target-list"));
 
+loader.lazyRequireGetter(this, "DebuggerClient",
+  "devtools/shared/client/main", true);
+
 const Strings = Services.strings.createBundle(
   "chrome://devtools/locale/aboutdebugging.properties");
 
 const ExtensionIcon = "chrome://mozapps/skin/extensions/extensionGeneric.svg";
 const CHROME_ENABLED_PREF = "devtools.chrome.enabled";
 const REMOTE_ENABLED_PREF = "devtools.debugger.remote-enabled";
 
 module.exports = createClass({
   displayName: "AddonsPanel",
 
+  propTypes: {
+    client: PropTypes.instanceOf(DebuggerClient).isRequired,
+    id: PropTypes.string.isRequired
+  },
+
   getInitialState() {
     return {
       extensions: [],
       debugDisabled: false,
     };
   },
 
   componentDidMount() {
@@ -120,16 +128,17 @@ module.exports = createClass({
     },
     PanelHeader({
       id: id + "-header",
       name: Strings.GetStringFromName("addons")
     }),
     AddonsControls({ debugDisabled }),
     dom.div({ id: "addons" },
       TargetList({
+        id: "extensions",
         name,
         targets,
         client,
         debugDisabled,
         targetClass,
         sort: true
       })
     ));
--- a/devtools/client/aboutdebugging/components/addons/target.js
+++ b/devtools/client/aboutdebugging/components/addons/target.js
@@ -1,27 +1,45 @@
 /* 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/. */
 
 /* eslint-env browser */
 
 "use strict";
 
-const { createClass, DOM: dom } =
+const { createClass, DOM: dom, PropTypes } =
   require("devtools/client/shared/vendor/react");
 const { debugAddon } = require("../../modules/addon");
 const Services = require("Services");
 
+loader.lazyImporter(this, "BrowserToolboxProcess",
+  "resource://devtools/client/framework/ToolboxProcess.jsm");
+
+loader.lazyRequireGetter(this, "DebuggerClient",
+  "devtools/shared/client/main", true);
+
 const Strings = Services.strings.createBundle(
   "chrome://devtools/locale/aboutdebugging.properties");
 
 module.exports = createClass({
   displayName: "AddonTarget",
 
+  propTypes: {
+    client: PropTypes.instanceOf(DebuggerClient).isRequired,
+    debugDisabled: PropTypes.bool,
+    target: PropTypes.shape({
+      addonActor: PropTypes.string.isRequired,
+      addonID: PropTypes.string.isRequired,
+      icon: PropTypes.string,
+      name: PropTypes.string.isRequired,
+      temporarilyInstalled: PropTypes.bool
+    }).isRequired
+  },
+
   debug() {
     let { target } = this.props;
     debugAddon(target.addonID);
   },
 
   reload() {
     let { client, target } = this.props;
     // This function sometimes returns a partial promise that only
--- a/devtools/client/aboutdebugging/components/panel-header.js
+++ b/devtools/client/aboutdebugging/components/panel-header.js
@@ -1,19 +1,24 @@
 /* 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 { createClass, DOM: dom } =
+const { createClass, DOM: dom, PropTypes } =
   require("devtools/client/shared/vendor/react");
 
 module.exports = createClass({
   displayName: "PanelHeader",
 
+  propTypes: {
+    id: PropTypes.string.isRequired,
+    name: PropTypes.string.isRequired
+  },
+
   render() {
     let { name, id } = this.props;
 
     return dom.div({ className: "header" },
       dom.h1({ id, className: "header-name" }, name));
   },
 });
--- a/devtools/client/aboutdebugging/components/panel-menu-entry.js
+++ b/devtools/client/aboutdebugging/components/panel-menu-entry.js
@@ -1,20 +1,28 @@
 /* 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 { createClass, DOM: dom } =
+const { createClass, DOM: dom, PropTypes } =
   require("devtools/client/shared/vendor/react");
 
 module.exports = createClass({
   displayName: "PanelMenuEntry",
 
+  propTypes: {
+    icon: PropTypes.string.isRequired,
+    id: PropTypes.string.isRequired,
+    name: PropTypes.string.isRequired,
+    selected: PropTypes.bool,
+    selectPanel: PropTypes.func.isRequired
+  },
+
   onClick() {
     this.props.selectPanel(this.props.id);
   },
 
   onKeyDown(event) {
     if ([" ", "Enter"].includes(event.key)) {
       this.props.selectPanel(this.props.id);
     }
--- a/devtools/client/aboutdebugging/components/panel-menu.js
+++ b/devtools/client/aboutdebugging/components/panel-menu.js
@@ -1,21 +1,32 @@
 /* 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 { createClass, createFactory, DOM: dom } =
+const { createClass, createFactory, DOM: dom, PropTypes } =
   require("devtools/client/shared/vendor/react");
 const PanelMenuEntry = createFactory(require("./panel-menu-entry"));
 
 module.exports = createClass({
   displayName: "PanelMenu",
 
+  propTypes: {
+    panels: PropTypes.arrayOf(PropTypes.shape({
+      id: PropTypes.string.isRequired,
+      name: PropTypes.string.isRequired,
+      icon: PropTypes.string.isRequired,
+      component: PropTypes.func.isRequired
+    })).isRequired,
+    selectPanel: PropTypes.func.isRequired,
+    selectedPanelId: PropTypes.string
+  },
+
   render() {
     let { panels, selectedPanelId, selectPanel } = this.props;
     let panelLinks = panels.map(({ id, name, icon }) => {
       let selected = id == selectedPanelId;
       return PanelMenuEntry({
         id,
         name,
         icon,
--- a/devtools/client/aboutdebugging/components/tabs/panel.js
+++ b/devtools/client/aboutdebugging/components/tabs/panel.js
@@ -1,30 +1,38 @@
 /* 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/. */
 
 /* eslint-env browser */
 
 "use strict";
 
-const { createClass, createFactory, DOM: dom } =
+const { createClass, createFactory, DOM: dom, PropTypes } =
   require("devtools/client/shared/vendor/react");
 const Services = require("Services");
 
 const PanelHeader = createFactory(require("../panel-header"));
 const TargetList = createFactory(require("../target-list"));
 const TabTarget = createFactory(require("./target"));
 
+loader.lazyRequireGetter(this, "DebuggerClient",
+  "devtools/shared/client/main", true);
+
 const Strings = Services.strings.createBundle(
   "chrome://devtools/locale/aboutdebugging.properties");
 
 module.exports = createClass({
   displayName: "TabsPanel",
 
+  propTypes: {
+    client: PropTypes.instanceOf(DebuggerClient).isRequired,
+    id: PropTypes.string.isRequired
+  },
+
   getInitialState() {
     return {
       tabs: []
     };
   },
 
   componentDidMount() {
     let { client } = this.props;
--- a/devtools/client/aboutdebugging/components/tabs/target.js
+++ b/devtools/client/aboutdebugging/components/tabs/target.js
@@ -1,26 +1,35 @@
 /* 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/. */
 
 /* eslint-env browser */
 
 "use strict";
 
-const { createClass, DOM: dom } =
+const { createClass, DOM: dom, PropTypes } =
   require("devtools/client/shared/vendor/react");
 const Services = require("Services");
 
 const Strings = Services.strings.createBundle(
   "chrome://devtools/locale/aboutdebugging.properties");
 
 module.exports = createClass({
   displayName: "TabTarget",
 
+  propTypes: {
+    target: PropTypes.shape({
+      icon: PropTypes.string,
+      outerWindowID: PropTypes.number.isRequired,
+      title: PropTypes.string,
+      url: PropTypes.string.isRequired
+    }).isRequired
+  },
+
   debug() {
     let { target } = this.props;
     window.open("about:devtools-toolbox?type=tab&id=" + target.outerWindowID);
   },
 
   render() {
     let { target } = this.props;
 
--- a/devtools/client/aboutdebugging/components/target-list.js
+++ b/devtools/client/aboutdebugging/components/target-list.js
@@ -1,28 +1,42 @@
 /* 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 { createClass, DOM: dom } =
+const { createClass, DOM: dom, PropTypes } =
   require("devtools/client/shared/vendor/react");
 const Services = require("Services");
 
+loader.lazyRequireGetter(this, "DebuggerClient",
+  "devtools/shared/client/main", true);
+
 const Strings = Services.strings.createBundle(
   "chrome://devtools/locale/aboutdebugging.properties");
 
 const LocaleCompare = (a, b) => {
   return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
 };
 
 module.exports = createClass({
   displayName: "TargetList",
 
+  propTypes: {
+    client: PropTypes.instanceOf(DebuggerClient).isRequired,
+    debugDisabled: PropTypes.bool,
+    error: PropTypes.node,
+    id: PropTypes.string.isRequired,
+    name: PropTypes.string,
+    sort: PropTypes.bool,
+    targetClass: PropTypes.func.isRequired,
+    targets: PropTypes.arrayOf(PropTypes.object).isRequired
+  },
+
   render() {
     let { client, debugDisabled, error, targetClass, targets, sort } = this.props;
     if (sort) {
       targets = targets.sort(LocaleCompare);
     }
     targets = targets.map(target => {
       return targetClass({ client, target, debugDisabled });
     });
--- a/devtools/client/aboutdebugging/components/workers/panel.js
+++ b/devtools/client/aboutdebugging/components/workers/panel.js
@@ -3,35 +3,46 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 /* globals window */
 "use strict";
 
 loader.lazyImporter(this, "PrivateBrowsingUtils",
   "resource://gre/modules/PrivateBrowsingUtils.jsm");
 
 const { Ci } = require("chrome");
-const { createClass, createFactory, DOM: dom } =
+const { createClass, createFactory, DOM: dom, PropTypes } =
   require("devtools/client/shared/vendor/react");
 const { getWorkerForms } = require("../../modules/worker");
 const Services = require("Services");
 
 const PanelHeader = createFactory(require("../panel-header"));
 const TargetList = createFactory(require("../target-list"));
 const WorkerTarget = createFactory(require("./target"));
 const ServiceWorkerTarget = createFactory(require("./service-worker-target"));
 
+loader.lazyImporter(this, "PrivateBrowsingUtils",
+  "resource://gre/modules/PrivateBrowsingUtils.jsm");
+
+loader.lazyRequireGetter(this, "DebuggerClient&