Merge m-c to oak DONTBUILD
authorRobert Strong <robert.bugzilla@gmail.com>
Fri, 19 May 2017 17:09:36 -0700
changeset 1476268 98d7a22714fea8efe7befc6f109435235b78cdda
parent 1476267 2713d645c2df4182f784d5f3ba8b58c3c209f6b0 (current diff)
parent 1131307 8d60d0f825110cfb646ac31dc16dc011708bcf34 (diff)
child 1476269 6a6a080b2b9fcba3fe8bd0e937152ebdf458e9aa
push id263306
push usercatlee@mozilla.com
push dateFri, 06 Apr 2018 15:43:50 +0000
treeherdertry@a0bfb6549eeb [default view] [failures only]
milestone55.0a1
Merge m-c to oak DONTBUILD
browser/app/profile/firefox.js
browser/base/content/aboutDialog-appUpdater.js
browser/base/content/moz.build
browser/base/content/sync/aboutSyncTabs-bindings.xml
browser/base/content/sync/aboutSyncTabs.css
browser/base/content/sync/aboutSyncTabs.js
browser/base/content/sync/aboutSyncTabs.xul
browser/base/content/test/general/browser.ini
browser/base/content/test/general/browser_tabopen_reflows.js
browser/base/content/test/general/browser_windowopen_reflows.js
browser/base/content/test/windows/.eslintrc.js
browser/base/content/test/windows/browser.ini
browser/base/content/test/windows/browser_toolbariconcolor_restyles.js
browser/base/moz.build
browser/components/nsBrowserGlue.js
browser/locales/en-US/chrome/browser/aboutSyncTabs.dtd
browser/locales/en-US/chrome/browser/browser.dtd
browser/modules/SelfSupportBackend.jsm
browser/modules/test/browser/browser_SelfSupportBackend.js
browser/themes/linux/aboutSyncTabs.css
browser/themes/osx/aboutSyncTabs.css
browser/themes/windows/aboutSyncTabs.css
gfx/webrender/res/ps_border.fs.glsl
gfx/webrender/res/ps_border.glsl
gfx/webrender/res/ps_border.vs.glsl
js/src/tests/test262/built-ins/Array/prototype/every/15.4.4.16-2-15.js
js/src/tests/test262/built-ins/Array/prototype/every/15.4.4.16-7-c-i-23.js
js/src/tests/test262/built-ins/Array/prototype/filter/15.4.4.20-2-15.js
js/src/tests/test262/built-ins/Array/prototype/filter/15.4.4.20-9-c-i-23.js
js/src/tests/test262/built-ins/Array/prototype/forEach/15.4.4.18-2-15.js
js/src/tests/test262/built-ins/Array/prototype/forEach/15.4.4.18-7-c-i-23.js
js/src/tests/test262/built-ins/Array/prototype/indexOf/15.4.4.14-1-17.js
js/src/tests/test262/built-ins/Array/prototype/indexOf/15.4.4.14-2-15.js
js/src/tests/test262/built-ins/Array/prototype/indexOf/15.4.4.14-9-b-i-23.js
js/src/tests/test262/built-ins/Array/prototype/lastIndexOf/15.4.4.15-1-17.js
js/src/tests/test262/built-ins/Array/prototype/lastIndexOf/15.4.4.15-2-15.js
js/src/tests/test262/built-ins/Array/prototype/lastIndexOf/15.4.4.15-8-b-i-23.js
js/src/tests/test262/built-ins/Array/prototype/map/15.4.4.19-2-15.js
js/src/tests/test262/built-ins/Array/prototype/map/15.4.4.19-8-c-i-23.js
js/src/tests/test262/built-ins/Array/prototype/reduce/15.4.4.21-2-15.js
js/src/tests/test262/built-ins/Array/prototype/reduce/15.4.4.21-8-b-iii-1-23.js
js/src/tests/test262/built-ins/Array/prototype/reduce/15.4.4.21-9-c-i-23.js
js/src/tests/test262/built-ins/Array/prototype/reduceRight/15.4.4.22-2-15.js
js/src/tests/test262/built-ins/Array/prototype/reduceRight/15.4.4.22-8-b-iii-1-23.js
js/src/tests/test262/built-ins/Array/prototype/reduceRight/15.4.4.22-9-c-i-23.js
js/src/tests/test262/built-ins/Array/prototype/slice/create-species-undef-invalid-len.js
js/src/tests/test262/built-ins/Array/prototype/some/15.4.4.17-2-15.js
js/src/tests/test262/built-ins/Array/prototype/some/15.4.4.17-7-c-i-23.js
js/src/tests/test262/built-ins/Simd/AUTHORS
js/src/tests/test262/built-ins/Simd/all_true.js
js/src/tests/test262/built-ins/Simd/any_true.js
js/src/tests/test262/built-ins/Simd/bit_conversion.js
js/src/tests/test262/built-ins/Simd/bit_preservation.js
js/src/tests/test262/built-ins/Simd/browser.js
js/src/tests/test262/built-ins/Simd/check.js
js/src/tests/test262/built-ins/Simd/constructor.js
js/src/tests/test262/built-ins/Simd/float_operators.js
js/src/tests/test262/built-ins/Simd/from.js
js/src/tests/test262/built-ins/Simd/from_bits.js
js/src/tests/test262/built-ins/Simd/loadn.js
js/src/tests/test262/built-ins/Simd/logical_operators.js
js/src/tests/test262/built-ins/Simd/negate.js
js/src/tests/test262/built-ins/Simd/not.js
js/src/tests/test262/built-ins/Simd/numerical_operators.js
js/src/tests/test262/built-ins/Simd/operators.js
js/src/tests/test262/built-ins/Simd/replace_lane.js
js/src/tests/test262/built-ins/Simd/round_trip.js
js/src/tests/test262/built-ins/Simd/saturate.js
js/src/tests/test262/built-ins/Simd/select.js
js/src/tests/test262/built-ins/Simd/shell.js
js/src/tests/test262/built-ins/Simd/shift_operator.js
js/src/tests/test262/built-ins/Simd/shuffle.js
js/src/tests/test262/built-ins/Simd/storen.js
js/src/tests/test262/built-ins/Simd/swizzle.js
js/src/tests/test262/language/block-scope/syntax/redeclaration-in-block/attempt-to-redeclare-function-declaration-with-function-declaration-strict.js
js/src/tests/test262/language/block-scope/syntax/redeclaration-in-block/attempt-to-redeclare-function-declaration-with-let.js
js/src/tests/test262/language/block-scope/syntax/redeclaration-in-block/attempt-to-redeclare-function-declaration-with-var.js
js/src/tests/test262/language/block-scope/syntax/redeclaration-in-block/attempt-to-redeclare-var-binding-with-let.js
js/src/tests/test262/language/block-scope/syntax/redeclaration-in-block/attempt-to-redeclare-var-with-function-declaration.js
js/src/tests/test262/language/block-scope/syntax/redeclaration-in-block/browser.js
js/src/tests/test262/language/block-scope/syntax/redeclaration-in-block/shell.js
js/src/tests/test262/language/expressions/addition/S9.3_A1_T2.js
js/src/tests/test262/language/expressions/addition/S9.3_A2_T2.js
js/src/tests/test262/language/expressions/addition/S9.3_A3_T2.js
js/src/tests/test262/language/expressions/addition/S9.3_A4.1_T2.js
js/src/tests/test262/language/expressions/addition/S9.3_A4.2_T2.js
js/src/tests/test262/language/expressions/addition/S9.3_A5_T2.js
js/src/tests/test262/language/expressions/assignment/11.13.1-1-1.js
js/src/tests/test262/language/expressions/assignment/11.13.1-1-2.js
js/src/tests/test262/language/expressions/assignment/11.13.1-1-3.js
js/src/tests/test262/language/expressions/assignment/11.13.1-1-4.js
js/src/tests/test262/language/expressions/generators/yield-as-label.js
js/src/tests/test262/language/expressions/object/method-definition/yield-as-binding-identifier.js
js/src/tests/test262/language/expressions/object/method-definition/yield-as-label.js
js/src/tests/test262/language/future-reserved-words/7.6.1-17-s-strict.js
js/src/tests/test262/language/future-reserved-words/7.6.1-18-s-strict.js
js/src/tests/test262/language/future-reserved-words/7.6.1-19-s-strict.js
js/src/tests/test262/language/future-reserved-words/7.6.1-20-s-strict.js
js/src/tests/test262/language/future-reserved-words/7.6.1-21-s-strict.js
js/src/tests/test262/language/future-reserved-words/7.6.1-22-s-strict.js
js/src/tests/test262/language/future-reserved-words/7.6.1-23-s-strict.js
js/src/tests/test262/language/future-reserved-words/7.6.1-24-s-strict.js
js/src/tests/test262/language/future-reserved-words/7.6.1-25-s-strict.js
js/src/tests/test262/language/future-reserved-words/7.6.1.2-1-s-strict.js
js/src/tests/test262/language/future-reserved-words/7.6.1.2-10-s.js
js/src/tests/test262/language/future-reserved-words/7.6.1.2-11-s.js
js/src/tests/test262/language/future-reserved-words/7.6.1.2-12-s.js
js/src/tests/test262/language/future-reserved-words/7.6.1.2-13-s.js
js/src/tests/test262/language/future-reserved-words/7.6.1.2-14-s.js
js/src/tests/test262/language/future-reserved-words/7.6.1.2-16-s.js
js/src/tests/test262/language/future-reserved-words/7.6.1.2-2-s-strict.js
js/src/tests/test262/language/future-reserved-words/7.6.1.2-3-s-strict.js
js/src/tests/test262/language/future-reserved-words/7.6.1.2-4-s-strict.js
js/src/tests/test262/language/future-reserved-words/7.6.1.2-5-s-strict.js
js/src/tests/test262/language/future-reserved-words/7.6.1.2-6-s-strict.js
js/src/tests/test262/language/future-reserved-words/7.6.1.2-7-s-strict.js
js/src/tests/test262/language/future-reserved-words/7.6.1.2-8-s-strict.js
js/src/tests/test262/language/future-reserved-words/7.6.1.2-9-s-strict.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.1.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.10.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.11.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.12.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.13.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.14.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.15-strict.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.15ns.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.16.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.17.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.18-strict.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.18ns.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.19.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.2.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.20.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.21-strict.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.21ns.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.22-strict.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.22ns.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.23-strict.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.23ns.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.24-strict.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.24ns.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.25.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.26-strict.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.26ns.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.27.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.28.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.29.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.3.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.30.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.31.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.4.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.5.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.6.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.7.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.8.js
js/src/tests/test262/language/future-reserved-words/S7.6.1.2_A1.9.js
js/src/tests/test262/language/keywords/S7.6.1.1_A1.1.js
js/src/tests/test262/language/keywords/S7.6.1.1_A1.10.js
js/src/tests/test262/language/keywords/S7.6.1.1_A1.11.js
js/src/tests/test262/language/keywords/S7.6.1.1_A1.12.js
js/src/tests/test262/language/keywords/S7.6.1.1_A1.13.js
js/src/tests/test262/language/keywords/S7.6.1.1_A1.14.js
js/src/tests/test262/language/keywords/S7.6.1.1_A1.15.js
js/src/tests/test262/language/keywords/S7.6.1.1_A1.16.js
js/src/tests/test262/language/keywords/S7.6.1.1_A1.17.js
js/src/tests/test262/language/keywords/S7.6.1.1_A1.18.js
js/src/tests/test262/language/keywords/S7.6.1.1_A1.19.js
js/src/tests/test262/language/keywords/S7.6.1.1_A1.2.js
js/src/tests/test262/language/keywords/S7.6.1.1_A1.20.js
js/src/tests/test262/language/keywords/S7.6.1.1_A1.21.js
js/src/tests/test262/language/keywords/S7.6.1.1_A1.22.js
js/src/tests/test262/language/keywords/S7.6.1.1_A1.23.js
js/src/tests/test262/language/keywords/S7.6.1.1_A1.24.js
js/src/tests/test262/language/keywords/S7.6.1.1_A1.25.js
js/src/tests/test262/language/keywords/S7.6.1.1_A1.3.js
js/src/tests/test262/language/keywords/S7.6.1.1_A1.4.js
js/src/tests/test262/language/keywords/S7.6.1.1_A1.5.js
js/src/tests/test262/language/keywords/S7.6.1.1_A1.6.js
js/src/tests/test262/language/keywords/S7.6.1.1_A1.7.js
js/src/tests/test262/language/keywords/S7.6.1.1_A1.8.js
js/src/tests/test262/language/keywords/S7.6.1.1_A1.9.js
js/src/tests/test262/language/reserved-words/7.6.1-1-1.js
js/src/tests/test262/language/reserved-words/7.6.1-1-10.js
js/src/tests/test262/language/reserved-words/7.6.1-1-11.js
js/src/tests/test262/language/reserved-words/7.6.1-1-12.js
js/src/tests/test262/language/reserved-words/7.6.1-1-13.js
js/src/tests/test262/language/reserved-words/7.6.1-1-14.js
js/src/tests/test262/language/reserved-words/7.6.1-1-15.js
js/src/tests/test262/language/reserved-words/7.6.1-1-16.js
js/src/tests/test262/language/reserved-words/7.6.1-1-2.js
js/src/tests/test262/language/reserved-words/7.6.1-1-3.js
js/src/tests/test262/language/reserved-words/7.6.1-1-4.js
js/src/tests/test262/language/reserved-words/7.6.1-1-5.js
js/src/tests/test262/language/reserved-words/7.6.1-1-6.js
js/src/tests/test262/language/reserved-words/7.6.1-1-7.js
js/src/tests/test262/language/reserved-words/7.6.1-1-8.js
js/src/tests/test262/language/reserved-words/7.6.1-1-9.js
js/src/tests/test262/language/reserved-words/7.6.1-2-1.js
js/src/tests/test262/language/reserved-words/7.6.1-2-10.js
js/src/tests/test262/language/reserved-words/7.6.1-2-11.js
js/src/tests/test262/language/reserved-words/7.6.1-2-12.js
js/src/tests/test262/language/reserved-words/7.6.1-2-13.js
js/src/tests/test262/language/reserved-words/7.6.1-2-14.js
js/src/tests/test262/language/reserved-words/7.6.1-2-15.js
js/src/tests/test262/language/reserved-words/7.6.1-2-16.js
js/src/tests/test262/language/reserved-words/7.6.1-2-2.js
js/src/tests/test262/language/reserved-words/7.6.1-2-3.js
js/src/tests/test262/language/reserved-words/7.6.1-2-4.js
js/src/tests/test262/language/reserved-words/7.6.1-2-5.js
js/src/tests/test262/language/reserved-words/7.6.1-2-6.js
js/src/tests/test262/language/reserved-words/7.6.1-2-7.js
js/src/tests/test262/language/reserved-words/7.6.1-2-8.js
js/src/tests/test262/language/reserved-words/7.6.1-2-9.js
js/src/tests/test262/language/reserved-words/7.6.1-3-1.js
js/src/tests/test262/language/reserved-words/7.6.1-3-10.js
js/src/tests/test262/language/reserved-words/7.6.1-3-11.js
js/src/tests/test262/language/reserved-words/7.6.1-3-12.js
js/src/tests/test262/language/reserved-words/7.6.1-3-13.js
js/src/tests/test262/language/reserved-words/7.6.1-3-14.js
js/src/tests/test262/language/reserved-words/7.6.1-3-15.js
js/src/tests/test262/language/reserved-words/7.6.1-3-16.js
js/src/tests/test262/language/reserved-words/7.6.1-3-2.js
js/src/tests/test262/language/reserved-words/7.6.1-3-3.js
js/src/tests/test262/language/reserved-words/7.6.1-3-4.js
js/src/tests/test262/language/reserved-words/7.6.1-3-5.js
js/src/tests/test262/language/reserved-words/7.6.1-3-6.js
js/src/tests/test262/language/reserved-words/7.6.1-3-7.js
js/src/tests/test262/language/reserved-words/7.6.1-3-8.js
js/src/tests/test262/language/reserved-words/7.6.1-3-9.js
js/src/tests/test262/language/reserved-words/7.6.1-4-1.js
js/src/tests/test262/language/reserved-words/7.6.1-4-10.js
js/src/tests/test262/language/reserved-words/7.6.1-4-11.js
js/src/tests/test262/language/reserved-words/7.6.1-4-12.js
js/src/tests/test262/language/reserved-words/7.6.1-4-13.js
js/src/tests/test262/language/reserved-words/7.6.1-4-14.js
js/src/tests/test262/language/reserved-words/7.6.1-4-15.js
js/src/tests/test262/language/reserved-words/7.6.1-4-16.js
js/src/tests/test262/language/reserved-words/7.6.1-4-2.js
js/src/tests/test262/language/reserved-words/7.6.1-4-3.js
js/src/tests/test262/language/reserved-words/7.6.1-4-4.js
js/src/tests/test262/language/reserved-words/7.6.1-4-5.js
js/src/tests/test262/language/reserved-words/7.6.1-4-6.js
js/src/tests/test262/language/reserved-words/7.6.1-4-7.js
js/src/tests/test262/language/reserved-words/7.6.1-4-8.js
js/src/tests/test262/language/reserved-words/7.6.1-4-9.js
js/src/tests/test262/language/reserved-words/7.6.1-5-1.js
js/src/tests/test262/language/reserved-words/7.6.1-5-10.js
js/src/tests/test262/language/reserved-words/7.6.1-5-11.js
js/src/tests/test262/language/reserved-words/7.6.1-5-12.js
js/src/tests/test262/language/reserved-words/7.6.1-5-13.js
js/src/tests/test262/language/reserved-words/7.6.1-5-14.js
js/src/tests/test262/language/reserved-words/7.6.1-5-15.js
js/src/tests/test262/language/reserved-words/7.6.1-5-16.js
js/src/tests/test262/language/reserved-words/7.6.1-5-2.js
js/src/tests/test262/language/reserved-words/7.6.1-5-3.js
js/src/tests/test262/language/reserved-words/7.6.1-5-4.js
js/src/tests/test262/language/reserved-words/7.6.1-5-5.js
js/src/tests/test262/language/reserved-words/7.6.1-5-6.js
js/src/tests/test262/language/reserved-words/7.6.1-5-7.js
js/src/tests/test262/language/reserved-words/7.6.1-5-8.js
js/src/tests/test262/language/reserved-words/7.6.1-5-9.js
js/src/tests/test262/language/reserved-words/7.6.1-6-1.js
js/src/tests/test262/language/reserved-words/7.6.1-6-10.js
js/src/tests/test262/language/reserved-words/7.6.1-6-11.js
js/src/tests/test262/language/reserved-words/7.6.1-6-12.js
js/src/tests/test262/language/reserved-words/7.6.1-6-13.js
js/src/tests/test262/language/reserved-words/7.6.1-6-14.js
js/src/tests/test262/language/reserved-words/7.6.1-6-15.js
js/src/tests/test262/language/reserved-words/7.6.1-6-16.js
js/src/tests/test262/language/reserved-words/7.6.1-6-2.js
js/src/tests/test262/language/reserved-words/7.6.1-6-3.js
js/src/tests/test262/language/reserved-words/7.6.1-6-4.js
js/src/tests/test262/language/reserved-words/7.6.1-6-5.js
js/src/tests/test262/language/reserved-words/7.6.1-6-6.js
js/src/tests/test262/language/reserved-words/7.6.1-6-7.js
js/src/tests/test262/language/reserved-words/7.6.1-6-8.js
js/src/tests/test262/language/reserved-words/7.6.1-6-9.js
js/src/tests/test262/language/reserved-words/7.6.1-7-1.js
js/src/tests/test262/language/reserved-words/7.6.1-7-10.js
js/src/tests/test262/language/reserved-words/7.6.1-7-11.js
js/src/tests/test262/language/reserved-words/7.6.1-7-12.js
js/src/tests/test262/language/reserved-words/7.6.1-7-13.js
js/src/tests/test262/language/reserved-words/7.6.1-7-14.js
js/src/tests/test262/language/reserved-words/7.6.1-7-15.js
js/src/tests/test262/language/reserved-words/7.6.1-7-16.js
js/src/tests/test262/language/reserved-words/7.6.1-7-2.js
js/src/tests/test262/language/reserved-words/7.6.1-7-3.js
js/src/tests/test262/language/reserved-words/7.6.1-7-4.js
js/src/tests/test262/language/reserved-words/7.6.1-7-5.js
js/src/tests/test262/language/reserved-words/7.6.1-7-6.js
js/src/tests/test262/language/reserved-words/7.6.1-7-7.js
js/src/tests/test262/language/reserved-words/7.6.1-7-8.js
js/src/tests/test262/language/reserved-words/7.6.1-7-9.js
js/src/tests/test262/language/reserved-words/7.6.1-8-1.js
js/src/tests/test262/language/reserved-words/7.6.1-8-10.js
js/src/tests/test262/language/reserved-words/7.6.1-8-11.js
js/src/tests/test262/language/reserved-words/7.6.1-8-12.js
js/src/tests/test262/language/reserved-words/7.6.1-8-13.js
js/src/tests/test262/language/reserved-words/7.6.1-8-14.js
js/src/tests/test262/language/reserved-words/7.6.1-8-15.js
js/src/tests/test262/language/reserved-words/7.6.1-8-16.js
js/src/tests/test262/language/reserved-words/7.6.1-8-2.js
js/src/tests/test262/language/reserved-words/7.6.1-8-3.js
js/src/tests/test262/language/reserved-words/7.6.1-8-4.js
js/src/tests/test262/language/reserved-words/7.6.1-8-5.js
js/src/tests/test262/language/reserved-words/7.6.1-8-6.js
js/src/tests/test262/language/reserved-words/7.6.1-8-7.js
js/src/tests/test262/language/reserved-words/7.6.1-8-8.js
js/src/tests/test262/language/reserved-words/7.6.1-8-9.js
js/src/tests/test262/language/reserved-words/7.6.1.2-1gs-strict.js
js/src/tests/test262/language/reserved-words/S7.6.1_A1.1.js
js/src/tests/test262/language/reserved-words/S7.6.1_A1.2.js
js/src/tests/test262/language/reserved-words/S7.6.1_A1.3.js
js/src/tests/test262/language/reserved-words/S7.6.1_A2.js
js/src/tests/test262/language/statements/class/definition/methods-gen-yield-as-binding-identifier.js
js/src/tests/test262/language/statements/class/definition/methods-gen-yield-as-label.js
js/src/tests/test262/language/statements/generators/yield-as-label.js
js/src/tests/test262/language/statements/switch/early-lex-dup.js
js/src/tests/test262/language/statements/switch/early-lex-var-collision.js
layout/reftests/bugs/346189-1-ref.xul
layout/reftests/bugs/346189-1.xul
memory/mozjemalloc/ql.h
memory/mozjemalloc/qr.h
old-configure.in
security/manager/ssl/nsCrypto.cpp
security/manager/ssl/nsCrypto.h
taskcluster/ci/test/tests.yml
testing/talos/talos/config.py
testing/xpcshell/selftest.py
third_party/rust/gamma-lut/src/main.rs
third_party/rust/threadpool/.cargo-checksum.json
third_party/rust/threadpool/.cargo-ok
third_party/rust/threadpool/.gitignore
third_party/rust/threadpool/.travis.yml
third_party/rust/threadpool/CHANGES.md
third_party/rust/threadpool/Cargo.toml
third_party/rust/threadpool/LICENSE-APACHE
third_party/rust/threadpool/LICENSE-MIT
third_party/rust/threadpool/README.md
third_party/rust/threadpool/lib.rs
toolkit/components/places/tests/unit/test_getPlacesInfo.js
toolkit/components/telemetry/Histograms.json
toolkit/mozapps/installer/packager.mk
toolkit/xre/moz.build
toolkit/xre/nsAppRunner.cpp
tools/profiler/public/StoreSequencer.h
--- a/addon-sdk/source/python-lib/cuddlefish/prefs.py
+++ b/addon-sdk/source/python-lib/cuddlefish/prefs.py
@@ -50,23 +50,23 @@ DEFAULT_NO_CONNECTIONS_PREFS = {
     'media.gmp-manager.cert.requireBuiltIn' : False,
     'media.gmp-manager.url' : 'http://localhost/media-dummy/gmpmanager',
     'media.gmp-manager.url.override': 'http://localhost/dummy-gmp-manager.xml',
     'media.gmp-manager.updateEnabled': False,
     'browser.aboutHomeSnippets.updateUrl': 'https://localhost/snippet-dummy',
     'browser.newtab.url' : 'about:blank',
     'browser.search.update': False,
     'browser.search.suggest.enabled' : False,
+    'browser.safebrowsing.downloads.remote.url': 'http://localhost/safebrowsing-dummy/downloads',
+    'browser.safebrowsing.malware.enabled' : False,
     'browser.safebrowsing.phishing.enabled' : False,
     'browser.safebrowsing.provider.google.updateURL': 'http://localhost/safebrowsing-dummy/update',
     'browser.safebrowsing.provider.google.gethashURL': 'http://localhost/safebrowsing-dummy/gethash',
     'browser.safebrowsing.provider.google4.updateURL': 'http://localhost/safebrowsing4-dummy/update',
     'browser.safebrowsing.provider.google4.gethashURL': 'http://localhost/safebrowsing4-dummy/gethash',
-    'browser.safebrowsing.malware.reportURL': 'http://localhost/safebrowsing-dummy/malwarereport',
-    'browser.selfsupport.url': 'https://localhost/selfsupport-dummy',
     'browser.safebrowsing.provider.mozilla.gethashURL': 'http://localhost/safebrowsing-dummy/gethash',
     'browser.safebrowsing.provider.mozilla.updateURL': 'http://localhost/safebrowsing-dummy/update',
 
     # Disable app update
     'app.update.enabled' : False,
     'app.update.staging.enabled': False,
 
     # Disable about:newtab content fetch
@@ -113,16 +113,17 @@ DEFAULT_FIREFOX_PREFS = {
     'devtools.browsertoolbox.panel': 'jsdebugger',
     'devtools.chrome.enabled' : True,
 
     # From:
     # https://hg.mozilla.org/mozilla-central/file/1dd81c324ac7/build/automation.py.in#l388
     # Make url-classifier updates so rare that they won't affect tests.
     'urlclassifier.updateinterval' : 172800,
     # Point the url-classifier to a nonexistent local URL for fast failures.
+    'browser.safebrowsing.downloads.remote.url': 'http://localhost/safebrowsing-dummy/downloads',
     'browser.safebrowsing.provider.google.gethashURL' : 'http://localhost/safebrowsing-dummy/gethash',
     'browser.safebrowsing.provider.google.updateURL' : 'http://localhost/safebrowsing-dummy/update',
     'browser.safebrowsing.provider.google4.gethashURL' : 'http://localhost/safebrowsing4-dummy/gethash',
     'browser.safebrowsing.provider.google4.updateURL' : 'http://localhost/safebrowsing4-dummy/update',
     'browser.safebrowsing.provider.mozilla.gethashURL': 'http://localhost/safebrowsing-dummy/gethash',
     'browser.safebrowsing.provider.mozilla.updateURL': 'http://localhost/safebrowsing-dummy/update',
 }
 
--- a/addon-sdk/source/test/leak/leak-utils.js
+++ b/addon-sdk/source/test/leak/leak-utils.js
@@ -1,16 +1,15 @@
 /* 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 { Cu, Ci } = require("chrome");
 const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
-const { SelfSupportBackend } = Cu.import("resource:///modules/SelfSupportBackend.jsm", {});
 const Startup = Cu.import("resource://gre/modules/sdk/system/Startup.js", {}).exports;
 
 // Adapted from the SpecialPowers.exactGC() code.  We don't have a
 // window to operate on so we cannot use the exact same logic.  We
 // use 6 GC iterations here as that is what is needed to clean up
 // the windows we have tested with.
 function gc() {
   return new Promise(resolve => {
@@ -33,21 +32,16 @@ function gc() {
 }
 
 // Execute the given test function and verify that we did not leak windows
 // in the process.  The test function must return a promise or be a generator.
 // If the promise is resolved, or generator completes, with an sdk loader
 // object then it will be unloaded after the memory measurements.
 exports.asyncWindowLeakTest = function*(assert, asyncTestFunc) {
 
-  // SelfSupportBackend periodically tries to open windows.  This can
-  // mess up our window leak detection below, so turn it off.
-  if (SelfSupportBackend._log)
-    SelfSupportBackend.uninit();
-
   // Wait for the browser to finish loading.
   yield Startup.onceInitialized;
 
   // Track windows that are opened in an array of weak references.
   let weakWindows = [];
   function windowObserver(subject, topic) {
     let supportsWeak = subject.QueryInterface(Ci.nsISupportsWeakReference);
     if (supportsWeak) {
--- a/addon-sdk/source/test/preferences/no-connections.json
+++ b/addon-sdk/source/test/preferences/no-connections.json
@@ -10,24 +10,25 @@
   "media.gmp-manager.cert.requireBuiltIn": false,
   "media.gmp-manager.url": "http://localhost/media-dummy/gmpmanager",
   "media.gmp-manager.url.override": "http://localhost/dummy-gmp-manager.xml",
   "media.gmp-manager.updateEnabled": false,
   "browser.aboutHomeSnippets.updateUrl": "https://localhost/snippet-dummy",
   "browser.newtab.url": "about:blank",
   "browser.search.update": false,
   "browser.search.suggest.enabled": false,
+  "browser.safebrowsing.downloads.remote.url": "http://localhost/safebrowsing-dummy/downloads",
+  "browser.safebrowsing.malware.enabled": false,
   "browser.safebrowsing.phishing.enabled": false,
   "browser.safebrowsing.provider.google.updateURL": "http://localhost/safebrowsing-dummy/update",
   "browser.safebrowsing.provider.google.gethashURL": "http://localhost/safebrowsing-dummy/gethash",
   "browser.safebrowsing.provider.google.reportURL": "http://localhost/safebrowsing-dummy/malwarereport",
   "browser.safebrowsing.provider.google4.updateURL": "http://localhost/safebrowsing4-dummy/update",
   "browser.safebrowsing.provider.google4.gethashURL": "http://localhost/safebrowsing4-dummy/gethash",
   "browser.safebrowsing.provider.google4.reportURL": "http://localhost/safebrowsing4-dummy/malwarereport",
-  "browser.selfsupport.url": "https://localhost/selfsupport-dummy",
   "browser.safebrowsing.provider.mozilla.gethashURL": "http://localhost/safebrowsing-dummy/gethash",
   "browser.safebrowsing.provider.mozilla.updateURL": "http://localhost/safebrowsing-dummy/update",
   "browser.newtabpage.directory.source": "data:application/json,{'jetpack':1}",
   "extensions.update.url": "http://localhost/extensions-dummy/updateURL",
   "extensions.update.background.url": "http://localhost/extensions-dummy/updateBackgroundURL",
   "extensions.blocklist.url": "http://localhost/extensions-dummy/blocklistURL",
   "extensions.webservice.discoverURL": "http://localhost/extensions-dummy/discoveryURL",
   "extensions.getAddons.maxResults": 0,
--- a/browser/app/permissions
+++ b/browser/app/permissions
@@ -3,17 +3,16 @@
 # * matchtype \t type \t permission \t host
 # * "origin" should be used for matchtype, "host" is supported for legacy reasons
 # * type is a string that identifies the type of permission (e.g. "cookie")
 # * permission is an integer between 1 and 15
 # See nsPermissionManager.cpp for more...
 
 # UITour
 origin	uitour	1	https://www.mozilla.org
-origin	uitour	1	https://self-repair.mozilla.org
 origin	uitour	1	https://support.mozilla.org
 origin	uitour	1	https://addons.mozilla.org
 origin	uitour	1	https://discovery.addons.mozilla.org
 origin	uitour	1	about:home
 
 # XPInstall
 origin	install	1	https://addons.mozilla.org
 origin	install	1	https://testpilot.firefox.com
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -817,18 +817,16 @@ pref("browser.EULA.version", 3);
 pref("browser.rights.version", 3);
 pref("browser.rights.3.shown", false);
 
 #ifdef DEBUG
 // Don't show the about:rights notification in debug builds.
 pref("browser.rights.override", true);
 #endif
 
-pref("browser.selfsupport.url", "https://self-repair.mozilla.org/%LOCALE%/repair");
-
 pref("browser.sessionstore.resume_from_crash", true);
 pref("browser.sessionstore.resume_session_once", false);
 
 // Minimal interval between two save operations in milliseconds (while the user is active).
 pref("browser.sessionstore.interval", 15000); // 15 seconds
 
 // Minimal interval between two save operations in milliseconds (while the user is idle).
 pref("browser.sessionstore.interval.idle", 3600000); // 1h
--- a/browser/base/content/aboutDialog-appUpdater.js
+++ b/browser/base/content/aboutDialog-appUpdater.js
@@ -170,16 +170,24 @@ appUpdater.prototype =
    */
   selectPanel(aChildID) {
     let panel = document.getElementById(aChildID);
 
     let button = panel.querySelector("button");
     if (button) {
       if (aChildID == "downloadAndInstall") {
         let updateVersion = gAppUpdater.update.displayVersion;
+        // Include the build ID if this is an "a#" (nightly or aurora) build
+        if (/a\d+$/.test(updateVersion)) {
+          let buildID = gAppUpdater.update.buildID;
+          let year = buildID.slice(0, 4);
+          let month = buildID.slice(4, 6);
+          let day = buildID.slice(6, 8);
+          updateVersion += ` (${year}-${month}-${day})`;
+        }
         button.label = this.bundle.formatStringFromName("update.downloadAndInstallButton.label", [updateVersion], 1);
         button.accessKey = this.bundle.GetStringFromName("update.downloadAndInstallButton.accesskey");
       }
       this.updateDeck.selectedPanel = panel;
       if (!document.commandDispatcher.focusedElement || // don't steal the focus
           document.commandDispatcher.focusedElement.localName == "button") // except from the other buttons
         button.focus();
 
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -477,17 +477,17 @@ var PlacesCommandHook = {
       // Bug 1148838 - Make this code work for full page plugins.
       let description = null;
       let charset = null;
 
       let docInfo = await this._getPageDetails(aBrowser);
 
       try {
         info.title = docInfo.isErrorPage ?
-          (await PlacesUtils.promisePlaceInfo(aBrowser.currentURI)).title :
+          (await PlacesUtils.history.fetch(aBrowser.currentURI)).title :
           aBrowser.contentTitle;
         info.title = info.title || url.href;
         description = docInfo.description;
         charset = aBrowser.characterSet;
       } catch (e) {
         Components.utils.reportError(e);
       }
 
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -140,17 +140,18 @@
 
     <!-- for search and content formfill/pw manager -->
 
     <panel type="autocomplete-richlistbox"
            id="PopupAutoComplete"
            noautofocus="true"
            hidden="true"
            overflowpadding="4"
-           norolluponanchor="true" />
+           norolluponanchor="true"
+           nomaxresults="true" />
 
     <!-- for search with one-off buttons -->
     <panel type="autocomplete" id="PopupSearchAutoComplete" noautofocus="true" hidden="true"/>
 
     <!-- for url bar autocomplete -->
     <panel type="autocomplete-richlistbox"
            id="PopupAutoCompleteRichResult"
            noautofocus="true"
@@ -315,17 +316,17 @@
       <toolbarbutton id="sidebar-switcher-tabs"
                      label="&syncedTabs.sidebar.label;"
                      class="subviewbutton subviewbutton-iconic"
                      observes="viewTabsSidebar"
                      oncommand="SidebarUI.show('viewTabsSidebar');">
          <observes element="viewTabsSidebar" attribute="checked"/>
        </toolbarbutton>
       <toolbarseparator/>
-      <toolbarbutton label="&sidebarCloseButton.tooltip;"
+      <toolbarbutton label="&sidebarMenuClose.label;"
                      class="subviewbutton"
                      oncommand="SidebarUI.hide()"/>
     </panel>
 
     <menupopup id="toolbar-context-menu"
                onpopupshowing="onViewToolbarsPopupShowing(event, document.getElementById('viewToolbarsMenuSeparator'));">
       <menuitem oncommand="gCustomizeMode.addToPanel(document.popupNode)"
                 accesskey="&customizeMenu.moveToPanel.accesskey;"
--- a/browser/base/content/moz.build
+++ b/browser/base/content/moz.build
@@ -20,19 +20,16 @@ with Files("docs/**"):
     BUG_COMPONENT = ("Core", "Security")
 
 with Files("newtab/**"):
     BUG_COMPONENT = ("Firefox", "New Tab Page")
 
 with Files("pageinfo/**"):
     BUG_COMPONENT = ("Firefox", "Page Info Window")
 
-with Files("sync/**"):
-    BUG_COMPONENT = ("Firefox", "Sync")
-
 with Files("test/alerts/**"):
     BUG_COMPONENT = ("Toolkit", "Notifications and Alerts")
 
 with Files("test/appUpdate/**"):
     BUG_COMPONENT = ("Toolkit", "Application Update")
 
 with Files("test/captivePortal/**"):
     BUG_COMPONENT = ("Firefox", "General")
deleted file mode 100644
--- a/browser/base/content/sync/aboutSyncTabs-bindings.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0"?>
-
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
-   - License, v. 2.0. If a copy of the MPL was not distributed with this
-   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-
-<!-- import-globals-from aboutSyncTabs.js -->
-
-<bindings id="tabBindings"
-          xmlns="http://www.mozilla.org/xbl"
-          xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-          xmlns:xbl="http://www.mozilla.org/xbl">
-
-  <binding id="tab-listing" extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
-    <content>
-      <xul:hbox flex="1">
-        <xul:vbox pack="start">
-          <xul:image class="tabIcon"
-                     xbl:inherits="src=icon"/>
-        </xul:vbox>
-        <xul:vbox pack="start" flex="1">
-            <xul:label xbl:inherits="value=title,selected"
-                       crop="end" flex="1" class="title"/>
-            <xul:label xbl:inherits="value=url,selected"
-                       crop="end" flex="1" class="url"/>
-        </xul:vbox>
-      </xul:hbox>
-    </content>
-    <handlers>
-      <handler event="dblclick" button="0">
-        <![CDATA[
-          RemoteTabViewer.openSelected();
-        ]]>
-      </handler>
-    </handlers>
-  </binding>
-
-  <binding id="client-listing" extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
-    <content>
-      <xul:hbox pack="start" align="center" onfocus="event.target.blur()" onselect="return false;">
-        <xul:image/>
-        <xul:label xbl:inherits="value=clientName"
-                   class="clientName"
-                   crop="center" flex="1"/>
-      </xul:hbox>
-    </content>
-  </binding>
-</bindings>
deleted file mode 100644
--- a/browser/base/content/sync/aboutSyncTabs.css
+++ /dev/null
@@ -1,11 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-richlistitem[type="tab"] {
-  -moz-binding: url(chrome://browser/content/sync/aboutSyncTabs-bindings.xml#tab-listing);
-}
-
-richlistitem[type="client"] {
-  -moz-binding: url(chrome://browser/content/sync/aboutSyncTabs-bindings.xml#client-listing);
-}
deleted file mode 100644
--- a/browser/base/content/sync/aboutSyncTabs.js
+++ /dev/null
@@ -1,305 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/* import-globals-from ../utilityOverlay.js */
-
-var Cu = Components.utils;
-
-Cu.import("resource://services-common/utils.js");
-Cu.import("resource://services-sync/main.js");
-Cu.import("resource:///modules/PlacesUIUtils.jsm");
-Cu.import("resource://gre/modules/AppConstants.jsm");
-Cu.import("resource://gre/modules/PlacesUtils.jsm", this);
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "Promise",
-                                  "resource://gre/modules/Promise.jsm");
-
-var RemoteTabViewer = {
-  _tabsList: null,
-
-  init() {
-    Services.obs.addObserver(this, "weave:service:login:finish");
-    Services.obs.addObserver(this, "weave:engine:sync:finish");
-
-    this._tabsList = document.getElementById("tabsList");
-
-    this.buildList(true);
-  },
-
-  uninit() {
-    Services.obs.removeObserver(this, "weave:service:login:finish");
-    Services.obs.removeObserver(this, "weave:engine:sync:finish");
-  },
-
-  createItem(attrs) {
-    let item = document.createElement("richlistitem");
-
-    // Copy the attributes from the argument into the item.
-    for (let attr in attrs) {
-      item.setAttribute(attr, attrs[attr]);
-    }
-
-    if (attrs["type"] == "tab") {
-      item.label = attrs.title != "" ? attrs.title : attrs.url;
-    }
-
-    return item;
-  },
-
-  filterTabs(event) {
-    let val = event.target.value.toLowerCase();
-    let numTabs = this._tabsList.getRowCount();
-    let clientTabs = 0;
-    let currentClient = null;
-
-    for (let i = 0; i < numTabs; i++) {
-      let item = this._tabsList.getItemAtIndex(i);
-      let hide = false;
-      if (item.getAttribute("type") == "tab") {
-        if (!item.getAttribute("url").toLowerCase().includes(val) &&
-            !item.getAttribute("title").toLowerCase().includes(val)) {
-          hide = true;
-        } else {
-          clientTabs++;
-        }
-      } else if (item.getAttribute("type") == "client") {
-        if (currentClient) {
-          if (clientTabs == 0) {
-            currentClient.hidden = true;
-          }
-        }
-        currentClient = item;
-        clientTabs = 0;
-      }
-      item.hidden = hide;
-    }
-    if (clientTabs == 0) {
-      currentClient.hidden = true;
-    }
-  },
-
-  openSelected() {
-    let items = this._tabsList.selectedItems;
-    let urls = [];
-    for (let i = 0; i < items.length; i++) {
-      if (items[i].getAttribute("type") == "tab") {
-        urls.push(items[i].getAttribute("url"));
-        let index = this._tabsList.getIndexOfItem(items[i]);
-        this._tabsList.removeItemAt(index);
-      }
-    }
-    if (urls.length) {
-      getTopWin().gBrowser.loadTabs(urls);
-      this._tabsList.clearSelection();
-    }
-  },
-
-  bookmarkSingleTab() {
-    let item = this._tabsList.selectedItems[0];
-    let uri = Weave.Utils.makeURI(item.getAttribute("url"));
-    let title = item.getAttribute("title");
-    PlacesUIUtils.showBookmarkDialog({ action: "add"
-                                     , type: "bookmark"
-                                     , uri
-                                     , title
-                                     , hiddenRows: [ "description"
-                                                   , "location"
-                                                   , "loadInSidebar"
-                                                   , "keyword" ]
-                                     }, window.top);
-  },
-
-  bookmarkSelectedTabs() {
-    let items = this._tabsList.selectedItems;
-    let URIs = [];
-    for (let i = 0; i < items.length; i++) {
-      if (items[i].getAttribute("type") == "tab") {
-        let uri = Weave.Utils.makeURI(items[i].getAttribute("url"));
-        if (!uri) {
-          continue;
-        }
-
-        URIs.push(uri);
-      }
-    }
-    if (URIs.length) {
-      PlacesUIUtils.showBookmarkDialog({ action: "add"
-                                       , type: "folder"
-                                       , URIList: URIs
-                                       , hiddenRows: [ "description" ]
-                                       }, window.top);
-    }
-  },
-
-  getIcon(iconUri, defaultIcon) {
-    try {
-      let iconURI = Weave.Utils.makeURI(iconUri);
-      return PlacesUtils.favicons.getFaviconLinkForIcon(iconURI).spec;
-    } catch (ex) {
-      // Do nothing.
-    }
-
-    // Just give the provided default icon or the system's default.
-    return defaultIcon || PlacesUtils.favicons.defaultFavicon.spec;
-  },
-
-  _waitingForBuildList: false,
-
-  _buildListRequested: false,
-
-  buildList(forceSync) {
-    if (this._waitingForBuildList) {
-      this._buildListRequested = true;
-      return;
-    }
-
-    this._waitingForBuildList = true;
-    this._buildListRequested = false;
-
-    this._clearTabList();
-
-    if (Weave.Service.isLoggedIn) {
-      this._refetchTabs(forceSync);
-      this._generateWeaveTabList();
-    } else {
-      // XXXzpao We should say something about not being logged in & not having data
-      //        or tell the appropriate condition. (bug 583344)
-    }
-
-    this._waitingForBuildList = false;
-    if (this._buildListRequested) {
-      CommonUtils.nextTick(this.buildList, this);
-    }
-  },
-
-  _clearTabList() {
-    let list = this._tabsList;
-
-    // Clear out existing richlistitems.
-    let count = list.getRowCount();
-    if (count > 0) {
-      for (let i = count - 1; i >= 0; i--) {
-        list.removeItemAt(i);
-      }
-    }
-  },
-
-  _generateWeaveTabList() {
-    let engine = Weave.Service.engineManager.get("tabs");
-    let list = this._tabsList;
-
-    let seenURLs = new Set();
-    let localURLs = engine.getOpenURLs();
-
-    for (let [, client] of Object.entries(engine.getAllClients())) {
-      // Create the client node, but don't add it in-case we don't show any tabs
-      let appendClient = true;
-
-      client.tabs.forEach(function({title, urlHistory, icon}) {
-        let url = urlHistory[0];
-        if (!url || localURLs.has(url) || seenURLs.has(url)) {
-          return;
-        }
-        seenURLs.add(url);
-
-        if (appendClient) {
-          let attrs = {
-            type: "client",
-            clientName: client.clientName,
-            class: Weave.Service.clientsEngine.isMobile(client.id) ? "mobile" : "desktop"
-          };
-          let clientEnt = this.createItem(attrs);
-          list.appendChild(clientEnt);
-          appendClient = false;
-          clientEnt.disabled = true;
-        }
-        let attrs = {
-          type:  "tab",
-          title: title || url,
-          url,
-          icon:  this.getIcon(icon),
-        }
-        let tab = this.createItem(attrs);
-        list.appendChild(tab);
-      }, this);
-    }
-  },
-
-  adjustContextMenu(event) {
-    let mode = "all";
-    switch (this._tabsList.selectedItems.length) {
-      case 0:
-        break;
-      case 1:
-        mode = "single"
-        break;
-      default:
-        mode = "multiple";
-        break;
-    }
-
-    let menu = document.getElementById("tabListContext");
-    let el = menu.firstChild;
-    while (el) {
-      let showFor = el.getAttribute("showFor");
-      if (showFor) {
-        el.hidden = showFor != mode && showFor != "all";
-      }
-
-      el = el.nextSibling;
-    }
-  },
-
-  _refetchTabs(force) {
-    if (!force) {
-      // Don't bother refetching tabs if we already did so recently
-      let lastFetch = Services.prefs.getIntPref("services.sync.lastTabFetch", 0);
-
-      let now = Math.floor(Date.now() / 1000);
-      if (now - lastFetch < 30) {
-        return false;
-      }
-    }
-
-    // Ask Sync to just do the tabs engine if it can.
-    Weave.Service.sync(["tabs"]);
-    Services.prefs.setIntPref("services.sync.lastTabFetch",
-                              Math.floor(Date.now() / 1000));
-
-    return true;
-  },
-
-  observe(subject, topic, data) {
-    switch (topic) {
-      case "weave:service:login:finish":
-        // A login has finished, which means that a Sync is about to start and
-        // we will eventually get to the "tabs" engine - but try and force the
-        // tab engine to sync first by passing |true| for the forceSync param.
-        this.buildList(true);
-        break;
-      case "weave:engine:sync:finish":
-        if (data == "tabs") {
-          // The tabs engine just finished, so re-build the list without
-          // forcing a new sync of the tabs engine.
-          this.buildList(false);
-        }
-        break;
-    }
-  },
-
-  handleClick(event) {
-    if (event.target.getAttribute("type") != "tab") {
-      return;
-    }
-
-    if (event.button == 1) {
-      let url = event.target.getAttribute("url");
-      openUILink(url, event);
-      let index = this._tabsList.getIndexOfItem(event.target);
-      this._tabsList.removeItemAt(index);
-    }
-  }
-}
deleted file mode 100644
--- a/browser/base/content/sync/aboutSyncTabs.xul
+++ /dev/null
@@ -1,68 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!-- 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/. -->
-
-<?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
-<?xml-stylesheet href="chrome://browser/skin/aboutSyncTabs.css" type="text/css"?>
-<?xml-stylesheet href="chrome://browser/content/sync/aboutSyncTabs.css" type="text/css"?>
-
-<!DOCTYPE window [
-  <!ENTITY % aboutSyncTabsDTD SYSTEM "chrome://browser/locale/aboutSyncTabs.dtd">
-  %aboutSyncTabsDTD;
-]>
-
-<window id="tabs-display"
-        onload="RemoteTabViewer.init()"
-        onunload="RemoteTabViewer.uninit()"
-        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-        xmlns:html="http://www.w3.org/1999/xhtml"
-        title="&tabs.otherDevices.label;">
-  <script type="application/javascript" src="chrome://browser/content/sync/aboutSyncTabs.js"/>
-  <script type="application/javascript" src="chrome://browser/content/utilityOverlay.js"/>
-  <html:head>
-    <html:link rel="icon" href="chrome://browser/skin/sync-16.png"/>
-  </html:head>
-
-  <popupset id="contextmenus">
-    <menupopup id="tabListContext">
-      <menuitem label="&tabs.context.openTab.label;"
-                accesskey="&tabs.context.openTab.accesskey;"
-                oncommand="RemoteTabViewer.openSelected()"
-                showFor="single"/>
-      <menuitem label="&tabs.context.bookmarkSingleTab.label;"
-                accesskey="&tabs.context.bookmarkSingleTab.accesskey;"
-                oncommand="RemoteTabViewer.bookmarkSingleTab(event)"
-                showFor="single"/>
-      <menuitem label="&tabs.context.openMultipleTabs.label;"
-                accesskey="&tabs.context.openMultipleTabs.accesskey;"
-                oncommand="RemoteTabViewer.openSelected()"
-                showFor="multiple"/>
-      <menuitem label="&tabs.context.bookmarkMultipleTabs.label;"
-                accesskey="&tabs.context.bookmarkMultipleTabs.accesskey;"
-                oncommand="RemoteTabViewer.bookmarkSelectedTabs()"
-                showFor="multiple"/>
-      <menuseparator/>
-      <menuitem label="&tabs.context.refreshList.label;"
-                accesskey="&tabs.context.refreshList.accesskey;"
-                oncommand="RemoteTabViewer.buildList()"
-                showFor="all"/>
-    </menupopup>
-  </popupset>
-  <richlistbox context="tabListContext" id="tabsList" seltype="multiple"
-               align="center" flex="1"
-               onclick="RemoteTabViewer.handleClick(event)"
-               oncontextmenu="RemoteTabViewer.adjustContextMenu(event)">
-    <hbox id="headers" align="center">
-      <label id="tabsListHeading"
-             value="&tabs.otherDevices.label;"/>
-      <spacer flex="1"/>
-      <textbox type="search"
-               emptytext="&tabs.searchText.label;"
-               oncommand="RemoteTabViewer.filterTabs(event)"/>
-    </hbox>
-
-  </richlistbox>
-</window>
-
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -995,21 +995,25 @@
 
       <method name="getWindowTitleForBrowser">
         <parameter name="aBrowser"/>
         <body>
           <![CDATA[
             var newTitle = "";
             var docElement = this.ownerDocument.documentElement;
             var sep = docElement.getAttribute("titlemenuseparator");
-
-            // Strip out any null bytes in the content title, since the
-            // underlying widget implementations of nsWindow::SetTitle pass
-            // null-terminated strings to system APIs.
-            var docTitle = aBrowser.contentTitle.replace(/\0/g, "");
+            let tab = this.getTabForBrowser(aBrowser);
+            let docTitle;
+
+            if (tab._labelIsContentTitle) {
+              // Strip out any null bytes in the content title, since the
+              // underlying widget implementations of nsWindow::SetTitle pass
+              // null-terminated strings to system APIs.
+              docTitle = tab.getAttribute("label").replace(/\0/g, "");
+            }
 
             if (!docTitle)
               docTitle = docElement.getAttribute("titledefault");
 
             var modifier = docElement.getAttribute("titlemodifier");
             if (docTitle) {
               newTitle += docElement.getAttribute("titlepreface");
               newTitle += docTitle;
@@ -1407,23 +1411,24 @@
       <method name="setTabTitleLoading">
         <parameter name="aTab"/>
         <body/>
       </method>
 
       <method name="setInitialTabTitle">
         <parameter name="aTab"/>
         <parameter name="aTitle"/>
+        <parameter name="aOptions"/>
         <body><![CDATA[
           if (aTitle) {
-            aTab.setAttribute("label", aTitle);
-
             // Don't replace the set label with the empty tab label or the URL
             // while the tab is loading.
             aTab._suppressTransientPlaceholderLabel = true;
+
+            this._setTabLabel(aTab, aTitle, aOptions);
           }
         ]]></body>
       </method>
 
       <method name="setTabTitle">
         <parameter name="aTab"/>
         <body>
           <![CDATA[
@@ -1432,17 +1437,20 @@
 
             if (aTab._suppressTransientPlaceholderLabel) {
               if (!title) {
                 return false;
               }
               delete aTab._suppressTransientPlaceholderLabel;
             }
 
-            if (!title) {
+            let isContentTitle = false;
+            if (title) {
+              isContentTitle = true;
+            } else {
               if (browser.currentURI.spec) {
                 try {
                   title = this.mURIFixup.createExposableURI(browser.currentURI).spec;
                 } catch (ex) {
                   title = browser.currentURI.spec;
                 }
               }
 
@@ -1460,24 +1468,43 @@
                 let brandBundle = document.getElementById("bundle_brand");
                 let brandShortName = brandBundle.getString("brandShortName");
                 title = gNavigatorBundle.getFormattedString("customizeMode.tabTitle",
                                                             [ brandShortName ]);
               } else // Still no title?  Fall back to our untitled string.
                 title = this.mStringBundle.getString("tabs.emptyTabTitle");
             }
 
-            if (aTab.label == title)
+            return this._setTabLabel(aTab, title, { isContentTitle });
+          ]]>
+        </body>
+      </method>
+
+      <method name="_setTabLabel">
+        <parameter name="aTab"/>
+        <parameter name="aLabel"/>
+        <parameter name="aOptions"/>
+        <body>
+          <![CDATA[
+            if (!aLabel || aTab.getAttribute("label") == aLabel) {
               return false;
-
-            aTab.label = title;
-            this._tabAttrModified(aTab, ["label"]);
-
-            if (aTab.selected)
+            }
+
+            aTab.setAttribute("label", aLabel);
+            aTab._labelIsContentTitle = aOptions && aOptions.isContentTitle;
+
+            // Dispatch TabAttrModified event unless we're setting the label
+            // before the TabOpen event was dispatched.
+            if (!aOptions || !aOptions.beforeTabOpen) {
+              this._tabAttrModified(aTab, ["label"]);
+            }
+
+            if (aTab.selected) {
               this.updateTitlebar();
+            }
 
             return true;
           ]]>
         </body>
       </method>
 
       <method name="loadOneTab">
         <parameter name="aURI"/>
@@ -2308,17 +2335,17 @@
 
             var uriIsAboutBlank = aURI == "about:blank";
 
             if (!aNoInitialLabel) {
               if (isBlankPageURL(aURI)) {
                 t.setAttribute("label", this.mStringBundle.getString("tabs.emptyTabTitle"));
               } else {
                 // Set URL as label so that the tab isn't empty initially.
-                this.setInitialTabTitle(t, aURI);
+                this.setInitialTabTitle(t, aURI, { beforeTabOpen: true });
               }
             }
 
             if (aIsPrerendered) {
               t.setAttribute("hidden", "true");
             }
 
             // Related tab inherits current tab's user context unless a different
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -501,18 +501,16 @@ skip-if = buildapp == 'mulet' || (e10s &
 skip-if = os == "linux" || os == "mac" # No tabs in titlebar on linux
                                        # Disabled on OS X because of bug 967917
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_tabfocus.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_tabkeynavigation.js]
 skip-if = (os == "mac" && !e10s) # Bug 1237713 - OSX eats keypresses for some reason
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
-[browser_tabopen_reflows.js]
-# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_tabs_close_beforeunload.js]
 support-files =
   close_beforeunload_opens_second_tab.html
   close_beforeunload.html
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_tabs_isActive.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_tabs_owner.js]
@@ -579,19 +577,16 @@ skip-if = true # Bug 1005420 - fails int
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_visibleTabs_contextMenu.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_visibleTabs_tabPreview.js]
 skip-if = (os == "win" && !debug)
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_web_channel.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
-[browser_windowopen_reflows.js]
-skip-if = os == "mac" # bug 1339317
-# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_zbug569342.js]
 skip-if = e10s || debug # Bug 1094240 - has findbar-related failures
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_registerProtocolHandler_notification.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_addCertException.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_e10s_about_page_triggeringprincipal.js]
--- a/browser/base/content/test/general/browser_audioTabIcon.js
+++ b/browser/base/content/test/general/browser_audioTabIcon.js
@@ -2,17 +2,17 @@ const PAGE = "https://example.com/browse
 const TABATTR_REMOVAL_PREFNAME = "browser.tabs.delayHidingAudioPlayingIconMS";
 const INITIAL_TABATTR_REMOVAL_DELAY_MS = Services.prefs.getIntPref(TABATTR_REMOVAL_PREFNAME);
 
 async function wait_for_tab_playing_event(tab, expectPlaying) {
   if (tab.soundPlaying == expectPlaying) {
     ok(true, "The tab should " + (expectPlaying ? "" : "not ") + "be playing");
     return true;
   }
-  return await BrowserTestUtils.waitForEvent(tab, "TabAttrModified", false, (event) => {
+  return BrowserTestUtils.waitForEvent(tab, "TabAttrModified", false, (event) => {
     if (event.detail.changed.includes("soundplaying")) {
       is(tab.hasAttribute("soundplaying"), expectPlaying, "The tab should " + (expectPlaying ? "" : "not ") + "be playing");
       is(tab.soundPlaying, expectPlaying, "The tab should " + (expectPlaying ? "" : "not ") + "be playing");
       return true;
     }
     return false;
   });
 }
@@ -48,18 +48,16 @@ async function pause(tab, options) {
     // Use 10s to remove possibility of race condition with attr removal.
     Services.prefs.setIntPref(TABATTR_REMOVAL_PREFNAME, 10000);
   }
 
   try {
     let browser = tab.linkedBrowser;
     let awaitDOMAudioPlaybackStopped =
       BrowserTestUtils.waitForEvent(browser, "DOMAudioPlaybackStopped", "DOMAudioPlaybackStopped event should get fired after pause");
-    let awaitTabPausedAttrModified =
-      wait_for_tab_playing_event(tab, false);
     await ContentTask.spawn(browser, {}, async function() {
       let audio = content.document.querySelector("audio");
       audio.pause();
     });
 
     // If the tab has already be muted, it means the tab won't have soundplaying,
     // so we don't need to check this attribute.
     if (browser.audioMuted) {
@@ -68,17 +66,17 @@ async function pause(tab, options) {
 
     if (extendedDelay) {
       ok(tab.hasAttribute("soundplaying"), "The tab should still have the soundplaying attribute immediately after pausing");
 
       await awaitDOMAudioPlaybackStopped;
       ok(tab.hasAttribute("soundplaying"), "The tab should still have the soundplaying attribute immediately after DOMAudioPlaybackStopped");
     }
 
-    await awaitTabPausedAttrModified;
+    await wait_for_tab_playing_event(tab, false);
     ok(!tab.hasAttribute("soundplaying"), "The tab should not have the soundplaying attribute after the timeout has resolved");
   } finally {
     // Make sure other tests don't timeout if an exception gets thrown above.
     // Need to use setIntPref instead of clearUserPref because prefs_general.js
     // overrides the default value to help this and other tests run faster.
     Services.prefs.setIntPref(TABATTR_REMOVAL_PREFNAME, INITIAL_TABATTR_REMOVAL_DELAY_MS);
   }
 }
rename from browser/base/content/test/windows/.eslintrc.js
rename to browser/base/content/test/performance/.eslintrc.js
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/performance/browser.ini
@@ -0,0 +1,7 @@
+[DEFAULT]
+support-files =
+  head.js
+[browser_tabclose_reflows.js]
+[browser_tabopen_reflows.js]
+[browser_toolbariconcolor_restyles.js]
+[browser_windowopen_reflows.js]
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/performance/browser_tabclose_reflows.js
@@ -0,0 +1,71 @@
+"use strict";
+
+/**
+ * WHOA THERE: We should never be adding new things to EXPECTED_REFLOWS. This
+ * is a whitelist that should slowly go away as we improve the performance of
+ * the front-end. Instead of adding more reflows to the whitelist, you should
+ * be modifying your code to avoid the reflow.
+ *
+ * See https://developer.mozilla.org/en-US/Firefox/Performance_best_practices_for_Firefox_fe_engineers
+ * for tips on how to do that.
+ */
+const EXPECTED_REFLOWS = [
+  [
+    "_adjustFocusAfterTabSwitch@chrome://browser/content/tabbrowser.xml",
+  ],
+];
+
+if (gMultiProcessBrowser) {
+  EXPECTED_REFLOWS.push(
+    [
+      "_adjustFocusAfterTabSwitch@chrome://browser/content/tabbrowser.xml",
+    ],
+  );
+}
+
+/*
+ * This test ensures that there are no unexpected
+ * uninterruptible reflows when closing new tabs.
+ */
+add_task(async function() {
+  // If we've got a preloaded browser, get rid of it so that it
+  // doesn't interfere with the test if it's loading. We have to
+  // do this before we disable preloading or changing the new tab
+  // URL, otherwise _getPreloadedBrowser will return null, despite
+  // the preloaded browser existing.
+  let preloaded = gBrowser._getPreloadedBrowser();
+  if (preloaded) {
+    preloaded.remove();
+  }
+
+  await SpecialPowers.pushPrefEnv({
+    set: [["browser.newtab.preload", false]],
+  });
+
+  let aboutNewTabService = Cc["@mozilla.org/browser/aboutnewtab-service;1"]
+                             .getService(Ci.nsIAboutNewTabService);
+  aboutNewTabService.newTabURL = "about:blank";
+
+  registerCleanupFunction(() => {
+    aboutNewTabService.resetNewTabURL();
+  });
+
+  // Because the tab strip is a scrollable frame, we can't use the
+  // default dirtying function from withReflowObserver and reliably
+  // get reflows for the strip. Instead, we provide a node that's
+  // already in the scrollable frame to dirty - in this case, the
+  // original tab.
+  let origTab = gBrowser.selectedTab;
+
+  let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
+  await BrowserTestUtils.waitForCondition(() => tab._fullyOpen);
+
+  // Add a reflow observer and open a new tab.
+  await withReflowObserver(async function() {
+    let switchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone");
+    gBrowser.removeTab(tab, { animate: true });
+    await BrowserTestUtils.waitForEvent(tab, "transitionend",
+        false, e => e.propertyName === "max-width");
+    await switchDone;
+  }, EXPECTED_REFLOWS, window, origTab);
+});
rename from browser/base/content/test/general/browser_tabopen_reflows.js
rename to browser/base/content/test/performance/browser_tabopen_reflows.js
--- a/browser/base/content/test/general/browser_tabopen_reflows.js
+++ b/browser/base/content/test/performance/browser_tabopen_reflows.js
@@ -1,145 +1,108 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
-XPCOMUtils.defineLazyGetter(this, "docShell", () => {
-  return window.QueryInterface(Ci.nsIInterfaceRequestor)
-               .getInterface(Ci.nsIWebNavigation)
-               .QueryInterface(Ci.nsIDocShell);
-});
+"use strict";
 
+/**
+ * WHOA THERE: We should never be adding new things to EXPECTED_REFLOWS. This
+ * is a whitelist that should slowly go away as we improve the performance of
+ * the front-end. Instead of adding more reflows to the whitelist, you should
+ * be modifying your code to avoid the reflow.
+ *
+ * See https://developer.mozilla.org/en-US/Firefox/Performance_best_practices_for_Firefox_fe_engineers
+ * for tips on how to do that.
+ */
 const EXPECTED_REFLOWS = [
-  // tabbrowser.adjustTabstrip() call after tabopen animation has finished
-  "adjustTabstrip@chrome://browser/content/tabbrowser.xml|" +
-    "_handleNewTab@chrome://browser/content/tabbrowser.xml|" +
-    "onxbltransitionend@chrome://browser/content/tabbrowser.xml|",
-
-  // switching focus in updateCurrentBrowser() causes reflows
-  "_adjustFocusAfterTabSwitch@chrome://browser/content/tabbrowser.xml|" +
-    "updateCurrentBrowser@chrome://browser/content/tabbrowser.xml|" +
-    "onselect@chrome://browser/content/browser.xul|",
-
-  // switching focus in openLinkIn() causes reflows
-  "openLinkIn@chrome://browser/content/utilityOverlay.js|" +
-    "openUILinkIn@chrome://browser/content/utilityOverlay.js|" +
-    "BrowserOpenTab@chrome://browser/content/browser.js|",
+  // selection change notification may cause querying the focused editor content
+  // by IME and that will cause reflow.
+  [
+    "select@chrome://global/content/bindings/textbox.xml",
+    "focusAndSelectUrlBar@chrome://browser/content/browser.js",
+    "openLinkIn@chrome://browser/content/utilityOverlay.js",
+    "openUILinkIn@chrome://browser/content/utilityOverlay.js",
+    "BrowserOpenTab@chrome://browser/content/browser.js",
+  ],
 
   // selection change notification may cause querying the focused editor content
   // by IME and that will cause reflow.
-  "select@chrome://global/content/bindings/textbox.xml|" +
-    "focusAndSelectUrlBar@chrome://browser/content/browser.js|" +
-    "openLinkIn@chrome://browser/content/utilityOverlay.js|" +
-    "openUILinkIn@chrome://browser/content/utilityOverlay.js|" +
-    "BrowserOpenTab@chrome://browser/content/browser.js|",
+  [
+    "select@chrome://global/content/bindings/textbox.xml",
+    "focusAndSelectUrlBar@chrome://browser/content/browser.js",
+    "openLinkIn@chrome://browser/content/utilityOverlay.js",
+    "openUILinkIn@chrome://browser/content/utilityOverlay.js",
+    "BrowserOpenTab@chrome://browser/content/browser.js",
+  ],
 
+  [
+    "select@chrome://global/content/bindings/textbox.xml",
+    "focusAndSelectUrlBar@chrome://browser/content/browser.js",
+    "openLinkIn@chrome://browser/content/utilityOverlay.js",
+    "openUILinkIn@chrome://browser/content/utilityOverlay.js",
+    "BrowserOpenTab@chrome://browser/content/browser.js",
+  ],
+
+  [
+    "openLinkIn@chrome://browser/content/utilityOverlay.js",
+    "openUILinkIn@chrome://browser/content/utilityOverlay.js",
+    "BrowserOpenTab@chrome://browser/content/browser.js",
+  ],
 ];
 
-const PREF_PRELOAD = "browser.newtab.preload";
-const PREF_NEWTAB_DIRECTORYSOURCE = "browser.newtabpage.directory.source";
+if (!gMultiProcessBrowser) {
+  EXPECTED_REFLOWS.push(
+    [
+      "_adjustFocusAfterTabSwitch@chrome://browser/content/tabbrowser.xml",
+      "updateCurrentBrowser@chrome://browser/content/tabbrowser.xml",
+      "onselect@chrome://browser/content/browser.xul",
+    ],
+  );
+}
 
 /*
  * This test ensures that there are no unexpected
  * uninterruptible reflows when opening new tabs.
  */
 add_task(async function() {
-  let DirectoryLinksProvider = Cu.import("resource:///modules/DirectoryLinksProvider.jsm", {}).DirectoryLinksProvider;
-  let NewTabUtils = Cu.import("resource://gre/modules/NewTabUtils.jsm", {}).NewTabUtils;
-  let Promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
-
-  // resolves promise when directory links are downloaded and written to disk
-  function watchLinksChangeOnce() {
-    return new Promise(resolve => {
-      let observer = {
-        onManyLinksChanged: () => {
-          DirectoryLinksProvider.removeObserver(observer);
-          NewTabUtils.links.populateCache(() => {
-            NewTabUtils.allPages.update();
-            resolve();
-          }, true);
-        }
-      };
-      observer.onDownloadFail = observer.onManyLinksChanged;
-      DirectoryLinksProvider.addObserver(observer);
-    });
+  // If we've got a preloaded browser, get rid of it so that it
+  // doesn't interfere with the test if it's loading. We have to
+  // do this before we disable preloading or changing the new tab
+  // URL, otherwise _getPreloadedBrowser will return null, despite
+  // the preloaded browser existing.
+  let preloaded = gBrowser._getPreloadedBrowser();
+  if (preloaded) {
+    preloaded.remove();
   }
 
-  let gOrigDirectorySource = Services.prefs.getCharPref(PREF_NEWTAB_DIRECTORYSOURCE);
-  registerCleanupFunction(() => {
-    Services.prefs.clearUserPref(PREF_PRELOAD);
-    Services.prefs.setCharPref(PREF_NEWTAB_DIRECTORYSOURCE, gOrigDirectorySource);
-    return watchLinksChangeOnce();
+  await SpecialPowers.pushPrefEnv({
+    set: [["browser.newtab.preload", false]],
   });
 
-  Services.prefs.setBoolPref(PREF_PRELOAD, false);
-  // set directory source to dummy/empty links
-  Services.prefs.setCharPref(PREF_NEWTAB_DIRECTORYSOURCE, 'data:application/json,{"test":1}');
-
-  // run tests when directory source change completes
-  await watchLinksChangeOnce();
+  let aboutNewTabService = Cc["@mozilla.org/browser/aboutnewtab-service;1"]
+                             .getService(Ci.nsIAboutNewTabService);
+  aboutNewTabService.newTabURL = "about:blank";
 
-  // Perform a click in the top left of content to ensure the mouse isn't
-  // hovering over any of the tiles
-  let target = gBrowser.selectedBrowser;
-  let rect = target.getBoundingClientRect();
-  let left = rect.left + 1;
-  let top = rect.top + 1;
+  registerCleanupFunction(() => {
+    aboutNewTabService.resetNewTabURL();
+  });
 
-  let utils = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                    .getInterface(Ci.nsIDOMWindowUtils);
-  utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0);
-  utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0);
+  // Because the tab strip is a scrollable frame, we can't use the
+  // default dirtying function from withReflowObserver and reliably
+  // get reflows for the strip. Instead, we provide a node that's
+  // already in the scrollable frame to dirty - in this case, the
+  // original tab.
+  let origTab = gBrowser.selectedTab;
 
   // Add a reflow observer and open a new tab.
-  docShell.addWeakReflowObserver(observer);
-  BrowserOpenTab();
+  await withReflowObserver(async function() {
+    let switchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone");
+    BrowserOpenTab();
+    await BrowserTestUtils.waitForEvent(gBrowser.selectedTab, "transitionend",
+        false, e => e.propertyName === "max-width");
+    await switchDone;
+  }, EXPECTED_REFLOWS, window, origTab);
 
-  // Wait until the tabopen animation has finished.
-  await waitForTransitionEnd();
-
-  // Remove reflow observer and clean up.
-  docShell.removeWeakReflowObserver(observer);
-  gBrowser.removeCurrentTab();
+  let switchDone = BrowserTestUtils.waitForEvent(window, "TabSwitchDone");
+  await BrowserTestUtils.removeTab(gBrowser.selectedTab);
+  await switchDone;
 });
 
-var observer = {
-  reflow(start, end) {
-    // Gather information about the current code path.
-    let path = (new Error().stack).split("\n").slice(1).map(line => {
-      return line.replace(/:\d+:\d+$/, "");
-    }).join("|");
-    let pathWithLineNumbers = (new Error().stack).split("\n").slice(1).join("|");
-
-    // Stack trace is empty. Reflow was triggered by native code.
-    if (path === "") {
-      return;
-    }
-
-    // Check if this is an expected reflow.
-    for (let stack of EXPECTED_REFLOWS) {
-      if (path.startsWith(stack)) {
-        ok(true, "expected uninterruptible reflow '" + stack + "'");
-        return;
-      }
-    }
-
-    ok(false, "unexpected uninterruptible reflow '" + pathWithLineNumbers + "'");
-  },
-
-  reflowInterruptible(start, end) {
-    // We're not interested in interruptible reflows.
-  },
-
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIReflowObserver,
-                                         Ci.nsISupportsWeakReference])
-};
-
-function waitForTransitionEnd() {
-  return new Promise(resolve => {
-    let tab = gBrowser.selectedTab;
-    tab.addEventListener("transitionend", function onEnd(event) {
-      if (event.propertyName === "max-width") {
-        tab.removeEventListener("transitionend", onEnd);
-        resolve();
-      }
-    });
-  });
-}
rename from browser/base/content/test/windows/browser_toolbariconcolor_restyles.js
rename to browser/base/content/test/performance/browser_toolbariconcolor_restyles.js
rename from browser/base/content/test/general/browser_windowopen_reflows.js
rename to browser/base/content/test/performance/browser_windowopen_reflows.js
--- a/browser/base/content/test/general/browser_windowopen_reflows.js
+++ b/browser/base/content/test/performance/browser_windowopen_reflows.js
@@ -1,117 +1,73 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
+/**
+ * WHOA THERE: We should never be adding new things to EXPECTED_REFLOWS. This
+ * is a whitelist that should slowly go away as we improve the performance of
+ * the front-end. Instead of adding more reflows to the whitelist, you should
+ * be modifying your code to avoid the reflow.
+ *
+ * See https://developer.mozilla.org/en-US/Firefox/Performance_best_practices_for_Firefox_fe_engineers
+ * for tips on how to do that.
+ */
 const EXPECTED_REFLOWS = [
-  // handleEvent flushes layout to get the tabstrip width after a resize.
-  "handleEvent@chrome://browser/content/tabbrowser.xml|",
-
-  // Loading a tab causes a reflow.
-  "loadTabs@chrome://browser/content/tabbrowser.xml|" +
-    "loadOneOrMoreURIs@chrome://browser/content/browser.js|" +
-    "_delayedStartup@chrome://browser/content/browser.js|",
+  // Selecting the address bar causes two reflows, unfortunately.
+  [
+    "select@chrome://global/content/bindings/textbox.xml",
+    "focusAndSelectUrlBar@chrome://browser/content/browser.js",
+    "_delayedStartup@chrome://browser/content/browser.js",
+  ],
 
-  // Selecting the address bar causes a reflow.
-  "select@chrome://global/content/bindings/textbox.xml|" +
-    "focusAndSelectUrlBar@chrome://browser/content/browser.js|" +
-    "_delayedStartup@chrome://browser/content/browser.js|",
+  // Selecting the address bar causes two reflows, unfortunately.
+  [
+    "select@chrome://global/content/bindings/textbox.xml",
+    "focusAndSelectUrlBar@chrome://browser/content/browser.js",
+    "_delayedStartup@chrome://browser/content/browser.js",
+  ],
+];
 
-  // Focusing the content area causes a reflow.
-  "_delayedStartup@chrome://browser/content/browser.js|",
-];
+if (Services.appinfo.OS == "Darwin") {
+  // TabsInTitlebar._update causes a reflow on OS X trying to do calculations
+  // since layout info is already dirty. This doesn't seem to happen before
+  // MozAfterPaint on Linux.
+  EXPECTED_REFLOWS.push(
+    [
+      "rect@chrome://browser/content/browser-tabsintitlebar.js",
+      "_update@chrome://browser/content/browser-tabsintitlebar.js",
+      "updateAppearance@chrome://browser/content/browser-tabsintitlebar.js",
+      "handleEvent@chrome://browser/content/tabbrowser.xml",
+    ],
+  );
+}
 
 if (Services.appinfo.OS == "WINNT" || Services.appinfo.OS == "Darwin") {
-  // TabsInTitlebar._update causes a reflow on OS X and Windows trying to do calculations
-  // since layout info is already dirty. This doesn't seem to happen before
-  // MozAfterPaint on Linux.
-  EXPECTED_REFLOWS.push("rect@chrome://browser/content/browser-tabsintitlebar.js|" +
-                          "_update@chrome://browser/content/browser-tabsintitlebar.js|" +
-                          "updateAppearance@chrome://browser/content/browser-tabsintitlebar.js|" +
-                          "handleEvent@chrome://browser/content/tabbrowser.xml|");
-}
-
-if (Services.appinfo.OS == "Darwin") {
-  // _onOverflow causes a reflow getting widths.
-  EXPECTED_REFLOWS.push("_onOverflow@resource:///modules/CustomizableUI.jsm|" +
-                        "init@resource:///modules/CustomizableUI.jsm|" +
-                        "observe@resource:///modules/CustomizableUI.jsm|" +
-                        "_delayedStartup@chrome://browser/content/browser.js|");
-  // Same as above since in packaged builds there are no function names and the resource URI includes "app"
-  EXPECTED_REFLOWS.push("@resource://app/modules/CustomizableUI.jsm|" +
-                          "@resource://app/modules/CustomizableUI.jsm|" +
-                          "@resource://app/modules/CustomizableUI.jsm|" +
-                          "_delayedStartup@chrome://browser/content/browser.js|");
+  EXPECTED_REFLOWS.push(
+    [
+      "handleEvent@chrome://browser/content/tabbrowser.xml",
+      "inferFromText@chrome://browser/content/browser.js",
+      "handleEvent@chrome://browser/content/browser.js",
+    ],
+  );
 }
 
 /*
  * This test ensures that there are no unexpected
  * uninterruptible reflows when opening new windows.
  */
-function test() {
-  waitForExplicitFinish();
-
-  // Add a reflow observer and open a new window
+add_task(async function() {
   let win = OpenBrowserWindow();
-  let docShell = win.QueryInterface(Ci.nsIInterfaceRequestor)
-                    .getInterface(Ci.nsIWebNavigation)
-                    .QueryInterface(Ci.nsIDocShell);
-  docShell.addWeakReflowObserver(observer);
-
-  // Wait until the mozafterpaint event occurs.
-  waitForMozAfterPaint(win, function paintListener() {
-    // Remove reflow observer and clean up.
-    docShell.removeWeakReflowObserver(observer);
-    win.close();
-
-    finish();
-  });
-}
-
-var observer = {
-  reflow(start, end) {
-    // Gather information about the current code path.
-    let stack = new Error().stack;
-    let path = stack.split("\n").slice(1).map(line => {
-      return line.replace(/:\d+:\d+$/, "");
-    }).join("|");
-    let pathWithLineNumbers = (new Error().stack).split("\n").slice(1).join("|");
-
-    // Stack trace is empty. Reflow was triggered by native code.
-    if (path === "") {
-      return;
-    }
 
-    // Check if this is an expected reflow.
-    for (let expectedStack of EXPECTED_REFLOWS) {
-      if (path.startsWith(expectedStack) ||
-          // Accept an empty function name for gBrowserInit._delayedStartup or TabsInTitlebar._update to workaround bug 906578.
-          path.startsWith(expectedStack.replace(/(^|\|)(gBrowserInit\._delayedStartup|TabsInTitlebar\._update)@/, "$1@"))) {
-        ok(true, "expected uninterruptible reflow '" + expectedStack + "'");
-        return;
-      }
-    }
-
-    ok(false, "unexpected uninterruptible reflow '" + pathWithLineNumbers + "'");
-  },
-
-  reflowInterruptible(start, end) {
-    // We're not interested in interruptible reflows.
-  },
+  await withReflowObserver(async function() {
+    let resizeEvent = BrowserTestUtils.waitForEvent(win, "resize");
+    let delayedStartup =
+      TestUtils.topicObserved("browser-delayed-startup-finished",
+                              subject => subject == win);
+    await resizeEvent;
+    await delayedStartup;
+  }, EXPECTED_REFLOWS, win);
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIReflowObserver,
-                                         Ci.nsISupportsWeakReference])
-};
+  await BrowserTestUtils.closeWindow(win);
+});
 
-function waitForMozAfterPaint(win, callback) {
-  let dwu = win.QueryInterface(Ci.nsIInterfaceRequestor)
-               .getInterface(Ci.nsIDOMWindowUtils);
-  let lastTransactionId = dwu.lastTransactionId;
-
-  win.addEventListener("MozAfterPaint", function onEnd(event) {
-    if (event.target != win || event.transactionId <= lastTransactionId)
-      return;
-    win.removeEventListener("MozAfterPaint", onEnd);
-    executeSoon(callback);
-  });
-}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/performance/head.js
@@ -0,0 +1,155 @@
+/**
+ * Async utility function for ensuring that no unexpected uninterruptible
+ * reflows occur during some period of time in a window.
+ *
+ * The helper works by running a JS function before each event is
+ * dispatched that attempts to dirty the layout tree - the idea being
+ * that this puts us in the "worst case scenario" so that any JS
+ * that attempts to query for layout or style information will cause
+ * a reflow to fire. We also dirty the layout tree after each reflow
+ * occurs, for good measure.
+ *
+ * This sounds good in theory, but it's trickier in practice due to
+ * various optimizations in our Layout engine. The default function
+ * for dirtying the layout tree adds a margin to the first element
+ * child it finds in the window to a maximum of 3px, and then goes
+ * back to 0px again and loops.
+ *
+ * This is not sufficient for reflows that we expect to happen within
+ * scrollable frames, as Gecko is able to side-step reflowing the
+ * contents of a scrollable frame if outer frames are dirtied. Because
+ * of this, it's currently possible to override the default node to
+ * dirty with one more appropriate for the test.
+ *
+ * It is also theoretically possible for enough events to fire between
+ * reflows such that the before and after state of the layout tree is
+ * exactly the same, meaning that no reflow is required, which opens
+ * us up to missing expected reflows. This seems to be possible in
+ * theory, but hasn't yet shown up in practice - it's just something
+ * to be aware of.
+ *
+ * Bug 1363361 has been filed for a more reliable way of dirtying layout.
+ *
+ * @param testFn (async function)
+ *        The async function that will exercise the browser activity that is
+ *        being tested for reflows.
+ * @param expectedStacks (Array, optional)
+ *        An Array of Arrays representing stacks.
+ *
+ *        Example:
+ *
+ *        [
+ *          // This reflow is caused by lorem ipsum
+ *          [
+ *            "select@chrome://global/content/bindings/textbox.xml",
+ *            "focusAndSelectUrlBar@chrome://browser/content/browser.js",
+ *            "openLinkIn@chrome://browser/content/utilityOverlay.js",
+ *            "openUILinkIn@chrome://browser/content/utilityOverlay.js",
+ *            "BrowserOpenTab@chrome://browser/content/browser.js",
+ *          ],
+ *
+ *          // This reflow is caused by lorem ipsum
+ *          [
+ *            "get_scrollPosition@chrome://global/content/bindings/scrollbox.xml",
+ *            "_fillTrailingGap@chrome://browser/content/tabbrowser.xml",
+ *            "_handleNewTab@chrome://browser/content/tabbrowser.xml",
+ *            "onxbltransitionend@chrome://browser/content/tabbrowser.xml",
+ *          ],
+ *
+ *        ]
+ *
+ *        Note that line numbers are not included in the stacks.
+ *
+ *        Order of the reflows doesn't matter. Expected reflows that aren't seen
+ *        will cause an assertion failure. When this argument is not passed,
+ *        it defaults to the empty Array, meaning no reflows are expected.
+ * @param window (browser window, optional)
+ *        The browser window to monitor. Defaults to the current window.
+ * @param elemToDirty (DOM node, optional)
+ *        Callers can provide a custom DOM node to change some layout style
+ *        on in the event that the action being tested is occurring within
+ *        a scrollable frame. Otherwise, withReflowObserver defaults to dirtying
+ *        the first element child of the window.
+ */
+async function withReflowObserver(testFn, expectedStacks = [], win = window, elemToDirty) {
+  if (!elemToDirty) {
+    elemToDirty = win.document.firstElementChild;
+  }
+
+  let i = 0;
+  let dirtyFrameFn = (e) => {
+    elemToDirty.style.margin = (++i % 4) + "px";
+  };
+
+  let els = Cc["@mozilla.org/eventlistenerservice;1"]
+              .getService(Ci.nsIEventListenerService);
+
+  // We're going to remove the stacks one by one as we see them so that
+  // we can check for expected, unseen reflows, so let's clone the array.
+  expectedStacks = expectedStacks.slice(0);
+
+  let observer = {
+    reflow(start, end) {
+      // Gather information about the current code path, slicing out the current
+      // frame.
+      let path = (new Error().stack).split("\n").slice(1).map(line => {
+        return line.replace(/:\d+:\d+$/, "");
+      }).join("|");
+
+      let pathWithLineNumbers = (new Error().stack).split("\n").slice(1);
+
+      // Just in case, dirty the frame now that we've reflowed.
+      dirtyFrameFn();
+
+      // Stack trace is empty. Reflow was triggered by native code, which
+      // we ignore.
+      if (path === "") {
+        return;
+      }
+
+      let index = expectedStacks.findIndex(stack => path.startsWith(stack.join("|")));
+
+      if (index != -1) {
+        Assert.ok(true, "expected uninterruptible reflow: '" +
+                  JSON.stringify(pathWithLineNumbers, null, "\t") + "'");
+        expectedStacks.splice(index, 1);
+      } else {
+        Assert.ok(false, "unexpected uninterruptible reflow \n" +
+                         JSON.stringify(pathWithLineNumbers, null, "\t") + "\n");
+      }
+    },
+
+    reflowInterruptible(start, end) {
+      // We're not interested in interruptible reflows.
+    },
+
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsIReflowObserver,
+                                           Ci.nsISupportsWeakReference])
+  };
+
+  let docShell = win.QueryInterface(Ci.nsIInterfaceRequestor)
+                    .getInterface(Ci.nsIWebNavigation)
+                    .QueryInterface(Ci.nsIDocShell);
+  docShell.addWeakReflowObserver(observer);
+
+  els.addListenerForAllEvents(win, dirtyFrameFn, true);
+
+  try {
+    dirtyFrameFn();
+    await testFn();
+  } finally {
+    for (let remainder of expectedStacks) {
+      Assert.ok(false,
+                `Unused expected reflow: ${JSON.stringify(remainder, null, "\t")}.\n` +
+                "This is probably a good thing - just remove it from the " +
+                "expected list.");
+    }
+
+
+    els.removeListenerForAllEvents(win, dirtyFrameFn, true);
+    docShell.removeWeakReflowObserver(observer);
+
+    elemToDirty.style.margin = "";
+  }
+}
+
deleted file mode 100644
--- a/browser/base/content/test/windows/browser.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[DEFAULT]
-[browser_toolbariconcolor_restyles.js]
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -124,20 +124,16 @@ browser.jar:
         content/browser/pageinfo/pageInfo.js          (content/pageinfo/pageInfo.js)
         content/browser/pageinfo/pageInfo.css         (content/pageinfo/pageInfo.css)
         content/browser/pageinfo/pageInfo.xml         (content/pageinfo/pageInfo.xml)
         content/browser/pageinfo/feeds.js             (content/pageinfo/feeds.js)
         content/browser/pageinfo/feeds.xml            (content/pageinfo/feeds.xml)
         content/browser/pageinfo/permissions.js       (content/pageinfo/permissions.js)
         content/browser/pageinfo/security.js          (content/pageinfo/security.js)
         content/browser/robot.ico                     (content/robot.ico)
-        content/browser/sync/aboutSyncTabs.xul        (content/sync/aboutSyncTabs.xul)
-        content/browser/sync/aboutSyncTabs.js         (content/sync/aboutSyncTabs.js)
-        content/browser/sync/aboutSyncTabs.css        (content/sync/aboutSyncTabs.css)
-        content/browser/sync/aboutSyncTabs-bindings.xml  (content/sync/aboutSyncTabs-bindings.xml)
         content/browser/safeMode.css                  (content/safeMode.css)
         content/browser/safeMode.js                   (content/safeMode.js)
         content/browser/safeMode.xul                  (content/safeMode.xul)
         content/browser/sanitize.js                   (content/sanitize.js)
         content/browser/sanitize.xul                  (content/sanitize.xul)
         content/browser/sanitizeDialog.js             (content/sanitizeDialog.js)
         content/browser/sanitizeDialog.css            (content/sanitizeDialog.css)
         content/browser/contentSearchUI.js            (content/contentSearchUI.js)
--- a/browser/base/moz.build
+++ b/browser/base/moz.build
@@ -17,33 +17,33 @@ MOCHITEST_CHROME_MANIFESTS += [
 BROWSER_CHROME_MANIFESTS += [
     'content/test/alerts/browser.ini',
     'content/test/captivePortal/browser.ini',
     'content/test/contextMenu/browser.ini',
     'content/test/forms/browser.ini',
     'content/test/general/browser.ini',
     'content/test/newtab/browser.ini',
     'content/test/pageinfo/browser.ini',
+    'content/test/performance/browser.ini',
     'content/test/permissions/browser.ini',
     'content/test/plugins/browser.ini',
     'content/test/popupNotifications/browser.ini',
     'content/test/popups/browser.ini',
     'content/test/referrer/browser.ini',
     'content/test/sidebar/browser.ini',
     'content/test/siteIdentity/browser.ini',
     'content/test/social/browser.ini',
     'content/test/static/browser.ini',
     'content/test/sync/browser.ini',
     'content/test/tabcrashed/browser.ini',
     'content/test/tabPrompts/browser.ini',
     'content/test/tabs/browser.ini',
     'content/test/urlbar/browser.ini',
     'content/test/webextensions/browser.ini',
     'content/test/webrtc/browser.ini',
-    'content/test/windows/browser.ini',
 ]
 
 if CONFIG['MOZ_UPDATER']:
     BROWSER_CHROME_MANIFESTS += ['content/test/appUpdate/browser.ini']
 
 DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION']
 DEFINES['MOZ_APP_VERSION_DISPLAY'] = CONFIG['MOZ_APP_VERSION_DISPLAY']
 
--- a/browser/components/about/AboutRedirector.cpp
+++ b/browser/components/about/AboutRedirector.cpp
@@ -75,18 +75,16 @@ static const RedirEntry kRedirMap[] = {
     nsIAboutModule::ALLOW_SCRIPT },
   { "searchreset", "chrome://browser/content/search/searchReset.xhtml",
     nsIAboutModule::ALLOW_SCRIPT |
     nsIAboutModule::HIDE_FROM_ABOUTABOUT },
   { "sessionrestore", "chrome://browser/content/aboutSessionRestore.xhtml",
     nsIAboutModule::ALLOW_SCRIPT },
   { "welcomeback", "chrome://browser/content/aboutWelcomeBack.xhtml",
     nsIAboutModule::ALLOW_SCRIPT },
-  { "sync-tabs", "chrome://browser/content/sync/aboutSyncTabs.xul",
-    nsIAboutModule::ALLOW_SCRIPT },
   // Linkable because of indexeddb use (bug 1228118)
   { "home", "chrome://browser/content/abouthome/aboutHome.xhtml",
     nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
     nsIAboutModule::URI_MUST_LOAD_IN_CHILD |
     nsIAboutModule::ALLOW_SCRIPT |
     nsIAboutModule::MAKE_LINKABLE |
     nsIAboutModule::ENABLE_INDEXED_DB },
   // the newtab's actual URL will be determined when the channel is created
--- a/browser/components/build/nsModule.cpp
+++ b/browser/components/build/nsModule.cpp
@@ -92,17 +92,16 @@ static const mozilla::Module::ContractID
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "tabcrashed", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "feeds", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "privatebrowsing", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "rights", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "robots", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "searchreset", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "sessionrestore", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "welcomeback", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
-    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "sync-tabs", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "home", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "newtab", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "preferences", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "downloads", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "accounts", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
 #ifdef MOZ_SERVICES_HEALTHREPORT
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "healthreport", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
 #endif
--- a/browser/components/contextualidentity/test/browser/browser_eme.js
+++ b/browser/components/contextualidentity/test/browser/browser_eme.js
@@ -98,17 +98,17 @@ add_task(async function test() {
   // Generate the key info for the default container.
   let keyInfo = generateKeyInfo(TESTKEY);
 
   // Update the media key for the default container.
   let result = await ContentTask.spawn(defaultContainer.browser, keyInfo, async function(aKeyInfo) {
     let access = await content.navigator.requestMediaKeySystemAccess("org.w3.clearkey",
                                                                      [{
                                                                        initDataTypes: [aKeyInfo.initDataType],
-                                                                       videoCapabilities: [{contentType: "video/webm"}],
+                                                                       videoCapabilities: [{contentType: 'video/webm; codecs="vp9"'}],
                                                                        sessionTypes: ["persistent-license"],
                                                                        persistentState: "required",
                                                                      }]);
     let mediaKeys = await access.createMediaKeys();
     let session = mediaKeys.createSession(aKeyInfo.sessionType);
     let res = {};
 
     // Insert the media key.
@@ -151,17 +151,17 @@ add_task(async function test() {
 
   // Open a tab with personal container.
   let personalContainer = await openTabInUserContext(TEST_URL + "empty_file.html", USER_ID_PERSONAL);
 
   await ContentTask.spawn(personalContainer.browser, keyInfo, async function(aKeyInfo) {
     let access = await content.navigator.requestMediaKeySystemAccess("org.w3.clearkey",
                                                                      [{
                                                                        initDataTypes: [aKeyInfo.initDataType],
-                                                                       videoCapabilities: [{contentType: "video/webm"}],
+                                                                       videoCapabilities: [{contentType: 'video/webm; codecs="vp9"'}],
                                                                        sessionTypes: ["persistent-license"],
                                                                        persistentState: "required",
                                                                      }]);
     let mediaKeys = await access.createMediaKeys();
     let session = mediaKeys.createSession(aKeyInfo.sessionType);
 
     // First, load the session to check that mediakeys do not share with
     // default container.
--- a/browser/components/contextualidentity/test/browser/browser_forgetAPI_EME_forgetThisSite.js
+++ b/browser/components/contextualidentity/test/browser/browser_forgetAPI_EME_forgetThisSite.js
@@ -93,17 +93,17 @@ async function setupEMEKey(browser) {
   // Generate the key info.
   let keyInfo = generateKeyInfo(TEST_EME_KEY);
 
   // Setup the EME key.
   let result = await ContentTask.spawn(browser, keyInfo, async function(aKeyInfo) {
     let access = await content.navigator.requestMediaKeySystemAccess("org.w3.clearkey",
                                                                      [{
                                                                        initDataTypes: [aKeyInfo.initDataType],
-                                                                       videoCapabilities: [{contentType: "video/webm"}],
+                                                                       videoCapabilities: [{contentType: 'video/webm; codecs="vp9"'}],
                                                                        sessionTypes: ["persistent-license"],
                                                                        persistentState: "required",
                                                                      }]);
     let mediaKeys = await access.createMediaKeys();
     let session = mediaKeys.createSession(aKeyInfo.sessionType);
     let res = {};
 
     // Insert the EME key.
@@ -148,17 +148,17 @@ async function checkEMEKey(browser, emeS
   // Generate the key info.
   let keyInfo = generateKeyInfo(TEST_EME_KEY);
   keyInfo.sessionId = emeSessionId;
 
   await ContentTask.spawn(browser, keyInfo, async function(aKeyInfo) {
     let access = await content.navigator.requestMediaKeySystemAccess("org.w3.clearkey",
                                                                      [{
                                                                        initDataTypes: [aKeyInfo.initDataType],
-                                                                       videoCapabilities: [{contentType: "video/webm"}],
+                                                                       videoCapabilities: [{contentType: 'video/webm; codecs="vp9"'}],
                                                                        sessionTypes: ["persistent-license"],
                                                                        persistentState: "required",
                                                                      }]);
     let mediaKeys = await access.createMediaKeys();
     let session = mediaKeys.createSession(aKeyInfo.sessionType);
 
     // First, load the session with the sessionId.
     await session.load(aKeyInfo.sessionId);
--- a/browser/components/extensions/ExtensionPopups.jsm
+++ b/browser/components/extensions/ExtensionPopups.jsm
@@ -125,19 +125,21 @@ class BasePopup {
         this.browser.remove();
       }
 
       if (this.viewNode) {
         this.viewNode.removeEventListener(this.DESTROY_EVENT, this);
         this.viewNode.style.maxHeight = "";
       }
 
-      if (this.panel) {
-        this.panel.style.removeProperty("--arrowpanel-background");
-        this.panel.style.removeProperty("--panel-arrow-image-vertical");
+      let {panel} = this;
+      if (panel) {
+        panel.style.removeProperty("--arrowpanel-background");
+        panel.style.removeProperty("--panel-arrow-image-vertical");
+        panel.removeAttribute("remote");
       }
 
       this.browser = null;
       this.viewNode = null;
     });
   }
 
   destroyBrowser(browser, finalize = false) {
@@ -372,16 +374,19 @@ class PanelPopup extends BasePopup {
     let document = imageNode.ownerDocument;
 
     let panel = document.createElement("panel");
     panel.setAttribute("id", makeWidgetId(extension.id) + "-panel");
     panel.setAttribute("class", "browser-extension-panel");
     panel.setAttribute("tabspecific", "true");
     panel.setAttribute("type", "arrow");
     panel.setAttribute("role", "group");
+    if (extension.remote) {
+      panel.setAttribute("remote", "true");
+    }
 
     document.getElementById("mainPopupSet").appendChild(panel);
 
     super(extension, panel, popupURL, browserStyle);
 
     this.contentReady.then(() => {
       panel.openPopup(imageNode, "bottomcenter topright", 0, 0, false, false);
 
@@ -445,16 +450,20 @@ class ViewPopup extends BasePopup {
    *        Resolves when the browser is ready. Resolves to `false` if the
    *        browser was destroyed before it was fully loaded, and the popup
    *        should be closed, or `true` otherwise.
    */
   async attach(viewNode) {
     this.viewNode = viewNode;
     this.viewNode.addEventListener(this.DESTROY_EVENT, this);
 
+    if (this.extension.remote) {
+      this.panel.setAttribute("remote", "true");
+    }
+
     // Wait until the browser element is fully initialized, and give it at least
     // a short grace period to finish loading its initial content, if necessary.
     //
     // In practice, the browser that was created by the mousdown handler should
     // nearly always be ready by this point.
     await Promise.all([
       this.browserReady,
       Promise.race([
--- a/browser/components/extensions/ext-contextMenus.js
+++ b/browser/components/extensions/ext-contextMenus.js
@@ -142,16 +142,23 @@ var gMenuBuilder = {
   },
 
   removeTopLevelMenuIfNeeded(element) {
     // If there is only one visible top level element we don't need the
     // root menu element for the extension.
     let menuPopup = element.firstChild;
     if (menuPopup && menuPopup.childNodes.length == 1) {
       let onlyChild = menuPopup.firstChild;
+
+      // Keep single checkbox items in the submenu on Linux since
+      // the extension icon overlaps the checkbox otherwise.
+      if (AppConstants.platform === "linux" && onlyChild.getAttribute("type") === "checkbox") {
+        return element;
+      }
+
       onlyChild.remove();
       return onlyChild;
     }
 
     return element;
   },
 
   buildSingleElement(item, contextData) {
--- a/browser/components/extensions/test/browser/browser_ext_contextMenus_checkboxes.js
+++ b/browser/components/extensions/test/browser/browser_ext_contextMenus_checkboxes.js
@@ -19,36 +19,64 @@ add_task(async function() {
         browser.test.sendMessage("contextmenus-click", info);
       });
 
       browser.contextMenus.create({
         title: "Checkbox",
         type: "checkbox",
       });
 
-      browser.contextMenus.create({
-        type: "separator",
-      });
+      browser.test.sendMessage("single-contextmenu-item-added");
+
+      browser.test.onMessage.addListener(msg => {
+        if (msg !== "add-additional-menu-items") {
+          return;
+        }
+
+        browser.contextMenus.create({
+          type: "separator",
+        });
 
-      browser.contextMenus.create({
-        title: "Checkbox",
-        type: "checkbox",
-        checked: true,
-      });
+        browser.contextMenus.create({
+          title: "Checkbox",
+          type: "checkbox",
+          checked: true,
+        });
 
-      browser.contextMenus.create({
-        title: "Checkbox",
-        type: "checkbox",
+        browser.contextMenus.create({
+          title: "Checkbox",
+          type: "checkbox",
+        });
+
+        browser.test.notifyPass("contextmenus-checkboxes");
       });
-
-      browser.test.notifyPass("contextmenus-checkboxes");
     },
   });
 
   await extension.startup();
+
+  await extension.awaitMessage("single-contextmenu-item-added");
+
+  async function testSingleCheckboxItem() {
+    let extensionMenuRoot = await openExtensionContextMenu();
+
+    // On Linux, the single menu item should be contained in a submenu.
+    if (AppConstants.platform === "linux") {
+      let items = extensionMenuRoot.getElementsByAttribute("type", "checkbox");
+      is(items.length, 1, "single checkbox should be in the submenu on Linux");
+      await closeContextMenu();
+    } else {
+      is(extensionMenuRoot, null, "there should be no submenu for a single checkbox item");
+      await closeContextMenu();
+    }
+  }
+
+  await testSingleCheckboxItem();
+
+  extension.sendMessage("add-additional-menu-items");
   await extension.awaitFinish("contextmenus-checkboxes");
 
   function confirmCheckboxStates(extensionMenuRoot, expectedStates) {
     let checkboxItems = extensionMenuRoot.getElementsByAttribute("type", "checkbox");
 
     is(checkboxItems.length, 3, "there should be 3 checkbox items in the context menu");
 
     is(checkboxItems[0].hasAttribute("checked"), expectedStates[0], `checkbox item 1 has state (checked=${expectedStates[0]})`);
--- a/browser/components/extensions/test/browser/browser_ext_getViews.js
+++ b/browser/components/extensions/test/browser/browser_ext_getViews.js
@@ -9,27 +9,22 @@ function genericChecker() {
     kind = "popup";
   } else if (path.indexOf("tab") != -1) {
     kind = "tab";
   }
   window.kind = kind;
 
   browser.test.onMessage.addListener((msg, ...args) => {
     if (msg == kind + "-check-views") {
-      let windowId = args[0];
       let counts = {
-        "background": 0,
-        "tab": 0,
-        "popup": 0,
-        "kind": 0,
-        "window": 0,
+        background: 0,
+        tab: 0,
+        popup: 0,
+        kind: 0,
       };
-      if (Number.isInteger(windowId)) {
-        counts.window = browser.extension.getViews({windowId: windowId}).length;
-      }
       if (kind !== "background") {
         counts.kind = browser.extension.getViews({type: kind}).length;
       }
       let views = browser.extension.getViews();
       let background;
       for (let i = 0; i < views.length; i++) {
         let view = views[i];
         browser.test.assertTrue(view.kind in counts, "view type is valid");
@@ -43,18 +38,23 @@ function genericChecker() {
       if (background) {
         browser.runtime.getBackgroundPage().then(view => {
           browser.test.assertEq(background, view, "runtime.getBackgroundPage() is correct");
           browser.test.sendMessage("counts", counts);
         });
       } else {
         browser.test.sendMessage("counts", counts);
       }
+    } else if (msg == kind + "-getViews-with-filter") {
+      let filter = args[0];
+      let count = browser.extension.getViews(filter).length;
+      browser.test.sendMessage("getViews-count", count);
     } else if (msg == kind + "-open-tab") {
-      browser.tabs.create({windowId: args[0], url: browser.runtime.getURL("tab.html")});
+      browser.tabs.create({windowId: args[0], url: browser.runtime.getURL("tab.html")})
+        .then((tab) => browser.test.sendMessage("opened-tab", tab.id));
     } else if (msg == kind + "-close-tab") {
       browser.tabs.query({
         windowId: args[0],
       }, tabs => {
         let tab = tabs.find(tab => tab.url.indexOf("tab.html") != -1);
         browser.tabs.remove(tab.id, () => {
           browser.test.sendMessage("closed");
         });
@@ -107,38 +107,50 @@ add_task(async function() {
   let {Management: {global: {windowTracker}}} = Cu.import("resource://gre/modules/Extension.jsm", {});
 
   let winId1 = windowTracker.getId(win1);
   let winId2 = windowTracker.getId(win2);
 
   async function openTab(winId) {
     extension.sendMessage("background-open-tab", winId);
     await extension.awaitMessage("tab-ready");
+    return extension.awaitMessage("opened-tab");
   }
 
-  async function checkViews(kind, tabCount, popupCount, kindCount, windowId = undefined, windowCount = 0) {
-    extension.sendMessage(kind + "-check-views", windowId);
+  async function checkViews(kind, tabCount, popupCount, kindCount) {
+    extension.sendMessage(kind + "-check-views");
     let counts = await extension.awaitMessage("counts");
     is(counts.background, 1, "background count correct");
     is(counts.tab, tabCount, "tab count correct");
     is(counts.popup, popupCount, "popup count correct");
     is(counts.kind, kindCount, "count for type correct");
-    is(counts.window, windowCount, "count for window correct");
+  }
+
+  async function checkViewsWithFilter(filter, expectedCount) {
+    extension.sendMessage("background-getViews-with-filter", filter);
+    let count = await extension.awaitMessage("getViews-count");
+    is(count, expectedCount, `count for ${JSON.stringify(filter)} correct`);
   }
 
   await checkViews("background", 0, 0, 0);
+  await checkViewsWithFilter({windowId: -1}, 1);
+  await checkViewsWithFilter({tabId: -1}, 1);
 
-  await openTab(winId1);
+  let tabId1 = await openTab(winId1);
 
-  await checkViews("background", 1, 0, 0, winId1, 1);
+  await checkViews("background", 1, 0, 0);
   await checkViews("tab", 1, 0, 1);
+  await checkViewsWithFilter({windowId: winId1}, 1);
+  await checkViewsWithFilter({tabId: tabId1}, 1);
 
-  await openTab(winId2);
+  let tabId2 = await openTab(winId2);
 
-  await checkViews("background", 2, 0, 0, winId2, 1);
+  await checkViews("background", 2, 0, 0);
+  await checkViewsWithFilter({windowId: winId2}, 1);
+  await checkViewsWithFilter({tabId: tabId2}, 1);
 
   async function triggerPopup(win, callback) {
     await clickBrowserAction(extension, win);
     await awaitExtensionPanel(extension, win);
 
     await extension.awaitMessage("popup-ready");
 
     await callback();
@@ -148,28 +160,34 @@ add_task(async function() {
 
   // The popup occasionally closes prematurely if we open it immediately here.
   // I'm not sure what causes it to close (it's something internal, and seems to
   // be focus-related, but it's not caused by JS calling hidePopup), but even a
   // short timeout seems to consistently fix it.
   await new Promise(resolve => win1.setTimeout(resolve, 10));
 
   await triggerPopup(win1, async function() {
-    await checkViews("background", 2, 1, 0, winId1, 2);
+    await checkViews("background", 2, 1, 0);
     await checkViews("popup", 2, 1, 1);
+    await checkViewsWithFilter({windowId: winId1}, 2);
+    await checkViewsWithFilter({type: "popup", tabId: -1}, 1);
   });
 
   await triggerPopup(win2, async function() {
-    await checkViews("background", 2, 1, 0, winId2, 2);
+    await checkViews("background", 2, 1, 0);
     await checkViews("popup", 2, 1, 1);
+    await checkViewsWithFilter({windowId: winId2}, 2);
+    await checkViewsWithFilter({type: "popup", tabId: -1}, 1);
   });
 
   info("checking counts after popups");
 
-  await checkViews("background", 2, 0, 0, winId1, 1);
+  await checkViews("background", 2, 0, 0);
+  await checkViewsWithFilter({windowId: winId1}, 1);
+  await checkViewsWithFilter({tabId: -1}, 1);
 
   info("closing one tab");
 
   extension.sendMessage("background-close-tab", winId1);
   await extension.awaitMessage("closed");
 
   info("one tab closed, one remains");
 
--- a/browser/components/migration/tests/marionette/test_refresh_firefox.py
+++ b/browser/components/migration/tests/marionette/test_refresh_firefox.py
@@ -165,45 +165,32 @@ class TestFirefoxRefresh(MarionetteTestC
         titleInBookmarks = self.marionette.execute_script("""
           let url = arguments[0];
           let bookmarkIds = PlacesUtils.bookmarks.getBookmarkIdsForURI(makeURI(url), {}, {});
           return bookmarkIds.length == 1 ? PlacesUtils.bookmarks.getItemTitle(bookmarkIds[0]) : "";
         """, script_args=[self._bookmarkURL])
         self.assertEqual(titleInBookmarks, self._bookmarkText)
 
     def checkHistory(self):
-        historyResults = self.runAsyncCode("""
-          let placeInfos = [];
-          PlacesUtils.asyncHistory.getPlacesInfo(makeURI(arguments[0]), {
-            handleError(resultCode, place) {
-              placeInfos = null;
-              marionetteScriptFinished("Unexpected error in fetching visit: " + resultCode);
-            },
-            handleResult(placeInfo) {
-              placeInfos.push(placeInfo);
-            },
-            handleCompletion() {
-              if (placeInfos) {
-                if (!placeInfos.length) {
-                  marionetteScriptFinished("No visits found");
-                } else {
-                  marionetteScriptFinished(placeInfos);
-                }
-              }
-            },
+        historyResult = self.runAsyncCode("""
+          PlacesUtils.history.fetch(arguments[0]).then(pageInfo => {
+            if (!pageInfo) {
+              marionetteScriptFinished("No visits found");
+            } else {
+              marionetteScriptFinished(pageInfo);
+            }
+          }).catch(e => {
+            marionetteScriptFinished("Unexpected error in fetching page: " + e);
           });
         """, script_args=[self._historyURL])
-        if type(historyResults) == str:
-            self.fail(historyResults)
+        if type(historyResult) == str:
+            self.fail(historyResult)
             return
 
-        historyCount = len(historyResults)
-        self.assertEqual(historyCount, 1, "Should have exactly 1 entry for URI, got %d" % historyCount)
-        if historyCount == 1:
-            self.assertEqual(historyResults[0]['title'], self._historyTitle)
+        self.assertEqual(historyResult['title'], self._historyTitle)
 
     def checkFormHistory(self):
         formFieldResults = self.runAsyncCode("""
           let results = [];
           global.FormHistory.search(["value"], {fieldname: arguments[0]}, {
             handleError(error) {
               results = error;
             },
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -29,17 +29,17 @@ XPCOMUtils.defineLazyGetter(this, "Weave
           DateTimePickerHelper:false, DirectoryLinksProvider:false,
           ExtensionsUI:false, Feeds:false,
           FileUtils:false, FormValidationHandler:false, Integration:false,
           LightweightThemeManager:false, LoginHelper:false, LoginManagerParent:false,
           NetUtil:false, NewTabUtils:false, OS:false,
           PageThumbs:false, PdfJs:false, PermissionUI:false, PlacesBackups:false,
           PlacesUtils:false, PluralForm:false, PrivateBrowsingUtils:false,
           ProcessHangMonitor:false, ReaderParent:false, RecentWindow:false,
-          RemotePrompt:false, SelfSupportBackend:false, SessionStore:false,
+          RemotePrompt:false, SessionStore:false,
           ShellService:false, SimpleServiceDiscovery:false, TabCrashHandler:false,
           Task:false, UITour:false, WebChannel:false,
           WindowsRegistry:false, webrtcUI:false, UserAgentOverrides: false */
 
 /**
  * IF YOU ADD OR REMOVE FROM THIS LIST, PLEASE UPDATE THE LIST ABOVE AS WELL.
  * XXX Bug 1325373 is for making eslint detect these automatically.
  */
@@ -78,17 +78,16 @@ let initializedModules = {};
   ["PlacesBackups", "resource://gre/modules/PlacesBackups.jsm"],
   ["PlacesUtils", "resource://gre/modules/PlacesUtils.jsm"],
   ["PluralForm", "resource://gre/modules/PluralForm.jsm"],
   ["PrivateBrowsingUtils", "resource://gre/modules/PrivateBrowsingUtils.jsm"],
   ["ProcessHangMonitor", "resource:///modules/ProcessHangMonitor.jsm"],
   ["ReaderParent", "resource:///modules/ReaderParent.jsm"],
   ["RecentWindow", "resource:///modules/RecentWindow.jsm"],
   ["RemotePrompt", "resource:///modules/RemotePrompt.jsm"],
-  ["SelfSupportBackend", "resource:///modules/SelfSupportBackend.jsm", "init"],
   ["SessionStore", "resource:///modules/sessionstore/SessionStore.jsm"],
   ["ShellService", "resource:///modules/ShellService.jsm"],
   ["SimpleServiceDiscovery", "resource://gre/modules/SimpleServiceDiscovery.jsm"],
   ["TabCrashHandler", "resource:///modules/ContentCrashHandlers.jsm"],
   ["Task", "resource://gre/modules/Task.jsm"],
   ["UITour", "resource:///modules/UITour.jsm"],
   ["WebChannel", "resource://gre/modules/WebChannel.jsm"],
   ["WindowsRegistry", "resource://gre/modules/WindowsRegistry.jsm"],
@@ -121,20 +120,16 @@ XPCOMUtils.defineLazyGetter(this, "gBran
 
 XPCOMUtils.defineLazyGetter(this, "gBrowserBundle", function() {
   return Services.strings.createBundle("chrome://browser/locale/browser.properties");
 });
 
 const global = this;
 
 const listeners = {
-  observers: {
-    "sessionstore-windows-restored": ["SelfSupportBackend"],
-  },
-
   ppmm: {
     // PLEASE KEEP THIS LIST IN SYNC WITH THE LISTENERS ADDED IN ContentPrefServiceParent.init
     "ContentPrefs:FunctionCall": ["ContentPrefServiceParent"],
     "ContentPrefs:AddObserverForName": ["ContentPrefServiceParent"],
     "ContentPrefs:RemoveObserverForName": ["ContentPrefServiceParent"],
     // PLEASE KEEP THIS LIST IN SYNC WITH THE LISTENERS ADDED IN ContentPrefServiceParent.init
     "FeedConverter:addLiveBookmark": ["Feeds"],
     "WCCR:setAutoHandler": ["Feeds"],
@@ -166,43 +161,29 @@ const listeners = {
     "rtcpeer:CancelRequest": ["webrtcUI"],
     "rtcpeer:Request": ["webrtcUI"],
     "webrtc:CancelRequest": ["webrtcUI"],
     "webrtc:Request": ["webrtcUI"],
     "webrtc:StopRecording": ["webrtcUI"],
     "webrtc:UpdateBrowserIndicators": ["webrtcUI"],
   },
 
-  observe(subject, topic, data) {
-    for (let module of this.observers[topic]) {
-      try {
-        this[module].observe(subject, topic, data);
-      } catch (e) {
-        Cu.reportError(e);
-      }
-    }
-  },
-
   receiveMessage(modules, data) {
     let val;
     for (let module of modules[data.name]) {
       try {
         val = global[module].receiveMessage(data) || val;
       } catch (e) {
         Cu.reportError(e);
       }
     }
     return val;
   },
 
   init() {
-    for (let observer of Object.keys(this.observers)) {
-      Services.obs.addObserver(this, observer);
-    }
-
     let receiveMessageMM = this.receiveMessage.bind(this, this.mm);
     for (let message of Object.keys(this.mm)) {
       Services.mm.addMessageListener(message, receiveMessageMM);
     }
 
     let receiveMessagePPMM = this.receiveMessage.bind(this, this.ppmm);
     for (let message of Object.keys(this.ppmm)) {
       Services.ppmm.addMessageListener(message, receiveMessagePPMM);
--- a/browser/components/places/content/bookmarkProperties.js
+++ b/browser/components/places/content/bookmarkProperties.js
@@ -655,17 +655,17 @@ var BookmarkPropertiesPanel = {
       info.feedUrl = this._feedURI;
       if (this._siteURI)
         info.siteUrl = this._siteURI;
 
       itemGuid = await PlacesTransactions.NewLivemark(info).transact();
     } else if (this._itemType == BOOKMARK_FOLDER) {
       itemGuid = await PlacesTransactions.NewFolder(info).transact();
       for (let uri of this._URIs) {
-        let placeInfo = await PlacesUtils.promisePlaceInfo(uri);
+        let placeInfo = await PlacesUtils.history.fetch(uri);
         let title = placeInfo ? placeInfo.title : "";
         await PlacesTransactions.transact({ parentGuid: itemGuid, uri, title });
       }
     } else {
       throw new Error(`unexpected value for _itemType:  ${this._itemType}`);
     }
 
     this._itemGuid = itemGuid;
--- a/browser/components/sessionstore/SessionStore.jsm
+++ b/browser/components/sessionstore/SessionStore.jsm
@@ -2641,17 +2641,17 @@ var SessionStoreInternal = {
       }
     }
 
     let activePageData = tabData.entries[tabData.index - 1] || null;
 
     // If the page has a title, set it.
     if (activePageData) {
       if (activePageData.title) {
-        win.gBrowser.setInitialTabTitle(tab, activePageData.title);
+        win.gBrowser.setInitialTabTitle(tab, activePageData.title, { isContentTitle: true });
       } else if (activePageData.url != "about:blank") {
         win.gBrowser.setInitialTabTitle(tab, activePageData.url);
       }
     }
 
     // Restore the tab icon.
     if ("image" in tabData) {
       // Use the serialized contentPrincipal with the new icon load.
--- a/browser/components/sessionstore/test/browser_tab_label_during_restore.js
+++ b/browser/components/sessionstore/test/browser_tab_label_during_restore.js
@@ -46,40 +46,44 @@ add_task(async function() {
 
   await browserLoadedPromise;
   const CONTENT_TITLE = firstTab.linkedBrowser.contentTitle;
   is(firstTab.linkedBrowser.currentURI.spec, TEST_URL, "correct URL loaded in first tab");
   is(typeof CONTENT_TITLE, "string", "content title is a string");
   isnot(CONTENT_TITLE.length, 0, "content title isn't empty");
   isnot(CONTENT_TITLE, TEST_URL, "content title is different from the URL");
   is(firstTab.label, CONTENT_TITLE, "first tab displays content title");
+  ok(document.title.startsWith(CONTENT_TITLE), "title bar displays content title");
   ok(secondTab.hasAttribute("pending"), "second tab is pending");
   is(secondTab.label, TEST_URL, "second tab displays URL as its title");
 
   info("selecting the second tab");
   let checkLabelChangeCount = observeLabelChanges(secondTab);
   browserLoadedPromise = BrowserTestUtils.browserLoaded(secondTab.linkedBrowser, false, TEST_URL);
   gBrowser.selectedTab = secondTab;
   await browserLoadedPromise;
   ok(!secondTab.hasAttribute("pending"), "second tab isn't pending anymore");
-  is(gBrowser.selectedTab.label, CONTENT_TITLE, "second tab displays content title");
+  is(secondTab.label, CONTENT_TITLE, "second tab displays content title");
+  ok(document.title.startsWith(CONTENT_TITLE), "title bar displays content title");
   checkLabelChangeCount(1);
 
   info("restoring the modified browser state");
   await TabStateFlusher.flushWindow(window);
   await promiseBrowserState(SessionStore.getBrowserState());
   [firstTab, secondTab] = gBrowser.tabs;
   is(secondTab, gBrowser.selectedTab, "second tab is selected after restoring");
+  ok(document.title.startsWith(CONTENT_TITLE), "title bar displays content title");
   ok(firstTab.hasAttribute("pending"), "first tab is pending after restoring");
   is(firstTab.label, CONTENT_TITLE, "first tab displays content title in pending state");
 
   info("selecting the first tab");
   checkLabelChangeCount = observeLabelChanges(firstTab);
   let tabContentRestored = TestUtils.topicObserved("sessionstore-debug-tab-restored");
   gBrowser.selectedTab = firstTab;
+  ok(document.title.startsWith(CONTENT_TITLE), "title bar displays content title");
   await tabContentRestored;
   ok(!firstTab.hasAttribute("pending"), "first tab isn't pending anymore");
   checkLabelChangeCount(0);
   is(firstTab.label, CONTENT_TITLE, "first tab displays content title after restoring content");
 
   await promiseBrowserState(BACKUP_STATE);
 });
 
--- a/browser/config/mozconfigs/linux64/debug-static-analysis-clang
+++ b/browser/config/mozconfigs/linux64/debug-static-analysis-clang
@@ -2,16 +2,19 @@ MOZ_AUTOMATION_BUILD_SYMBOLS=0
 MOZ_AUTOMATION_PACKAGE_TESTS=0
 MOZ_AUTOMATION_L10N_CHECK=0
 
 . "$topsrcdir/build/mozconfig.common"
 
 ac_add_options --enable-debug
 ac_add_options --enable-dmd
 
+# Disable stylo until bug 1356926 is fixed and we have >= llvm39 on centos.
+ac_add_options --disable-stylo
+
 # Use Clang as specified in manifest
 export CC="$topsrcdir/clang/bin/clang"
 export CXX="$topsrcdir/clang/bin/clang++"
 
 # Add the static checker
 ac_add_options --enable-clang-plugin
 
 . "$topsrcdir/build/unix/mozconfig.stdcxx"
--- a/browser/config/mozconfigs/linux64/opt-static-analysis-clang
+++ b/browser/config/mozconfigs/linux64/opt-static-analysis-clang
@@ -1,16 +1,19 @@
 MOZ_AUTOMATION_BUILD_SYMBOLS=0
 MOZ_AUTOMATION_PACKAGE_TESTS=0
 MOZ_AUTOMATION_L10N_CHECK=0
 
 . "$topsrcdir/build/mozconfig.common"
 
 ac_add_options --enable-dmd
 
+# Disable stylo until bug 1356926 is fixed and we have >= llvm39 on centos.
+ac_add_options --disable-stylo
+
 # Use Clang as specified in manifest
 CC="$topsrcdir/clang/bin/clang"
 CXX="$topsrcdir/clang/bin/clang++"
 
 # Add the static checker
 ac_add_options --enable-clang-plugin
 
 . "$topsrcdir/build/unix/mozconfig.stdcxx"
--- a/browser/config/mozconfigs/linux64/stylo
+++ b/browser/config/mozconfigs/linux64/stylo
@@ -1,5 +1,3 @@
 . "$topsrcdir/browser/config/mozconfigs/linux64/nightly"
 
-export LLVM_CONFIG="${TOOLTOOL_DIR}/clang/bin/llvm-config"
-
 ac_add_options --enable-stylo
--- a/browser/config/mozconfigs/linux64/stylo-debug
+++ b/browser/config/mozconfigs/linux64/stylo-debug
@@ -1,5 +1,3 @@
 . "$topsrcdir/browser/config/mozconfigs/linux64/debug"
 
-export LLVM_CONFIG="${TOOLTOOL_DIR}/clang/bin/llvm-config"
-
 ac_add_options --enable-stylo
--- a/browser/config/mozconfigs/linux64/valgrind
+++ b/browser/config/mozconfigs/linux64/valgrind
@@ -1,10 +1,14 @@
 . $topsrcdir/browser/config/mozconfigs/linux64/nightly
 
 ac_add_options --enable-valgrind
 ac_add_options --disable-jemalloc
 ac_add_options --disable-install-strip
 ac_add_options --disable-gtest-in-build
 
+# Rust code gives false positives that we have not entirely suppressed yet.
+# Bug 1365915 tracks fixing these.
+ac_add_options --disable-stylo
+
 # Include the override mozconfig again (even though the above includes it)
 # since it's supposed to override everything.
 . "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/tooltool-manifests/linux32/releng.manifest
+++ b/browser/config/tooltool-manifests/linux32/releng.manifest
@@ -26,10 +26,18 @@
   {
     "version": "sccache rev d3aa1116844b50c03015266d2f48235509fa7deb",
     "algorithm": "sha512",
     "visibility": "public",
     "filename": "sccache2.tar.xz",
     "unpack": true,
     "digest": "fde0128b9a4df74f268f9d45748534d0314db0467ae22e36101df4a5374c36bb8676514e8b70254fb2e6f2a2d1224ff7ce498305223035d5f1e7e306fda2f5d5",
     "size": 2179220
+  },
+  {
+    "version": "clang + llvm 3.9.0, built from SVN r290136",
+    "size": 166261192,
+    "digest": "52f3fc23f0f5c98050f8b0ac7c92a6752d067582a16f712a5a58074be98975d594f9e36249fc2be7f1cc2ca6d509c663faaf2bea66f949243cc1f41651638ba6",
+    "algorithm": "sha512",
+    "filename": "clang.tar.xz",
+    "unpack": true
   }
 ]
--- a/browser/config/tooltool-manifests/linux64/hazard.manifest
+++ b/browser/config/tooltool-manifests/linux64/hazard.manifest
@@ -34,10 +34,18 @@
   {
     "version": "sccache rev d3aa1116844b50c03015266d2f48235509fa7deb",
     "algorithm": "sha512",
     "visibility": "public",
     "filename": "sccache2.tar.xz",
     "unpack": true,
     "digest": "fde0128b9a4df74f268f9d45748534d0314db0467ae22e36101df4a5374c36bb8676514e8b70254fb2e6f2a2d1224ff7ce498305223035d5f1e7e306fda2f5d5",
     "size": 2179220
+  },
+  {
+    "version": "clang + llvm 3.9.0, built from SVN r290136",
+    "size": 166261192,
+    "digest": "52f3fc23f0f5c98050f8b0ac7c92a6752d067582a16f712a5a58074be98975d594f9e36249fc2be7f1cc2ca6d509c663faaf2bea66f949243cc1f41651638ba6",
+    "algorithm": "sha512",
+    "filename": "clang.tar.xz",
+    "unpack": true
   }
 ]
--- a/browser/config/tooltool-manifests/win32/releng.manifest
+++ b/browser/config/tooltool-manifests/win32/releng.manifest
@@ -33,10 +33,18 @@
   {
     "version": "makecab rev d2bc6797648b7a834782714a55d339d2fd4e58c8",
     "algorithm": "sha512",
     "visibility": "public",
     "filename": "makecab.tar.bz2",
     "unpack": true,
     "digest": "196ac6a567c85559957dfe511c3d8654d23c94d5603259e19ccafe9d71e0e4ccee63ccc9a778f2699654b786cda54266108b7d4db543d01bb0b42545b4e6ec75",
     "size": 297118
+  },
+  {
+    "version": "clang 5.0pre/r293859",
+    "size": 309009013,
+    "digest": "cd3ed31acefd185f441632158dde73538c62bab7ebf2a8ec630985ab345938ec522983721ddb1bead1de22d5ac1571d50a958ae002364d739f2a78c6e7244222",
+    "algorithm": "sha512",
+    "filename": "clang.tar.bz2",
+    "unpack": true
   }
 ]
--- a/browser/config/tooltool-manifests/win64/releng.manifest
+++ b/browser/config/tooltool-manifests/win64/releng.manifest
@@ -34,10 +34,18 @@
   {
     "version": "makecab rev d2bc6797648b7a834782714a55d339d2fd4e58c8",
     "algorithm": "sha512",
     "visibility": "public",
     "filename": "makecab.tar.bz2",
     "unpack": true,
     "digest": "196ac6a567c85559957dfe511c3d8654d23c94d5603259e19ccafe9d71e0e4ccee63ccc9a778f2699654b786cda54266108b7d4db543d01bb0b42545b4e6ec75",
     "size": 297118
+  },
+  {
+    "version": "clang 5.0pre/r293859",
+    "size": 313862839,
+    "digest": "44dee70d525ea93952af27f943d1cc773311970c31d971d2bc2e3437cce0c899f3a03ddd8e42e86f1b4fd9ab1c4bc1767cdb0406eb4b3934ae4fc272dab830dc",
+    "algorithm": "sha512",
+    "filename": "clang.tar.bz2",
+    "unpack": true
   }
 ]
deleted file mode 100644
--- a/browser/locales/en-US/chrome/browser/aboutSyncTabs.dtd
+++ /dev/null
@@ -1,20 +0,0 @@
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
-   - License, v. 2.0. If a copy of the MPL was not distributed with this
-   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-
-<!ENTITY tabs.otherDevices.label               "Tabs From Other Devices">
-
-<!ENTITY tabs.searchText.label                   "Type here to find tabs…">
-
-<!-- LOCALIZATION NOTE (tabs.context.openTab.accesskey, tabs.context.openMultipleTabs.accesskey):
-     Only one of these will show at a time (based on selection), so reusing accesskey is ok. -->
-<!ENTITY tabs.context.openTab.label                   "Open This Tab">
-<!ENTITY tabs.context.openTab.accesskey               "O">
-<!ENTITY tabs.context.openMultipleTabs.label          "Open Selected Tabs">
-<!ENTITY tabs.context.openMultipleTabs.accesskey      "O">
-<!ENTITY tabs.context.bookmarkSingleTab.label         "Bookmark This Tab…">
-<!ENTITY tabs.context.bookmarkSingleTab.accesskey     "B">
-<!ENTITY tabs.context.bookmarkMultipleTabs.label      "Bookmark Selected Tabs…">
-<!ENTITY tabs.context.bookmarkMultipleTabs.accesskey  "B">
-<!ENTITY tabs.context.refreshList.label               "Refresh List">
-<!ENTITY tabs.context.refreshList.accesskey           "R">
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -661,17 +661,18 @@ you can use these alternative items. Oth
 <!ENTITY fullZoomResetCmd.commandkey    "0">
 <!ENTITY fullZoomResetCmd.commandkey2   "">
 
 <!ENTITY fullZoomToggleCmd.label        "Zoom Text Only">
 <!ENTITY fullZoomToggleCmd.accesskey    "T">
 <!ENTITY fullZoom.label                 "Zoom">
 <!ENTITY fullZoom.accesskey             "Z">
 
-<!ENTITY sidebarCloseButton.tooltip     "Close Sidebar">
+<!ENTITY sidebarCloseButton.tooltip     "Close sidebar">
+<!ENTITY sidebarMenuClose.label         "Close Sidebar">
 
 <!ENTITY quitApplicationCmdWin2.label       "Exit">
 <!ENTITY quitApplicationCmdWin2.accesskey   "x">
 <!ENTITY quitApplicationCmdWin2.tooltip     "Exit &brandShorterName;">
 <!ENTITY goBackCmd.commandKey "[">
 <!ENTITY goForwardCmd.commandKey "]">
 <!ENTITY quitApplicationCmd.label       "Quit"> 
 <!ENTITY quitApplicationCmd.accesskey   "Q">
--- a/browser/locales/jar.mn
+++ b/browser/locales/jar.mn
@@ -15,17 +15,16 @@
     locale/browser/aboutHome.dtd                   (%chrome/browser/aboutHome.dtd)
     locale/browser/accounts.properties             (%chrome/browser/accounts.properties)
 #ifdef MOZ_SERVICES_HEALTHREPORT
     locale/browser/aboutHealthReport.dtd           (%chrome/browser/aboutHealthReport.dtd)
 #endif
     locale/browser/aboutSearchReset.dtd            (%chrome/browser/aboutSearchReset.dtd)
     locale/browser/aboutSessionRestore.dtd         (%chrome/browser/aboutSessionRestore.dtd)
     locale/browser/aboutTabCrashed.dtd             (%chrome/browser/aboutTabCrashed.dtd)
-    locale/browser/aboutSyncTabs.dtd               (%chrome/browser/aboutSyncTabs.dtd)
     locale/browser/browser.dtd                     (%chrome/browser/browser.dtd)
     locale/browser/baseMenuOverlay.dtd             (%chrome/browser/baseMenuOverlay.dtd)
     locale/browser/browser.properties              (%chrome/browser/browser.properties)
     locale/browser/customizableui/customizableWidgets.properties (%chrome/browser/customizableui/customizableWidgets.properties)
     locale/browser/lightweightThemes.properties    (%chrome/browser/lightweightThemes.properties)
     locale/browser/newTab.dtd                      (%chrome/browser/newTab.dtd)
     locale/browser/newTab.properties               (%chrome/browser/newTab.properties)
     locale/browser/pageInfo.dtd                    (%chrome/browser/pageInfo.dtd)
deleted file mode 100644
--- a/browser/modules/SelfSupportBackend.jsm
+++ /dev/null
@@ -1,353 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-this.EXPORTED_SYMBOLS = ["SelfSupportBackend"];
-
-const Cu = Components.utils;
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-
-Cu.import("resource://gre/modules/Log.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/Timer.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "HiddenFrame",
-  "resource://gre/modules/HiddenFrame.jsm");
-
-// Enables or disables the Self Support.
-const PREF_ENABLED = "browser.selfsupport.enabled";
-// Url to open in the Self Support browser, in the urlFormatter service format.
-const PREF_URL = "browser.selfsupport.url";
-// Unified Telemetry status.
-const PREF_TELEMETRY_UNIFIED = "toolkit.telemetry.unified";
-// UITour status.
-const PREF_UITOUR_ENABLED = "browser.uitour.enabled";
-
-// Controls the interval at which the self support page tries to reload in case of
-// errors.
-const RETRY_INTERVAL_MS = 30000;
-// Maximum number of SelfSupport page load attempts in case of failure.
-const MAX_RETRIES = 5;
-// The delay after which to load the self-support, at startup.
-const STARTUP_DELAY_MS = 5000;
-
-const LOGGER_NAME = "Browser.SelfSupportBackend";
-const PREF_BRANCH_LOG = "browser.selfsupport.log.";
-const PREF_LOG_LEVEL = PREF_BRANCH_LOG + "level";
-const PREF_LOG_DUMP = PREF_BRANCH_LOG + "dump";
-
-const HTML_NS = "http://www.w3.org/1999/xhtml";
-const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
-
-const UITOUR_FRAME_SCRIPT = "chrome://browser/content/content-UITour.js";
-
-// Whether the FHR/Telemetry unification features are enabled.
-// Changing this pref requires a restart.
-const IS_UNIFIED_TELEMETRY = Services.prefs.getBoolPref(PREF_TELEMETRY_UNIFIED, false);
-
-var gLogAppenderDump = null;
-
-this.SelfSupportBackend = Object.freeze({
-  init() {
-    SelfSupportBackendInternal.init();
-  },
-
-  uninit() {
-    SelfSupportBackendInternal.uninit();
-  },
-});
-
-var SelfSupportBackendInternal = {
-  // The browser element that will load the SelfSupport page.
-  _browser: null,
-  // The Id of the timer triggering delayed SelfSupport page load.
-  _delayedLoadTimerId: null,
-  // The HiddenFrame holding the _browser element.
-  _frame: null,
-  _log: null,
-  _progressListener: null,
-
-  // Whether we're invited to let test code talk to our frame.
-  _testing: false,
-
-  // Whether self-support is enabled, and we want to continue lazy UI
-  // startup after the session has been restored.
-  _lazyStartupEnabled: false,
-
-  /**
-   * Initializes the self support backend.
-   */
-  init() {
-    this._configureLogging();
-
-    this._log.trace("init");
-
-    Services.prefs.addObserver(PREF_BRANCH_LOG, this);
-
-    // Only allow to use SelfSupport if Unified Telemetry is enabled.
-    let reportingEnabled = IS_UNIFIED_TELEMETRY;
-    if (!reportingEnabled) {
-      this._log.config("init - Disabling SelfSupport because FHR and Unified Telemetry are disabled.");
-      return;
-    }
-
-    // Make sure UITour is enabled.
-    let uiTourEnabled = Services.prefs.getBoolPref(PREF_UITOUR_ENABLED, false);
-    if (!uiTourEnabled) {
-      this._log.config("init - Disabling SelfSupport because UITour is disabled.");
-      return;
-    }
-
-    // Check the preferences to see if we want this to be active.
-    if (!Services.prefs.getBoolPref(PREF_ENABLED, true)) {
-      this._log.config("init - SelfSupport is disabled.");
-      return;
-    }
-
-    this._lazyStartupEnabled = true;
-  },
-
-  /**
-   * Shut down the self support backend, if active.
-   */
-  uninit() {
-    if (!this._log) {
-      // We haven't been initialized yet, so just return.
-      return;
-    }
-
-    this._log.trace("uninit");
-
-    Services.prefs.removeObserver(PREF_BRANCH_LOG, this);
-
-    // Cancel delayed loading, if still active, when shutting down.
-    clearTimeout(this._delayedLoadTimerId);
-
-    // Dispose of the hidden browser.
-    if (this._browser !== null) {
-      if (this._browser.contentWindow) {
-        this._browser.contentWindow.removeEventListener("DOMWindowClose", this, true);
-      }
-
-      if (this._progressListener) {
-        this._browser.removeProgressListener(this._progressListener);
-        this._progressListener.destroy();
-        this._progressListener = null;
-      }
-
-      this._browser.remove();
-      this._browser = null;
-    }
-
-    if (this._frame) {
-      this._frame.destroy();
-      this._frame = null;
-    }
-    if (this._testing) {
-      Services.obs.notifyObservers(this._browser, "self-support-browser-destroyed");
-    }
-  },
-
-  /**
-   * Handle notifications. Once all windows are created, we wait a little bit more
-   * since tabs might still be loading. Then, we open the self support.
-   */
-  // Observers are added in nsBrowserGlue.js
-  observe(aSubject, aTopic, aData) {
-    this._log.trace("observe - Topic " + aTopic);
-
-    if (aTopic === "sessionstore-windows-restored") {
-      if (this._lazyStartupEnabled) {
-        this._delayedLoadTimerId = setTimeout(this._loadSelfSupport.bind(this), STARTUP_DELAY_MS);
-        this._lazyStartupEnabled = false;
-      }
-    } else if (aTopic === "nsPref:changed") {
-      this._configureLogging();
-    }
-  },
-
-  /**
-   * Configure the logger based on the preferences.
-   */
-  _configureLogging() {
-    if (!this._log) {
-      this._log = Log.repository.getLogger(LOGGER_NAME);
-
-      // Log messages need to go to the browser console.
-      let consoleAppender = new Log.ConsoleAppender(new Log.BasicFormatter());
-      this._log.addAppender(consoleAppender);
-    }
-
-    // Make sure the logger keeps up with the logging level preference.
-    this._log.level = Log.Level[Services.prefs.getStringPref(PREF_LOG_LEVEL, "Warn")];
-
-    // If enabled in the preferences, add a dump appender.
-    let logDumping = Services.prefs.getBoolPref(PREF_LOG_DUMP, false);
-    if (logDumping != !!gLogAppenderDump) {
-      if (logDumping) {
-        gLogAppenderDump = new Log.DumpAppender(new Log.BasicFormatter());
-        this._log.addAppender(gLogAppenderDump);
-      } else {
-        this._log.removeAppender(gLogAppenderDump);
-        gLogAppenderDump = null;
-      }
-    }
-  },
-
-  /**
-   * Create an hidden frame to host our |browser|, then load the SelfSupport page in it.
-   * @param aURL The URL to load in the browser.
-   */
-  _makeHiddenBrowser(aURL) {
-    this._frame = new HiddenFrame();
-    return this._frame.get().then(aFrame => {
-      let doc = aFrame.document;
-
-      this._browser = doc.createElementNS(XUL_NS, "browser");
-      this._browser.setAttribute("type", "content");
-      this._browser.setAttribute("disableglobalhistory", "true");
-      this._browser.setAttribute("src", aURL);
-
-      if (this._testing) {
-        Services.obs.notifyObservers(this._browser, "self-support-browser-created");
-      }
-      doc.documentElement.appendChild(this._browser);
-    });
-  },
-
-  handleEvent(aEvent) {
-    this._log.trace("handleEvent - aEvent.type " + aEvent.type + ", Trusted " + aEvent.isTrusted);
-
-    if (aEvent.type === "DOMWindowClose") {
-      let window = this._browser.contentDocument.defaultView;
-      let target = aEvent.target;
-
-      if (target == window) {
-        // preventDefault stops the default window.close(). We need to do that to prevent
-        // Services.appShell.hiddenDOMWindow from being destroyed.
-        aEvent.preventDefault();
-
-        this.uninit();
-      }
-    }
-  },
-
-  /**
-   * Called when the self support page correctly loads.
-   */
-  _pageSuccessCallback() {
-    this._log.debug("_pageSuccessCallback - Page correctly loaded.");
-    this._browser.removeProgressListener(this._progressListener);
-    this._progressListener.destroy();
-    this._progressListener = null;
-
-    // Allow SelfSupportBackend to catch |window.close()| issued by the content.
-    this._browser.contentWindow.addEventListener("DOMWindowClose", this, true);
-  },
-
-  /**
-   * Called when the self support page fails to load.
-   */
-  _pageLoadErrorCallback() {
-    this._log.info("_pageLoadErrorCallback - Too many failed load attempts. Giving up.");
-    this.uninit();
-  },
-
-  /**
-   * Create a browser and attach it to an hidden window. The browser will contain the
-   * self support page and attempt to load the page content. If loading fails, try again
-   * after an interval.
-   */
-  _loadSelfSupport() {
-    // Fetch the Self Support URL from the preferences.
-    let unformattedURL = Services.prefs.getStringPref(PREF_URL, "");
-    let url = Services.urlFormatter.formatURL(unformattedURL);
-    if (!url.startsWith("https:")) {
-      this._log.error("_loadSelfSupport - Non HTTPS URL provided: " + url);
-      return;
-    }
-
-    this._log.config("_loadSelfSupport - URL " + url);
-
-    // Create the hidden browser.
-    this._makeHiddenBrowser(url).then(() => {
-      // Load UITour frame script.
-      this._browser.messageManager.loadFrameScript(UITOUR_FRAME_SCRIPT, true);
-
-      // We need to watch for load errors as well and, in case, try to reload
-      // the self support page.
-      const webFlags = Ci.nsIWebProgress.NOTIFY_STATE_WINDOW |
-                       Ci.nsIWebProgress.NOTIFY_STATE_REQUEST |
-                       Ci.nsIWebProgress.NOTIFY_LOCATION;
-
-      this._progressListener = new ProgressListener(() => this._pageLoadErrorCallback(),
-                                                    () => this._pageSuccessCallback());
-
-      this._browser.addProgressListener(this._progressListener, webFlags);
-    });
-  }
-};
-
-/**
- * A progress listener object which notifies of page load error and load success
- * through callbacks. When the page fails to load, the progress listener tries to
- * reload it up to MAX_RETRIES times. The page is not loaded again immediately, but
- * after a timeout.
- *
- * @param aLoadErrorCallback Called when a page failed to load MAX_RETRIES times.
- * @param aLoadSuccessCallback Called when a page correctly loads.
- */
-function ProgressListener(aLoadErrorCallback, aLoadSuccessCallback) {
-  this._loadErrorCallback = aLoadErrorCallback;
-  this._loadSuccessCallback = aLoadSuccessCallback;
-  // The number of page loads attempted.
-  this._loadAttempts = 0;
-  this._log = Log.repository.getLogger(LOGGER_NAME);
-  // The Id of the timer which triggers page load again in case of errors.
-  this._reloadTimerId = null;
-}
-
-ProgressListener.prototype = {
-  onLocationChange(aWebProgress, aRequest, aLocation, aFlags) {
-    if (aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE) {
-      this._log.warn("onLocationChange - There was a problem fetching the SelfSupport URL (attempt " +
-                     this._loadAttempts + ").");
-
-      // Increase the number of attempts and bail out if we failed too many times.
-      this._loadAttempts++;
-      if (this._loadAttempts > MAX_RETRIES) {
-        this._loadErrorCallback();
-        return;
-      }
-
-      // Reload the page after the retry interval expires. The interval is multiplied
-      // by the number of attempted loads, so that it takes a bit more to try to reload
-      // when frequently failing.
-      this._reloadTimerId = setTimeout(() => {
-        this._log.debug("onLocationChange - Reloading SelfSupport URL in the hidden browser.");
-        aWebProgress.DOMWindow.location.reload();
-      }, RETRY_INTERVAL_MS * this._loadAttempts);
-    }
-  },
-
-  onStateChange(aWebProgress, aRequest, aFlags, aStatus) {
-    if (aFlags & Ci.nsIWebProgressListener.STATE_STOP &&
-        aFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK &&
-        aFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW &&
-        Components.isSuccessCode(aStatus)) {
-      this._loadSuccessCallback();
-    }
-  },
-
-  destroy() {
-    // Make sure we don't try to reload self support when shutting down.
-    clearTimeout(this._reloadTimerId);
-  },
-
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
-                                         Ci.nsISupportsWeakReference]),
-};
--- a/browser/modules/moz.build
+++ b/browser/modules/moz.build
@@ -11,19 +11,16 @@ with Files("test/browser/*Telemetry*"):
     BUG_COMPONENT = ("Toolkit", "Telemetry")
 
 with Files("test/browser/*ContentSearch*"):
     BUG_COMPONENT = ("Firefox", "Search")
 
 with Files("test/browser/*PermissionUI*"):
     BUG_COMPONENT = ("Firefox", "Site Identity and Permission Panels")
 
-with Files("test/browser/browser_SelfSupportBackend.js"):
-    BUG_COMPONENT = ("Toolkit", "Telemetry")
-
 with Files("test/browser/*SitePermissions*"):
     BUG_COMPONENT = ("Firefox", "Site Identity and Permission Panels")
 
 with Files("test/browser/browser_UnsubmittedCrashHandler.js"):
     BUG_COMPONENT = ("Toolkit", "Crash Reporting")
 
 with Files("test/browser/browser_bug1319078.js"):
     BUG_COMPONENT = ("Core", "DOM: Core & HTML")
@@ -92,19 +89,16 @@ with Files("ProcessHangMonitor.jsm"):
     BUG_COMPONENT = ("Core", "DOM: Content Processes")
 
 with Files("ReaderParent.jsm"):
     BUG_COMPONENT = ("Toolkit", "Reader Mode")
 
 with Files("Sanitizer.jsm"):
     BUG_COMPONENT = ("Firefox", "Preferences")
 
-with Files("SelfSupportBackend.jsm"):
-    BUG_COMPONENT = ("Toolkit", "Telemetry")
-
 with Files("SitePermissions.jsm"):
     BUG_COMPONENT = ("Firefox", "Site Identity and Permission Panels")
 
 with Files("Social*"):
     BUG_COMPONENT = ("Firefox", "SocialAPI")
 
 with Files("TransientPrefs.jsm"):
     BUG_COMPONENT = ("Firefox", "Preferences")
@@ -155,17 +149,16 @@ EXTRA_JS_MODULES += [
     'offlineAppCache.jsm',
     'PermissionUI.jsm',
     'PluginContent.jsm',
     'ProcessHangMonitor.jsm',
     'ReaderParent.jsm',
     'RecentWindow.jsm',
     'RemotePrompt.jsm',
     'Sanitizer.jsm',
-    'SelfSupportBackend.jsm',
     'SitePermissions.jsm',
     'Social.jsm',
     'SocialService.jsm',
     'TransientPrefs.jsm',
     'webrtcUI.jsm',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
--- a/browser/modules/test/browser/browser.ini
+++ b/browser/modules/test/browser/browser.ini
@@ -14,20 +14,16 @@ support-files =
   contentSearchSuggestions.sjs
   contentSearchSuggestions.xml
   !/browser/components/search/test/head.js
   !/browser/components/search/test/testEngine.xml
 [browser_PermissionUI.js]
 [browser_PermissionUI_prompts.js]
 [browser_ProcessHangNotifications.js]
 skip-if = !e10s
-[browser_SelfSupportBackend.js]
-support-files =
-  ../../../components/uitour/test/uitour.html
-  ../../../components/uitour/UITour-lib.js
 [browser_SitePermissions.js]
 [browser_SitePermissions_combinations.js]
 [browser_SitePermissions_expiry.js]
 [browser_SitePermissions_tab_urls.js]
 [browser_taskbar_preview.js]
 skip-if = os != "win"
 [browser_UnsubmittedCrashHandler.js]
 run-if = crashreporter
deleted file mode 100644
--- a/browser/modules/test/browser/browser_SelfSupportBackend.js
+++ /dev/null
@@ -1,172 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-// Pass an empty scope object to the import to prevent "leaked window property"
-// errors in tests.
-var Preferences = Cu.import("resource://gre/modules/Preferences.jsm", {}).Preferences;
-var PromiseUtils = Cu.import("resource://gre/modules/PromiseUtils.jsm", {}).PromiseUtils;
-var SelfSupportBackend =
-  Cu.import("resource:///modules/SelfSupportBackend.jsm", {}).SelfSupportBackend;
-
-const PREF_SELFSUPPORT_ENABLED = "browser.selfsupport.enabled";
-const PREF_SELFSUPPORT_URL = "browser.selfsupport.url";
-const PREF_UITOUR_ENABLED = "browser.uitour.enabled";
-
-const TEST_WAIT_RETRIES = 60;
-
-const TEST_PAGE_URL = getRootDirectory(gTestPath) + "uitour.html";
-const TEST_PAGE_URL_HTTPS = TEST_PAGE_URL.replace("chrome://mochitests/content/", "https://example.com/");
-
-function sendSessionRestoredNotification() {
-  let selfSupportBackendImpl =
-    Cu.import("resource:///modules/SelfSupportBackend.jsm", {}).SelfSupportBackendInternal;
-  selfSupportBackendImpl.observe(null, "sessionstore-windows-restored", null);
-}
-
-function toggleSelfSupportTestMode(testing) {
-  let selfSupportBackendImpl =
-    Cu.import("resource:///modules/SelfSupportBackend.jsm", {}).SelfSupportBackendInternal;
-  selfSupportBackendImpl._testing = testing;
-}
-
-
-/**
- * Wait for self support page to load.
- *
- * @param aURL The URL to look for to identify the browser.
- *
- * @returns {Promise} Return a promise which is resolved when SelfSupport page is fully
- *          loaded.
- */
-function promiseSelfSupportLoad(aURL) {
-  return new Promise((resolve, reject) => {
-    // Find the SelfSupport browser.
-    let browser = null;
-    let browserPromise = TestUtils.topicObserved("self-support-browser-created",
-        (subject, topic) => {
-          let url = subject.getAttribute("src");
-          Cu.reportError("Got browser with src: " + url);
-          if (url == aURL) {
-            browser = subject;
-          }
-          return url == aURL;
-        });
-
-    // Once found, append a "load" listener to catch page loads.
-    browserPromise.then(() => {
-      if (browser.contentDocument.readyState === "complete") {
-        resolve(browser);
-      } else {
-        let handler = () => {
-          browser.removeEventListener("load", handler, true);
-          resolve(browser);
-        };
-        browser.addEventListener("load", handler, true);
-      }
-    }, reject);
-  });
-}
-
-/**
- * Prepare the test environment.
- */
-add_task(async function setupEnvironment() {
-  // We always run the SelfSupportBackend in tests to check for weird behaviours.
-  // Disable it to test its start-up.
-  SelfSupportBackend.uninit();
-
-  // Testing prefs are set via |user_pref|, so we need to get their value in order
-  // to restore them.
-  let selfSupportEnabled = Preferences.get(PREF_SELFSUPPORT_ENABLED, true);
-  let uitourEnabled = Preferences.get(PREF_UITOUR_ENABLED, false);
-  let selfSupportURL = Preferences.get(PREF_SELFSUPPORT_URL, "");
-
-  // Enable the SelfSupport backend and set the page URL. We also make sure UITour
-  // is enabled.
-  Preferences.set(PREF_SELFSUPPORT_ENABLED, true);
-  Preferences.set(PREF_UITOUR_ENABLED, true);
-  Preferences.set(PREF_SELFSUPPORT_URL, TEST_PAGE_URL_HTTPS);
-
-  // Whitelist the HTTPS page to use UITour.
-  let pageURI = Services.io.newURI(TEST_PAGE_URL_HTTPS);
-  Services.perms.add(pageURI, "uitour", Services.perms.ALLOW_ACTION);
-
-  registerCleanupFunction(() => {
-    Services.perms.remove(pageURI, "uitour");
-    Preferences.set(PREF_SELFSUPPORT_ENABLED, selfSupportEnabled);
-    Preferences.set(PREF_UITOUR_ENABLED, uitourEnabled);
-    Preferences.set(PREF_SELFSUPPORT_URL, selfSupportURL);
-  });
-});
-
-/**
- * Test that the self support page can use the UITour API and close itself.
- */
-add_task(async function test_selfSupport() {
-  toggleSelfSupportTestMode(true);
-  registerCleanupFunction(toggleSelfSupportTestMode.bind(null, false));
-  // Initialise the SelfSupport backend and trigger the load.
-  SelfSupportBackend.init();
-
-  // Wait for the SelfSupport page to load.
-  let selfSupportBrowserPromise = promiseSelfSupportLoad(TEST_PAGE_URL_HTTPS);
-
-  // SelfSupportBackend waits for "sessionstore-windows-restored" to start loading. Send it.
-  info("Sending sessionstore-windows-restored");
-  sendSessionRestoredNotification();
-
-  // Wait for the SelfSupport page to load.
-  info("Waiting for the SelfSupport local page to load.");
-  let selfSupportBrowser = await selfSupportBrowserPromise;
-  Assert.ok(!!selfSupportBrowser, "SelfSupport browser must exist.");
-
-  // Get a reference to the UITour API.
-  info("Testing access to the UITour API.");
-  let contentWindow =
-    Cu.waiveXrays(selfSupportBrowser.contentDocument.defaultView);
-  let uitourAPI = contentWindow.Mozilla.UITour;
-
-  // Test the UITour API with a ping.
-  let pingPromise = new Promise((resolve) => {
-    uitourAPI.ping(resolve);
-  });
-  await pingPromise;
-  info("Ping succeeded");
-
-  let observePromise = ContentTask.spawn(selfSupportBrowser, null, async function checkObserve() {
-    await new Promise(resolve => {
-      let win = Cu.waiveXrays(content);
-      win.Mozilla.UITour.observe((event, data) => {
-        if (event != "Heartbeat:Engaged") {
-          return;
-        }
-        Assert.equal(data.flowId, "myFlowID", "Check flowId");
-        Assert.ok(!!data.timestamp, "Check timestamp");
-        resolve(data);
-      }, () => {});
-    });
-  });
-
-  info("Notifying Heartbeat:Engaged");
-  UITour.notify("Heartbeat:Engaged", {
-    flowId: "myFlowID",
-    timestamp: Date.now(),
-  });
-  await observePromise;
-  info("Observed in the hidden frame");
-
-  let selfSupportClosed = TestUtils.topicObserved("self-support-browser-destroyed");
-  // Close SelfSupport from content.
-  contentWindow.close();
-
-  await selfSupportClosed;
-  Assert.ok(!selfSupportBrowser.parentNode, "SelfSupport browser must have been removed.");
-
-  // We shouldn't need this, but let's keep it to make sure closing SelfSupport twice
-  // doesn't create any problem.
-  SelfSupportBackend.uninit();
-});
-
deleted file mode 100644
--- a/browser/themes/linux/aboutSyncTabs.css
+++ /dev/null
@@ -1,105 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#tabs-display,
-#tabsList {
-  background-color: transparent;
-  -moz-appearance: none;
-  margin: 0;
-}
-
-#tabsList {
-  width: 100%;
-}
-
-#tabs-display {
-  background: #fff url(chrome://browser/skin/sync-bg.png) repeat-x center -80px;
-}
-
-#headers {
-  background: url(chrome://browser/skin/sync-32.png) no-repeat;
-  margin-top: 4px;
-  width: 45em;
-  height: 32px;
-  margin-inline-start: 2em;
-  margin-inline-end: 2em;
-}
-
-#headers:-moz-locale-dir(rtl) {
-  background-position-x: 100%;
-}
-
-#tabsListHeading {
-  font-size: 140%;
-  font-weight: bold;
-  margin-inline-start: 40px;
-}
-
-richlistitem {
-  margin-inline-end: 2em;
-}
-
-richlistitem[selected="true"],
-richlistitem:focus {
-  outline-style: none;
-}
-
-richlistitem[type="tab"] {
-  min-height: 3em;
-  border: #999999 1px solid !important;
-  padding: 2px 5px;
-  margin-bottom: 4px;
-  margin-inline-start: 4em;
-  border-radius: 6px;
-  background-color: menu;
-  width: 44em;
-  opacity: 0.9;
-  box-shadow:
-    inset rgba(255, 255, 255, 0.5) 0 1px 0px,
-    inset rgba(0, 0, 0, 0.1) 0 -2px 0px,
-    rgba(0, 0, 0, 0.1) 0px 1px 0px;
-}
-
-richlistitem[type="tab"][selected="true"] {
-  background-color: -moz-MenuHover;
-}
-
-richlistitem[type="client"] {
-  min-height: 2em;
-  color: #000000;
-  margin-inline-start: 2em;
-  margin-top: 2px;
-  margin-bottom: 3px;
-  width: 42em;
-  border-radius: 6px;
-  background-color: transparent;
-  -moz-user-focus: ignore !important;
-}
-richlistitem.mobile[type="client"] {
-  list-style-image: url("chrome://browser/skin/sync-mobileIcon.svg#icon");
-}
-richlistitem.desktop[type="client"] {
-  list-style-image: url("chrome://browser/skin/sync-desktopIcon.svg#icon");
-}
-
-.title,
-.clientName {
-  color: #000000;
-  font-size: 1.1em;
-}
-
-.title[selected="true"],
-.url[selected="true"] {
-  color: inherit;
-}
-
-.url {
-  color: -moz-nativehyperlinktext;
-  font-size: 0.95em;
-}
-
-.tabIcon {
-  padding-inline-start: 2px;
-  padding-top: 2px;
-}
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -263,23 +263,27 @@ menuitem.bookmark-item {
 #close-button {
   list-style-image: url("chrome://global/skin/icons/Close.gif");
 }
 
 /* Location bar */
 #main-window {
   --urlbar-border-color: ThreeDShadow;
   --urlbar-border-color-hover: var(--urlbar-border-color);
-  --urlbar-background-color: -moz-field;
 }
 
 #navigator-toolbox:-moz-lwtheme {
   --urlbar-border-color: rgba(0,0,0,.3);
 }
 
+#urlbar {
+  /* override textbox[enablehistory="true"] styling: */
+  background-color: -moz-field;
+}
+
 %include ../shared/urlbar-searchbar.inc.css
 
 %ifdef MOZ_PHOTON_THEME
 
 #urlbar[focused="true"],
 .searchbar-textbox[focused="true"] {
   border-color: Highlight;
 }
@@ -296,20 +300,16 @@ menuitem.bookmark-item {
   margin: 0 3px;
 }
 
 #urlbar[focused],
 .searchbar-textbox[focused] {
   border-color: Highlight;
 }
 
-#urlbar {
-  background-color: -moz-field;
-}
-
 #urlbar:-moz-lwtheme,
 .searchbar-textbox:-moz-lwtheme {
   background-color: rgba(255,255,255,.8);
   color: black;
 }
 
 #urlbar:-moz-lwtheme[focused=true],
 .searchbar-textbox:-moz-lwtheme[focused=true] {
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -3,17 +3,16 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 browser.jar:
 % skin browser classic/1.0 %skin/classic/browser/
 % override chrome://global/skin/icons/warning-16.png moz-icon://stock/gtk-dialog-warning?size=menu
 #include ../shared/jar.inc.mn
   skin/classic/browser/sanitizeDialog.css
   skin/classic/browser/aboutSessionRestore-window-icon.png
-  skin/classic/browser/aboutSyncTabs.css
 * skin/classic/browser/syncedtabs/sidebar.css     (syncedtabs/sidebar.css)
 * skin/classic/browser/browser.css
 * skin/classic/browser/compacttheme.css
   skin/classic/browser/Info.png
   skin/classic/browser/menuPanel-customize.png
   skin/classic/browser/menuPanel-customize@2x.png
   skin/classic/browser/menuPanel-exit.png
   skin/classic/browser/menuPanel-exit@2x.png
@@ -94,19 +93,16 @@ browser.jar:
   skin/classic/browser/tabbrowser/tab-selected-start.svg    (tab-selected-start.svg)
 
   skin/classic/browser/tabbrowser/tab-stroke-end.png        (tabbrowser/tab-stroke-end.png)
   skin/classic/browser/tabbrowser/tab-stroke-end@2x.png     (tabbrowser/tab-stroke-end@2x.png)
   skin/classic/browser/tabbrowser/tab-stroke-start.png      (tabbrowser/tab-stroke-start.png)
   skin/classic/browser/tabbrowser/tab-stroke-start@2x.png   (tabbrowser/tab-stroke-start@2x.png)
   skin/classic/browser/tabbrowser/tabDragIndicator.png      (tabbrowser/tabDragIndicator.png)
 
-  skin/classic/browser/sync-16.png
-  skin/classic/browser/sync-32.png
-  skin/classic/browser/sync-bg.png
   skin/classic/browser/sync-desktopIcon.svg  (../shared/sync-desktopIcon.svg)
   skin/classic/browser/sync-horizontalbar.png
   skin/classic/browser/sync-horizontalbar@2x.png
   skin/classic/browser/sync-mobileIcon.svg  (../shared/sync-mobileIcon.svg)
   skin/classic/browser/syncProgress-horizontalbar.png
   skin/classic/browser/syncProgress-horizontalbar@2x.png
 #ifdef E10S_TESTING_ONLY
   skin/classic/browser/e10s-64@2x.png (../shared/e10s-64@2x.png)
deleted file mode 100644
--- a/browser/themes/osx/aboutSyncTabs.css
+++ /dev/null
@@ -1,105 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#tabs-display,
-#tabsList {
-  background-color: transparent;
-  -moz-appearance: none;
-  margin: 0;
-}
-
-#tabsList {
-  width: 100%;
-}
-
-#tabs-display {
-  background: #fff url(chrome://browser/skin/sync-bg.png) repeat-x center -80px;
-}
-
-#headers {
-  background: url(chrome://browser/skin/sync-32.png) no-repeat;
-  margin-top: 4px;
-  width: 45em;
-  height: 32px;
-  margin-inline-start: 2em;
-  margin-inline-end: 2em;
-}
-
-#headers:-moz-locale-dir(rtl) {
-  background-position-x: 100%;
-}
-
-#tabsListHeading {
-  font-size: 140%;
-  font-weight: bold;
-  margin-inline-start: 40px;
-}
-
-richlistitem {
-  margin-inline-end: 2em;
-}
-
-richlistitem[selected="true"],
-richlistitem:focus {
-  outline-style: none;
-}
-
-richlistitem[type="tab"] {
-  min-height: 3em;
-  border: #999999 1px solid !important;
-  padding: 2px 5px;
-  margin-bottom: 4px;
-  margin-inline-start: 4em;
-  border-radius: 6px;
-  background-color: menu;
-  width: 44em;
-  opacity: 0.9;
-  box-shadow:
-    inset rgba(255, 255, 255, 0.5) 0 1px 0px,
-    inset rgba(0, 0, 0, 0.1) 0 -2px 0px,
-    rgba(0, 0, 0, 0.1) 0px 1px 0px;
-}
-
-richlistitem[type="tab"][selected="true"] {
-  background-color: -moz-MenuHover;
-}
-
-richlistitem[type="client"] {
-  min-height: 2em;
-  color: #000000;
-  margin-inline-start: 2em;
-  margin-top: 2px;
-  margin-bottom: 3px;
-  width: 42em;
-  border-radius: 6px;
-  background-color: transparent;
-  -moz-user-focus: ignore !important;
-}
-richlistitem.mobile[type="client"] {
-  list-style-image: url("chrome://browser/skin/sync-mobileIcon.svg#icon");
-}
-richlistitem.desktop[type="client"] {
-  list-style-image: url("chrome://browser/skin/sync-desktopIcon.svg#icon");
-}
-
-.title,
-.clientName {
-  color: #000000;
-  font-size: 1.1em;
-}
-
-.title[selected="true"],
-.url[selected="true"] {
-  color: inherit;
-}
-
-.url {
-  color: -moz-nativehyperlinktext;
-  font-size: 0.95em;
-}
-
-.tabIcon {
-  padding-inline-start: 2px;
-  padding-top: 2px;
-}
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -522,17 +522,16 @@ toolbarpaletteitem[place="palette"] > #p
 
 %include ../shared/urlbar-searchbar.inc.css
 
 %ifdef MOZ_PHOTON_THEME
 
 #main-window {
   --urlbar-border-color: hsla(240, 5%, 5%, .25);
   --urlbar-border-color-hover: hsla(240, 5%, 5%, .35);
-  --urlbar-background-color: -moz-field;
 }
 
 #urlbar[focused="true"],
 .searchbar-textbox[focused="true"] {
   border-color: -moz-mac-focusring;
   box-shadow: var(--focus-ring-box-shadow);
 }
 
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -2,17 +2,16 @@
 # 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/.
 
 browser.jar:
 % skin browser classic/1.0 %skin/classic/browser/
 #include ../shared/jar.inc.mn
   skin/classic/browser/sanitizeDialog.css
   skin/classic/browser/aboutSessionRestore-window-icon.png
-  skin/classic/browser/aboutSyncTabs.css
 * skin/classic/browser/syncedtabs/sidebar.css          (syncedtabs/sidebar.css)
 * skin/classic/browser/browser.css
 * skin/classic/browser/compacttheme.css
   skin/classic/browser/Info.png
   skin/classic/browser/subtle-pattern.png
   skin/classic/browser/menu-back.png
   skin/classic/browser/menu-forward.png
   skin/classic/browser/menuPanel-customize.png
@@ -141,19 +140,16 @@ browser.jar:
   skin/classic/browser/tabbrowser/tab-selected-start.svg                 (tab-selected-start.svg)
 
   skin/classic/browser/tabbrowser/tab-stroke-end.png                     (tabbrowser/tab-stroke-end.png)
   skin/classic/browser/tabbrowser/tab-stroke-end@2x.png                  (tabbrowser/tab-stroke-end@2x.png)
   skin/classic/browser/tabbrowser/tab-stroke-start.png                   (tabbrowser/tab-stroke-start.png)
   skin/classic/browser/tabbrowser/tab-stroke-start@2x.png                (tabbrowser/tab-stroke-start@2x.png)
   skin/classic/browser/tabbrowser/tabDragIndicator.png                   (tabbrowser/tabDragIndicator.png)
   skin/classic/browser/tabbrowser/tabDragIndicator@2x.png                (tabbrowser/tabDragIndicator@2x.png)
-  skin/classic/browser/sync-16.png
-  skin/classic/browser/sync-32.png
-  skin/classic/browser/sync-bg.png
   skin/classic/browser/sync-desktopIcon.svg  (../shared/sync-desktopIcon.svg)
   skin/classic/browser/sync-horizontalbar.png
   skin/classic/browser/sync-horizontalbar@2x.png
   skin/classic/browser/sync-mobileIcon.svg  (../shared/sync-mobileIcon.svg)
   skin/classic/browser/syncProgress-horizontalbar.png
   skin/classic/browser/syncProgress-horizontalbar@2x.png
   skin/classic/browser/Toolbar-background-noise.png         (Toolbar-background-noise.png)
   skin/classic/browser/yosemite/menuPanel-customize.png                (menuPanel-customize-yosemite.png)
--- a/browser/themes/shared/identity-block/identity-block.inc.css
+++ b/browser/themes/shared/identity-block/identity-block.inc.css
@@ -165,16 +165,17 @@
 #tracking-protection-icon:not([state]) {
   margin-inline-end: -18px;
   pointer-events: none;
   opacity: 0;
   /* Only animate the shield in, when it disappears hide it immediately. */
   transition: none;
 }
 
+#urlbar[pageproxystate="invalid"] > #identity-box > #extension-icon,
 #urlbar[pageproxystate="invalid"] > #identity-box > #tracking-protection-icon {
   visibility: collapse;
 }
 
 /* CONNECTION ICON, EXTENSION ICON */
 
 #connection-icon,
 #extension-icon {
--- a/browser/themes/shared/toolbarbutton-icons.inc.css
+++ b/browser/themes/shared/toolbarbutton-icons.inc.css
@@ -8,33 +8,35 @@
   -moz-context-properties: fill;
   fill: var(--toolbarbutton-icon-fill);
 }
 
 toolbar[brighttext] :-moz-any(@primaryToolbarButtons@) {
   fill: var(--toolbarbutton-icon-fill-inverted);
 }
 
+#back-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
+%ifdef MOZ_PHOTON_THEME
+#forward-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
+#reload-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
+%endif
+#nav-bar-overflow-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
+#panic-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
+  transform: scaleX(-1);
+}
+
 #back-button {
   list-style-image: url("chrome://browser/skin/back-large.svg");
 }
 
-#back-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
-  transform: scaleX(-1);
-}
-
 #forward-button {
   list-style-image: url("chrome://browser/skin/forward.svg");
 }
 
 %ifdef MOZ_PHOTON_THEME
-#forward-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
-  transform: scaleX(-1);
-}
-
 #reload-button {
   list-style-image: url("chrome://browser/skin/reload.svg");
 }
 
 #stop-button {
   list-style-image: url("chrome://browser/skin/stop.svg");
 }
 %endif
@@ -166,35 +168,27 @@ toolbar:not([brighttext]) #bookmarks-men
 #zoom-controls:not(@inAnyPanel@) > #zoom-in-button {
   list-style-image: url("chrome://browser/skin/zoom-in.svg");
 }
 
 #nav-bar-overflow-button {
   list-style-image: url("chrome://browser/skin/chevron.svg");
 }
 
-#nav-bar-overflow-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
-  transform: scaleX(-1);
-}
-
 #email-link-button[cui-areatype="toolbar"] {
   list-style-image: url("chrome://browser/skin/mail.svg");
 }
 
 #sidebar-button[cui-areatype="toolbar"] {
   list-style-image: url("chrome://browser/skin/sidebars.svg");
 }
 
 #panic-button[cui-areatype="toolbar"] {
   list-style-image: url("chrome://browser/skin/forget.svg");
 }
 
 #panic-button[cui-areatype="toolbar"][open] {
   fill: rgb(213, 32, 20);
 }
 
-#panic-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
-  transform: scaleX(-1);
-}
-
 #webide-button[cui-areatype="toolbar"] {
   list-style-image: url("chrome://browser/skin/webIDE.svg");
 }
--- a/browser/themes/shared/urlbar-searchbar.inc.css
+++ b/browser/themes/shared/urlbar-searchbar.inc.css
@@ -3,17 +3,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 %ifdef MOZ_PHOTON_THEME
 
 #urlbar,
 .searchbar-textbox {
   -moz-appearance: none;
   background-clip: content-box;
-  background-color: var(--urlbar-background-color);
   border: 1px solid var(--urlbar-border-color);
   border-radius: var(--toolbarbutton-border-radius);
   box-shadow: 0 1px 4px hsla(0, 0%, 0%, .05);
   padding: 0;
   margin: 0 5px;
   min-height: 30px;
 }
 
deleted file mode 100644
--- a/browser/themes/windows/aboutSyncTabs.css
+++ /dev/null
@@ -1,105 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#tabs-display,
-#tabsList {
-  background-color: transparent;
-  -moz-appearance: none;
-  margin: 0;
-}
-
-#tabsList {
-  width: 100%;
-}
-
-#tabs-display {
-  background: #fff url(chrome://browser/skin/sync-bg.png) repeat-x center -80px;
-}
-
-#headers {
-  background: url(chrome://browser/skin/sync-32.png) no-repeat;
-  margin-top: 4px;
-  width: 45em;
-  height: 32px;
-  margin-inline-start: 2em;
-  margin-inline-end: 2em;
-}
-
-#headers:-moz-locale-dir(rtl) {
-  background-position-x: 100%;
-}
-
-#tabsListHeading {
-  font-size: 140%;
-  font-weight: bold;
-  margin-inline-start: 40px;
-}
-
-richlistitem {
-  margin-inline-end: 2em;
-}
-
-richlistitem[selected="true"],
-richlistitem:focus {
-  outline-style: none;
-}
-
-richlistitem[type="tab"] {
-  min-height: 3em;
-  border: #999999 1px solid !important;
-  padding: 2px 5px;
-  margin-bottom: 4px;
-  margin-inline-start: 4em;
-  border-radius: 6px;
-  background-color: menu;
-  width: 44em;
-  opacity: 0.9;
-  box-shadow:
-    inset rgba(255, 255, 255, 0.5) 0 1px 0px,
-    inset rgba(0, 0, 0, 0.1) 0 -2px 0px,
-    rgba(0, 0, 0, 0.1) 0px 1px 0px;
-}
-
-richlistitem[type="tab"][selected="true"] {
-  background-color: -moz-MenuHover;
-}
-
-richlistitem[type="client"] {
-  min-height: 2em;
-  color: #000000;
-  margin-inline-start: 2em;
-  margin-top: 2px;
-  margin-bottom: 3px;
-  width: 42em;
-  border-radius: 6px;
-  background-color: transparent;
-  -moz-user-focus: ignore !important;
-}
-richlistitem.mobile[type="client"] {
-  list-style-image: url("chrome://browser/skin/sync-mobileIcon.svg#icon");
-}
-richlistitem.desktop[type="client"] {
-  list-style-image: url("chrome://browser/skin/sync-desktopIcon.svg#icon");
-}
-
-.title,
-.clientName {
-  color: #000000;
-  font-size: 1.1em;
-}
-
-.title[selected="true"],
-.url[selected="true"] {
-  color: inherit;
-}
-
-.url {
-  color: -moz-nativehyperlinktext;
-  font-size: 0.95em;
-}
-
-.tabIcon {
-  padding-inline-start: 2px;
-  padding-top: 2px;
-}
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -665,17 +665,16 @@ toolbar[brighttext] #close-button {
 %include ../shared/urlbar-searchbar.inc.css
 
 %ifdef MOZ_PHOTON_THEME
 
 @media (-moz-windows-default-theme) {
   #main-window:not(:-moz-lwtheme) {
     --urlbar-border-color: hsla(240, 5%, 5%, .25);
     --urlbar-border-color-hover: hsla(240, 5%, 5%, .35);
-    --urlbar-background-color: -moz-field;
   }
 }
 
 #urlbar,
 .searchbar-textbox {
   font-size: 1.15em;
 }
 
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -2,17 +2,16 @@
 # 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/.
 
 browser.jar:
 % skin browser classic/1.0 %skin/classic/browser/
 #include ../shared/jar.inc.mn
   skin/classic/browser/sanitizeDialog.css
   skin/classic/browser/aboutSessionRestore-window-icon.png
-  skin/classic/browser/aboutSyncTabs.css
 * skin/classic/browser/syncedtabs/sidebar.css     (syncedtabs/sidebar.css)
 * skin/classic/browser/browser.css
 * skin/classic/browser/compacttheme.css
   skin/classic/browser/caption-buttons.svg
   skin/classic/browser/Info.png
   skin/classic/browser/livemark-folder.png
   skin/classic/browser/menu-back.png
   skin/classic/browser/menu-forward.png
@@ -120,19 +119,16 @@ browser.jar:
   skin/classic/browser/tabbrowser/tab-selected-end.svg         (tab-selected-end.svg)
   skin/classic/browser/tabbrowser/tab-selected-start.svg       (tab-selected-start.svg)
 
   skin/classic/browser/tabbrowser/tab-stroke-end.png           (tabbrowser/tab-stroke-end.png)
   skin/classic/browser/tabbrowser/tab-stroke-end@2x.png        (tabbrowser/tab-stroke-end@2x.png)
   skin/classic/browser/tabbrowser/tab-stroke-start.png         (tabbrowser/tab-stroke-start.png)
   skin/classic/browser/tabbrowser/tab-stroke-start@2x.png      (tabbrowser/tab-stroke-start@2x.png)
   skin/classic/browser/tabbrowser/tabDragIndicator.png         (tabbrowser/tabDragIndicator.png)
-  skin/classic/browser/sync-16.png
-  skin/classic/browser/sync-32.png
-  skin/classic/browser/sync-bg.png
   skin/classic/browser/sync-desktopIcon.svg  (../shared/sync-desktopIcon.svg)
   skin/classic/browser/sync-horizontalbar.png
   skin/classic/browser/sync-horizontalbar@2x.png
   skin/classic/browser/sync-horizontalbar-win7.png
   skin/classic/browser/sync-horizontalbar-win7@2x.png
   skin/classic/browser/sync-mobileIcon.svg  (../shared/sync-mobileIcon.svg)
   skin/classic/browser/syncProgress-horizontalbar.png
   skin/classic/browser/syncProgress-horizontalbar@2x.png
--- a/build/moz.configure/init.configure
+++ b/build/moz.configure/init.configure
@@ -60,30 +60,29 @@ def check_build_environment(help, dist):
             '  *     1. cd %s\n'
             '  *     2. gmake distclean\n'
             '  ***'
             % ('\n  '.join(conflict_files), topsrcdir)
         )
 
     return result
 
-set_config('TOPSRCDIR', delayed_getattr(check_build_environment, 'topsrcdir'))
-set_config('TOPOBJDIR', delayed_getattr(check_build_environment, 'topobjdir'))
-set_config('MOZ_BUILD_ROOT', delayed_getattr(check_build_environment,
-                                             'topobjdir'))
-set_config('DIST', delayed_getattr(check_build_environment, 'dist'))
+set_config('TOPSRCDIR', check_build_environment.topsrcdir)
+set_config('TOPOBJDIR', check_build_environment.topobjdir)
+set_config('MOZ_BUILD_ROOT', check_build_environment.topobjdir)
+set_config('DIST', check_build_environment.dist)
 
 add_old_configure_assignment(
-    '_topsrcdir', delayed_getattr(check_build_environment, 'topsrcdir'))
+    '_topsrcdir', check_build_environment.topsrcdir)
 add_old_configure_assignment(
-    '_objdir', delayed_getattr(check_build_environment, 'topobjdir'))
+    '_objdir', check_build_environment.topobjdir)
 add_old_configure_assignment(
-    'MOZ_BUILD_ROOT', delayed_getattr(check_build_environment, 'topobjdir'))
+    'MOZ_BUILD_ROOT', check_build_environment.topobjdir)
 add_old_configure_assignment(
-    'DIST', delayed_getattr(check_build_environment, 'dist'))
+    'DIST', check_build_environment.dist)
 
 option(env='MOZ_AUTOMATION', help='Enable options for automated builds')
 set_config('MOZ_AUTOMATION', depends_if('MOZ_AUTOMATION')(lambda x: True))
 
 
 option(env='OLD_CONFIGURE', nargs=1, help='Path to the old configure script')
 
 option(env='MOZ_CURRENT_PROJECT', nargs=1, help='Current build project')
@@ -553,47 +552,46 @@ def target_variables(target):
 
     return namespace(
         OS_TARGET=os_target,
         OS_ARCH=os_arch,
         OS_TEST=os_test,
         INTEL_ARCHITECTURE=target.cpu in ('x86', 'x86_64') or None,
     )
 
-set_config('OS_TARGET', delayed_getattr(target_variables, 'OS_TARGET'))
+set_config('OS_TARGET', target_variables.OS_TARGET)
 add_old_configure_assignment('OS_TARGET',
-                             delayed_getattr(target_variables, 'OS_TARGET'))
-set_config('OS_ARCH', delayed_getattr(target_variables, 'OS_ARCH'))
+                             target_variables.OS_TARGET)
+set_config('OS_ARCH', target_variables.OS_ARCH)
 add_old_configure_assignment('OS_ARCH',
-                             delayed_getattr(target_variables, 'OS_ARCH'))
-set_config('OS_TEST', delayed_getattr(target_variables, 'OS_TEST'))
+                             target_variables.OS_ARCH)
+set_config('OS_TEST', target_variables.OS_TEST)
 add_old_configure_assignment('OS_TEST',
-                             delayed_getattr(target_variables, 'OS_TEST'))
-set_config('CPU_ARCH', delayed_getattr(target, 'cpu'))
-add_old_configure_assignment('CPU_ARCH', delayed_getattr(target, 'cpu'))
-set_config('INTEL_ARCHITECTURE', delayed_getattr(target_variables,
-                                                 'INTEL_ARCHITECTURE'))
-set_config('TARGET_CPU', delayed_getattr(target, 'raw_cpu'))
-set_config('TARGET_OS', delayed_getattr(target, 'raw_os'))
+                             target_variables.OS_TEST)
+set_config('CPU_ARCH', target.cpu)
+add_old_configure_assignment('CPU_ARCH', target.cpu)
+set_config('INTEL_ARCHITECTURE', target_variables.INTEL_ARCHITECTURE)
+set_config('TARGET_CPU', target.raw_cpu)
+set_config('TARGET_OS', target.raw_os)
 
 
 @depends(host)
 def host_variables(host):
     if host.kernel == 'kFreeBSD':
         os_arch = 'GNU_kFreeBSD'
     else:
         os_arch = host.kernel
     return namespace(
         HOST_OS_ARCH=os_arch,
     )
 
-set_config('HOST_CPU_ARCH', delayed_getattr(host, 'cpu'))
-set_config('HOST_OS_ARCH', delayed_getattr(host_variables, 'HOST_OS_ARCH'))
+set_config('HOST_CPU_ARCH', host.cpu)
+set_config('HOST_OS_ARCH', host_variables.HOST_OS_ARCH)
 add_old_configure_assignment('HOST_OS_ARCH',
-                             delayed_getattr(host_variables, 'HOST_OS_ARCH'))
+                             host_variables.HOST_OS_ARCH)
 
 @depends(target)
 def target_is_windows(target):
     if target.kernel == 'WINNT':
         return True
 
 set_define('_WINDOWS', target_is_windows)
 set_define('WIN32', target_is_windows)
@@ -712,29 +710,24 @@ def milestone(build_env, _):
         is_nightly = True
     elif 'a' not in milestone:
         is_release_or_beta = True
 
     return namespace(version=milestone,
                      is_nightly=is_nightly,
                      is_release_or_beta=is_release_or_beta)
 
-@depends(milestone)
-def is_nightly(milestone):
-    return milestone.is_nightly
-
-set_config('GRE_MILESTONE', delayed_getattr(milestone, 'version'))
-set_config('NIGHTLY_BUILD', is_nightly)
-set_define('NIGHTLY_BUILD', is_nightly)
-add_old_configure_assignment('NIGHTLY_BUILD',
-                             is_nightly)
-set_config('RELEASE_OR_BETA', delayed_getattr(milestone, 'is_release_or_beta'))
-set_define('RELEASE_OR_BETA', delayed_getattr(milestone, 'is_release_or_beta'))
+set_config('GRE_MILESTONE', milestone.version)
+set_config('NIGHTLY_BUILD', milestone.is_nightly)
+set_define('NIGHTLY_BUILD', milestone.is_nightly)
+add_old_configure_assignment('NIGHTLY_BUILD', milestone.is_nightly)
+set_config('RELEASE_OR_BETA', milestone.is_release_or_beta)
+set_define('RELEASE_OR_BETA', milestone.is_release_or_beta)
 add_old_configure_assignment('RELEASE_OR_BETA',
-                             delayed_getattr(milestone, 'is_release_or_beta'))
+                             milestone.is_release_or_beta)
 
 # The app update channel is 'default' when not supplied. The value is used in
 # the application's confvars.sh (and is made available to a project specific
 # moz.configure).
 option('--enable-update-channel',
        nargs=1,
        help='Select application update channel',
        default='default')
--- a/build/moz.configure/keyfiles.configure
+++ b/build/moz.configure/keyfiles.configure
@@ -55,10 +55,10 @@ def id_and_secret_keyfile(desc):
         )
 
     content = keyfile(desc, help='Use the client id and secret key contained '
                                  'in the given keyfile for %s requests' % desc,
                       callback=id_and_secret)
 
 
     name = desc.upper().replace(' ', '_')
-    set_config('MOZ_%s_CLIENTID' % name, delayed_getattr(content, 'id'))
-    set_config('MOZ_%s_KEY' % name, delayed_getattr(content, 'secret'))
+    set_config('MOZ_%s_CLIENTID' % name, content.id)
+    set_config('MOZ_%s_KEY' % name, content.secret)
--- a/build/moz.configure/toolchain.configure
+++ b/build/moz.configure/toolchain.configure
@@ -22,19 +22,19 @@ def yasm_version(yasm):
         yasm, '--version',
         onerror=lambda: die('Failed to get yasm version.')
     ).splitlines()[0].split()[1]
     return Version(version)
 
 # Until we move all the yasm consumers out of old-configure.
 # bug 1257904
 add_old_configure_assignment('_YASM_MAJOR_VERSION',
-                             delayed_getattr(yasm_version, 'major'))
+                             yasm_version.major)
 add_old_configure_assignment('_YASM_MINOR_VERSION',
-                             delayed_getattr(yasm_version, 'minor'))
+                             yasm_version.minor)
 
 @depends(yasm, target)
 def yasm_asflags(yasm, target):
     if yasm:
         asflags = {
             ('OSX', 'x86'): '-f macho32',
             ('OSX', 'x86_64'): '-f macho64',
             ('WINNT', 'x86'): '-f win32',
@@ -640,17 +640,17 @@ def compiler(language, host_or_target, c
                     for k, v in other_compiler.__dict__.iteritems()
                 })
 
     # Normally, we'd use `var` instead of `_var`, but the interaction with
     # old-configure complicates things, and for now, we a) can't take the plain
     # result from check_prog as CC/CXX/HOST_CC/HOST_CXX and b) have to let
     # old-configure AC_SUBST it (because it's autoconf doing it, not us)
     compiler = check_prog('_%s' % var, what=what, progs=default_compilers,
-                          input=delayed_getattr(provided_compiler, 'compiler'),
+                          input=provided_compiler.compiler,
                           paths=toolchain_search_path)
 
     @depends(compiler, provided_compiler, compiler_wrapper, host_or_target)
     @checking('whether %s can be used' % what, lambda x: bool(x))
     @imports(_from='mozbuild.shellutil', _import='quote')
     def valid_compiler(compiler, provided_compiler, compiler_wrapper,
                        host_or_target):
         wrapper = list(compiler_wrapper or ())
@@ -786,21 +786,21 @@ def compiler(language, host_or_target, c
     # be provided.
     add_old_configure_assignment(var, depends_if(valid_compiler)(
         lambda x: list(x.wrapper) + [x.compiler] + list(x.flags)))
 
     # Set CC_TYPE/CC_VERSION/HOST_CC_TYPE/HOST_CC_VERSION to allow
     # old-configure to do some of its still existing checks.
     if language == 'C':
         set_config(
-            '%s_TYPE' % var, delayed_getattr(valid_compiler, 'type'))
+            '%s_TYPE' % var, valid_compiler.type)
         add_old_configure_assignment(
-            '%s_TYPE' % var, delayed_getattr(valid_compiler, 'type'))
+            '%s_TYPE' % var, valid_compiler.type)
         add_old_configure_assignment(
-            '%s_VERSION' % var, delayed_getattr(valid_compiler, 'version'))
+            '%s_VERSION' % var, valid_compiler.version)
 
     valid_compiler = compiler_class(valid_compiler)
 
     def compiler_error():
         raise FatalCheckError('Failed compiling a simple %s source with %s'
                               % (language, what))
 
     valid_compiler.try_compile(check_msg='%s works' % what,
--- a/build/moz.configure/util.configure
+++ b/build/moz.configure/util.configure
@@ -361,37 +361,16 @@ def dependable(obj):
         return depends(when=True)(obj)
     return depends(when=True)(lambda: obj)
 
 
 always = dependable(True)
 never = dependable(False)
 
 
-# Some @depends function return namespaces, and one could want to use one
-# specific attribute from such a namespace as a "value" given to functions
-# such as `set_config`. But those functions do not take immediate values.
-# The `delayed_getattr` function allows access to attributes from the result
-# of a @depends function in a non-immediate manner.
-#   @depends('--option')
-#   def option(value)
-#       return namespace(foo=value)
-#   set_config('FOO', delayed_getattr(option, 'foo')
-@template
-def delayed_getattr(func, key):
-    @depends(func)
-    def result(value):
-        # The @depends function we're being passed may have returned
-        # None, or an object that simply doesn't have the wanted key.
-        # In that case, just return None.
-        return getattr(value, key, None)
-
-    return result
-
-
 # Like @depends, but the decorated function is only called if one of the
 # arguments it would be called with has a positive value (bool(value) is True)
 @template
 def depends_if(*args, **kwargs):
     if kwargs:
         assert len(kwargs) == 1
         when = kwargs['when']
     else:
--- a/build/moz.configure/windows.configure
+++ b/build/moz.configure/windows.configure
@@ -148,17 +148,17 @@ def valid_windows_sdk_dir(compiler, wind
         include=sdk.include,
         lib=sdk.lib,
         version=biggest_version,
     )
 
 
 add_old_configure_assignment(
     'WINDOWSSDKDIR',
-    delayed_getattr(valid_windows_sdk_dir, 'path'))
+    valid_windows_sdk_dir.path)
 add_old_configure_assignment(
     'MOZ_WINSDK_MAXVER',
     depends(valid_windows_sdk_dir)(
         lambda x: '0x%04X0000' % x.version if x else None))
 
 
 @imports(_from='mozbuild.shellutil', _import='quote')
 def valid_ucrt_sdk_dir_result(value):
--- a/build/mozconfig.common
+++ b/build/mozconfig.common
@@ -11,16 +11,19 @@
 # of this file.
 
 mk_add_options AUTOCLOBBER=1
 
 ac_add_options --enable-crashreporter
 
 ac_add_options --enable-release
 
+# Tell the build system where to find llvm-config for builds on automation.
+export LLVM_CONFIG="${TOOLTOOL_DIR:-$topsrcdir}/clang/bin/llvm-config"
+
 # Enable checking that add-ons are signed by the trusted root
 MOZ_ADDON_SIGNING=${MOZ_ADDON_SIGNING-1}
 # Disable enforcing that add-ons are signed by the trusted root
 MOZ_REQUIRE_SIGNING=${MOZ_REQUIRE_SIGNING-0}
 
 ac_add_options --enable-js-shell
 
 . "$topsrcdir/build/mozconfig.automation"
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -968,16 +968,17 @@ endif
 #
 # but, given the idiosyncracies of make, can also be called without arguments:
 #
 #   $(call CARGO_BUILD)
 define CARGO_BUILD
 env $(environment_cleaner) $(rustflags_override) \
 	CARGO_TARGET_DIR=$(CARGO_TARGET_DIR) \
 	RUSTC=$(RUSTC) \
+	MOZ_SRC=$(topsrcdir) \
 	MOZ_DIST=$(ABS_DIST) \
 	LIBCLANG_PATH=$(MOZ_LIBCLANG_PATH) \
 	CLANG_PATH=$(MOZ_CLANG_PATH) \
 	PKG_CONFIG_ALLOW_CROSS=1 \
 	RUST_BACKTRACE=1 \
 	MOZ_TOPOBJDIR=$(topobjdir) \
 	$(1) \
 	$(CARGO) build $(cargo_build_flags)
--- a/devtools/.eslintrc.js
+++ b/devtools/.eslintrc.js
@@ -23,16 +23,18 @@ module.exports = {
     "loader": true,
     "module": true,
     "Node": true,
     "reportError": true,
     "require": true,
     "setInterval": true,
     "setTimeout": true,
     "uneval": true,
+    "TextDecoder": true,
+    "TextEncoder": true,
     "URL": true,
     "WebSocket": true,
     "XMLHttpRequest": true
   },
   "rules": {
     // These are the rules that have been configured so far to match the
     // devtools coding style.
 
--- a/devtools/client/debugger/new/debugger.js
+++ b/devtools/client/debugger/new/debugger.js
@@ -3379,17 +3379,17 @@ return /******/ (function(modules) { // 
 	    isDevelopment = _require5.isDevelopment;
 
 	var L10N = __webpack_require__(185);
 
 	var _require6 = __webpack_require__(966),
 	    showMenu = _require6.showMenu,
 	    buildMenu = _require6.buildMenu;
 
-	setConfig(({"environment":"firefox-panel","logging":false,"clientLogging":false,"firefox":{"mcPath":"./firefox"},"workers":{"parserURL":"resource://devtools/client/debugger/new/parser-worker.js","prettyPrintURL":"resource://devtools/client/debugger/new/pretty-print-worker.js"},"features":{"blackbox":{"enabled":true},"chromeScopes":{"enabled":false},"eventListeners":{"enabled":false},"codeCoverage":{"enabled":false},"searchNav":{"enabled":true}}}));
+	setConfig(({"environment":"firefox-panel","logging":false,"clientLogging":false,"firefox":{"mcPath":"./firefox"},"workers":{"parserURL":"resource://devtools/client/debugger/new/parser-worker.js","prettyPrintURL":"resource://devtools/client/debugger/new/pretty-print-worker.js"},"features":{"blackbox":{"enabled":true},"chromeScopes":{"enabled":false},"eventListeners":{"enabled":false},"codeCoverage":{"enabled":false},"searchNav":{"enabled":true},"collapseFrame":{"enabled":true}}}));
 
 	// Set various flags before requiring app code.
 	if (getValue("logging.client")) {
 	  // DevToolsUtils.dumpn.wantLogging = true;
 	}
 
 	var _require7 = __webpack_require__(885),
 	    firefox = _require7.firefox,
@@ -13295,29 +13295,31 @@ return /******/ (function(modules) { // 
 	  pref("devtools.debugger.client-source-maps-enabled", true);
 	  pref("devtools.debugger.pause-on-exceptions", false);
 	  pref("devtools.debugger.ignore-caught-exceptions", false);
 	  pref("devtools.debugger.call-stack-visible", false);
 	  pref("devtools.debugger.scopes-visible", false);
 	  pref("devtools.debugger.start-panel-collapsed", false);
 	  pref("devtools.debugger.end-panel-collapsed", false);
 	  pref("devtools.debugger.tabs", "[]");
+	  pref("devtools.debugger.ui.framework-grouping-on", true);
 	  pref("devtools.debugger.pending-selected-location", "{}");
 	  pref("devtools.debugger.pending-breakpoints", "[]");
 	  pref("devtools.debugger.expressions", "[]");
 	}
 
 	const prefs = new PrefsHelper("devtools", {
 	  clientSourceMapsEnabled: ["Bool", "debugger.client-source-maps-enabled"],
 	  pauseOnExceptions: ["Bool", "debugger.pause-on-exceptions"],
 	  ignoreCaughtExceptions: ["Bool", "debugger.ignore-caught-exceptions"],
 	  callStackVisible: ["Bool", "debugger.call-stack-visible"],
 	  scopesVisible: ["Bool", "debugger.scopes-visible"],
 	  startPanelCollapsed: ["Bool", "debugger.start-panel-collapsed"],
 	  endPanelCollapsed: ["Bool", "debugger.end-panel-collapsed"],
+	  frameworkGroupingOn: ["Bool", "debugger.ui.framework-grouping-on"],
 	  tabs: ["Json", "debugger.tabs"],
 	  pendingSelectedLocation: ["Json", "debugger.pending-selected-location"],
 	  pendingBreakpoints: ["Json", "debugger.pending-breakpoints"],
 	  expressions: ["Json", "debugger.expressions"]
 	});
 
 	module.exports = { prefs };
 
@@ -13557,16 +13559,17 @@ return /******/ (function(modules) { // 
 	  UPDATE_EXPRESSION: "UPDATE_EXPRESSION",
 	  DELETE_EXPRESSION: "DELETE_EXPRESSION",
 
 	  RECORD_COVERAGE: "RECORD_COVERAGE",
 
 	  TOGGLE_PROJECT_SEARCH: "TOGGLE_PROJECT_SEARCH",
 	  TOGGLE_FILE_SEARCH: "TOGGLE_FILE_SEARCH",
 	  TOGGLE_SYMBOL_SEARCH: "TOGGLE_SYMBOL_SEARCH",
+	  TOGGLE_FRAMEWORK_GROUPING: "TOGGLE_FRAMEWORK_GROUPING",
 	  SET_SYMBOL_SEARCH_TYPE: "SET_SYMBOL_SEARCH_TYPE",
 	  UPDATE_FILE_SEARCH_QUERY: "UPDATE_FILE_SEARCH_QUERY",
 	  TOGGLE_FILE_SEARCH_MODIFIER: "TOGGLE_FILE_SEARCH_MODIFIER",
 	  SHOW_SOURCE: "SHOW_SOURCE",
 	  TOGGLE_PANE: "TOGGLE_PANE"
 	};
 
 /***/ },
@@ -14769,59 +14772,47 @@ return /******/ (function(modules) { // 
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	Object.defineProperty(exports, "__esModule", {
 	  value: true
 	});
 	exports.getSelectedFrame = exports.getLoadedObjects = exports.getPause = exports.State = undefined;
+
+	var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+	/* 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/. */
+
 	exports.getLoadedObject = getLoadedObject;
 	exports.getObjectProperties = getObjectProperties;
 	exports.getIsWaitingOnBreak = getIsWaitingOnBreak;
 	exports.getShouldPauseOnExceptions = getShouldPauseOnExceptions;
 	exports.getShouldIgnoreCaughtExceptions = getShouldIgnoreCaughtExceptions;
 	exports.getFrames = getFrames;
 	exports.getDebuggeeUrl = getDebuggeeUrl;
 	exports.getChromeScopes = getChromeScopes;
 
 	var _reselect = __webpack_require__(993);
 
-	var _fromJS = __webpack_require__(237);
-
-	var _fromJS2 = _interopRequireDefault(_fromJS);
-
-	var _makeRecord = __webpack_require__(230);
-
-	var _makeRecord2 = _interopRequireDefault(_makeRecord);
-
 	var _prefs = __webpack_require__(226);
 
-	var _immutable = __webpack_require__(146);
-
-	var I = _interopRequireWildcard(_immutable);
-
 	var _constants = __webpack_require__(229);
 
 	var _constants2 = _interopRequireDefault(_constants);
 
-	function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
-
-	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-	/* This Source Code Form is subject to the terms of the Mozilla Public
-	 * License, v. 2.0. If a copy of the MPL was not distributed with this
-	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-	var State = exports.State = (0, _makeRecord2.default)({
+	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+	var State = exports.State = () => ({
 	  pause: undefined,
 	  isWaitingOnBreak: false,
 	  frames: undefined,
 	  selectedFrameId: undefined,
-	  loadedObjects: I.Map(),
+	  loadedObjects: {},
 	  shouldPauseOnExceptions: _prefs.prefs.pauseOnExceptions,
 	  shouldIgnoreCaughtExceptions: _prefs.prefs.ignoreCaughtExceptions,
 	  debuggeeUrl: ""
 	});
 
 	function update() {
 	  var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : State();
 	  var action = arguments[1];
@@ -14837,85 +14828,89 @@ return /******/ (function(modules) { // 
 	        pauseInfo.isInterrupted = pauseInfo.why.type === "interrupted";
 
 	        // turn this into an object keyed by object id
 	        var objectMap = {};
 	        _loadedObjects.forEach(obj => {
 	          objectMap[obj.value.objectId] = obj;
 	        });
 
-	        return state.merge({
+	        return Object.assign({}, state, {
 	          isWaitingOnBreak: false,
-	          pause: (0, _fromJS2.default)(pauseInfo),
+	          pause: pauseInfo,
 	          selectedFrameId: _selectedFrameId,
 	          frames: _frames,
 	          loadedObjects: objectMap
 	        });
 	      }
 
 	    case _constants2.default.RESUME:
-	      return state.merge({
+	      return Object.assign({}, state, {
 	        pause: null,
 	        frames: null,
 	        selectedFrameId: null,
 	        loadedObjects: {}
 	      });
 
 	    case _constants2.default.TOGGLE_PRETTY_PRINT:
 	      if (action.status == "done") {
 	        var _frames2 = action.value.frames;
-	        var _pause = state.get("pause");
+	        var _pause = state.pause;
 	        if (_pause) {
-	          _pause = _pause.set("frame", (0, _fromJS2.default)(_frames2[0]));
-	        }
-
-	        return state.merge({ pause: _pause, frames: _frames2 });
+	          _pause.frame = _frames2[0];
+	        }
+
+	        return Object.assign({}, state, { pause: _pause, frames: _frames2 });
 	      }
 
 	      break;
 	    case _constants2.default.BREAK_ON_NEXT:
-	      return state.set("isWaitingOnBreak", true);
+	      return Object.assign({}, state, { isWaitingOnBreak: true });
 
 	    case _constants2.default.SELECT_FRAME:
-	      return state.set("selectedFrameId", action.frame.id);
+	      return Object.assign({}, state, { selectedFrameId: action.frame.id });
 
 	    case _constants2.default.LOAD_OBJECT_PROPERTIES:
 	      if (action.status === "start") {
-	        return state.setIn(["loadedObjects", action.objectId], {});
+	        return _extends({}, state, {
+	          loadedObjects: _extends({}, state.loadedObjects, {
+	            [action.objectId]: {}
+	          })
+	        });
 	      }
 
 	      if (action.status === "done") {
 	        if (!action.value) {
-	          return state;
+	          return Object.assign({}, state);
 	        }
 
 	        var ownProperties = action.value.ownProperties;
 	        var ownSymbols = action.value.ownSymbols || [];
 	        var prototype = action.value.prototype;
 
-	        return state.setIn(["loadedObjects", action.objectId], {
-	          ownProperties,
-	          prototype,
-	          ownSymbols
+	        return _extends({}, state, {
+	          loadedObjects: _extends({}, state.loadedObjects, {
+	            [action.objectId]: { ownProperties, prototype, ownSymbols }
+	          })
 	        });
 	      }
 	      break;
 
 	    case _constants2.default.NAVIGATE:
-	      return State().set("debuggeeUrl", action.url);
+	      return Object.assign({}, State(), { debuggeeUrl: action.url });
 
 	    case _constants2.default.PAUSE_ON_EXCEPTIONS:
 	      var _shouldPauseOnExceptions = action.shouldPauseOnExceptions,
 	          _shouldIgnoreCaughtExceptions = action.shouldIgnoreCaughtExceptions;
 
 
 	      _prefs.prefs.pauseOnExceptions = _shouldPauseOnExceptions;
 	      _prefs.prefs.ignoreCaughtExceptions = _shouldIgnoreCaughtExceptions;
 
-	      return state.merge({
+	      return Object.assign({}, state, {
 	        shouldPauseOnExceptions: _shouldPauseOnExceptions,
 	        shouldIgnoreCaughtExceptions: _shouldIgnoreCaughtExceptions
 	      });
 	  }
 
 	  return state;
 	}
 
@@ -14927,56 +14922,57 @@ return /******/ (function(modules) { // 
 	// module for the UI, and all of those selectors should take the
 	// top-level app state, so we'd have to "wrap" them to automatically
 	// pick off the piece of state we're interested in. It's impossible
 	// (right now) to type those wrapped functions.
 
 
 	var getPauseState = state => state.pause;
 
-	var getPause = exports.getPause = (0, _reselect.createSelector)(getPauseState, pauseWrapper => pauseWrapper.get("pause"));
-
-	var getLoadedObjects = exports.getLoadedObjects = (0, _reselect.createSelector)(getPauseState, pauseWrapper => pauseWrapper.get("loadedObjects"));
+	var getPause = exports.getPause = (0, _reselect.createSelector)(getPauseState, pauseWrapper => pauseWrapper.pause);
+
+	var getLoadedObjects = exports.getLoadedObjects = (0, _reselect.createSelector)(getPauseState, pauseWrapper => pauseWrapper.loadedObjects);
 
 	function getLoadedObject(state, objectId) {
-	  return getLoadedObjects(state).get(objectId);
+	  return getLoadedObjects(state)[objectId];
 	}
 
 	function getObjectProperties(state, parentId) {
-	  return getLoadedObjects(state).filter(obj => obj.get("parentId") == parentId);
+	  return getLoadedObjects(state).filter(obj => obj.parentId == parentId);
 	}
 
 	function getIsWaitingOnBreak(state) {
-	  return state.pause.get("isWaitingOnBreak");
+	  return state.pause.isWaitingOnBreak;
 	}
 
 	function getShouldPauseOnExceptions(state) {
-	  return state.pause.get("shouldPauseOnExceptions");
+	  return state.pause.shouldPauseOnExceptions;
 	}
 
 	function getShouldIgnoreCaughtExceptions(state) {
-	  return state.pause.get("shouldIgnoreCaughtExceptions");
+	  return state.pause.shouldIgnoreCaughtExceptions;
 	}
 
 	function getFrames(state) {
-	  return state.pause.get("frames");
-	}
-
-	var getSelectedFrameId = (0, _reselect.createSelector)(getPauseState, pauseWrapper => pauseWrapper.get("selectedFrameId"));
+	  return state.pause.frames;
+	}
+
+	var getSelectedFrameId = (0, _reselect.createSelector)(getPauseState, pauseWrapper => {
+	  return pauseWrapper.selectedFrameId;
+	});
 
 	var getSelectedFrame = exports.getSelectedFrame = (0, _reselect.createSelector)(getSelectedFrameId, getFrames, (selectedFrameId, frames) => {
 	  if (!frames) {
 	    return null;
 	  }
-
-	  return frames.find(frame => frame.get("id") == selectedFrameId).toJS();
+	  return frames.find(frame => frame.id == selectedFrameId);
 	});
 
 	function getDebuggeeUrl(state) {
-	  return state.pause.get("debuggeeUrl");
+	  return state.pause.debuggeeUrl;
 	}
 
 	// NOTE: currently only used for chrome
 	function getChromeScopes(state) {
 	  var frame = getSelectedFrame(state);
 	  return frame ? frame.scopeChain : undefined;
 	}
 
@@ -14989,16 +14985,17 @@ return /******/ (function(modules) { // 
 	"use strict";
 
 	Object.defineProperty(exports, "__esModule", {
 	  value: true
 	});
 	exports.getSymbolSearchState = exports.getFileSearchState = exports.getProjectSearchState = exports.State = undefined;
 	exports.getFileSearchQueryState = getFileSearchQueryState;
 	exports.getFileSearchModifierState = getFileSearchModifierState;
+	exports.getFrameworkGroupingState = getFrameworkGroupingState;
 	exports.getSymbolSearchType = getSymbolSearchType;
 	exports.getShownSource = getShownSource;
 	exports.getPaneCollapse = getPaneCollapse;
 	exports.getHighlightedLineRange = getHighlightedLineRange;
 
 	var _makeRecord = __webpack_require__(230);
 
 	var _makeRecord2 = _interopRequireDefault(_makeRecord);
@@ -15020,16 +15017,17 @@ return /******/ (function(modules) { // 
 	    regexMatch: false
 	  })(),
 	  projectSearchOn: false,
 	  symbolSearchOn: false,
 	  symbolSearchType: "functions",
 	  shownSource: "",
 	  startPanelCollapsed: _prefs.prefs.startPanelCollapsed,
 	  endPanelCollapsed: _prefs.prefs.endPanelCollapsed,
+	  frameworkGroupingOn: _prefs.prefs.frameworkGroupingOn,
 	  highlightedLineRange: undefined
 	});
 
 	/**
 	 * UI reducer
 	 * @module reducers/ui
 	 */
 
@@ -15038,16 +15036,22 @@ return /******/ (function(modules) { // 
 	  var action = arguments[1];
 
 	  switch (action.type) {
 	    case _constants2.default.TOGGLE_PROJECT_SEARCH:
 	      {
 	        return state.set("projectSearchOn", action.value);
 	      }
 
+	    case _constants2.default.TOGGLE_FRAMEWORK_GROUPING:
+	      {
+	        _prefs.prefs.frameworkGroupingOn = action.value;
+	        return state.set("frameworkGroupingOn", action.value);
+	      }
+
 	    case _constants2.default.TOGGLE_FILE_SEARCH:
 	      {
 	        return state.set("fileSearchOn", action.value);
 	      }
 
 	    case _constants2.default.TOGGLE_SYMBOL_SEARCH:
 	      {
 	        return state.set("symbolSearchOn", action.value);
@@ -15118,16 +15122,20 @@ return /******/ (function(modules) { // 
 	function getFileSearchQueryState(state) {
 	  return state.ui.get("fileSearchQuery");
 	}
 
 	function getFileSearchModifierState(state) {
 	  return state.ui.get("fileSearchModifiers");
 	}
 
+	function getFrameworkGroupingState(state) {
+	  return state.ui.get("frameworkGroupingOn");
+	}
+
 	function getSymbolSearchType(state) {
 	  return state.ui.get("symbolSearchType");
 	}
 
 	var getProjectSearchState = exports.getProjectSearchState = getSearchState.bind(null, "projectSearchOn");
 	var getFileSearchState = exports.getFileSearchState = getSearchState.bind(null, "fileSearchOn");
 	var getSymbolSearchState = exports.getSymbolSearchState = getSearchState.bind(null, "symbolSearchOn");
 
@@ -15274,16 +15282,17 @@ return /******/ (function(modules) { // 
 	  getCoverageEnabled: coverage.getCoverageEnabled,
 
 	  getEventListeners: eventListeners.getEventListeners,
 
 	  getProjectSearchState: ui.getProjectSearchState,
 	  getFileSearchState: ui.getFileSearchState,
 	  getFileSearchQueryState: ui.getFileSearchQueryState,
 	  getFileSearchModifierState: ui.getFileSearchModifierState,
+	  getFrameworkGroupingState: ui.getFrameworkGroupingState,
 	  getSymbolSearchState: ui.getSymbolSearchState,
 	  getSymbolSearchType: ui.getSymbolSearchType,
 	  getShownSource: ui.getShownSource,
 	  getPaneCollapse: ui.getPaneCollapse,
 
 	  getExpressions: expressions.getExpressions,
 	  getVisibleExpressions: expressions.getVisibleExpressions,
 	  getExpression: expressions.getExpression,
@@ -15536,17 +15545,17 @@ return /******/ (function(modules) { // 
 	var ui = _interopRequireWildcard(_ui);
 
 	var _coverage = __webpack_require__(322);
 
 	var coverage = _interopRequireWildcard(_coverage);
 
 	function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
 
-	exports.default = Object.assign(navigation, breakpoints, expressions, eventListeners, sources, pause, ui, coverage);
+	exports.default = Object.assign({}, navigation, breakpoints, expressions, eventListeners, sources, pause, ui, coverage);
 
 /***/ },
 /* 245 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	Object.defineProperty(exports, "__esModule", {
@@ -16888,17 +16897,17 @@ return /******/ (function(modules) { // 
 	        }),
 	            code = _ref16.code,
 	            mappings = _ref16.mappings;
 
 	        yield sourceMaps.applySourceMap(source.id, url, code, mappings);
 
 	        var frames = (0, _selectors.getFrames)(getState());
 	        if (frames) {
-	          frames = yield (0, _pause.updateFrameLocations)(frames.toJS(), sourceMaps);
+	          frames = yield (0, _pause.updateFrameLocations)(frames, sourceMaps);
 	        }
 
 	        dispatch(selectSource(originalSource.id));
 
 	        return { text: code, contentType: "text/javascript", frames };
 	      })()
 	    });
 	  };
@@ -17076,44 +17085,45 @@ return /******/ (function(modules) { // 
 	    }
 
 	    return deferred.promise;
 	  };
 	}
 
 /***/ },
 /* 255 */
-/***/ function(module, exports) {
+/***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	Object.defineProperty(exports, "__esModule", {
 	  value: true
 	});
 	exports.updateFrameLocations = updateFrameLocations;
 	exports.getPauseReason = getPauseReason;
+
+	var get = __webpack_require__(67);
 	function updateFrameLocations(frames, sourceMaps) {
 	  if (!frames || frames.length == 0) {
 	    return Promise.resolve(frames);
 	  }
 
 	  return Promise.all(frames.map(frame => {
 	    return sourceMaps.getOriginalLocation(frame.location).then(loc => {
-	      return Object.assign(frame, {
+	      return Object.assign({}, frame, {
 	        location: loc
 	      });
 	    });
 	  }));
 	}
 
 	// Map protocol pause "why" reason to a valid L10N key
 	// These are the known unhandled reasons:
 	// "breakpointConditionThrown", "clientEvaluated"
 	// "interrupted", "attached"
-
 	var reasons = {
 	  debuggerStatement: "whyPaused.debuggerStatement",
 	  breakpoint: "whyPaused.breakpoint",
 	  exception: "whyPaused.exception",
 	  resumeLimit: "whyPaused.resumeLimit",
 	  pauseOnDOMEvents: "whyPaused.pauseOnDOMEvents",
 	  breakpointConditionThrown: "whyPaused.breakpointConditionThrown",
 
@@ -17127,17 +17137,17 @@ return /******/ (function(modules) { // 
 	  other: "whyPaused.other"
 	};
 
 	function getPauseReason(pauseInfo) {
 	  if (!pauseInfo) {
 	    return null;
 	  }
 
-	  var reasonType = pauseInfo.getIn(["why"]).get("type");
+	  var reasonType = get(pauseInfo, "why.type", null);
 	  if (!reasons[reasonType]) {
 	    console.log("Please file an issue: reasonType=", reasonType);
 	  }
 	  return reasons[reasonType];
 	}
 
 /***/ },
 /* 256 */,
@@ -19492,17 +19502,17 @@ return /******/ (function(modules) { // 
 	          why = pauseInfo.why,
 	          loadedObjects = pauseInfo.loadedObjects;
 
 	      frames = yield (0, _pause.updateFrameLocations)(frames, sourceMaps);
 	      var frame = frames[0];
 
 	      dispatch({
 	        type: _constants2.default.PAUSED,
-	        pauseInfo: { why, frame },
+	        pauseInfo: { why, frame, frames },
 	        frames: frames,
 	        selectedFrameId: frame.id,
 	        loadedObjects: loadedObjects || []
 	      });
 
 	      dispatch((0, _expressions.evaluateExpressions)(frame.id));
 
 	      dispatch((0, _sources.selectSource)(frame.location.sourceId, { line: frame.location.line }));
@@ -19779,16 +19789,17 @@ return /******/ (function(modules) { // 
 	"use strict";
 
 	Object.defineProperty(exports, "__esModule", {
 	  value: true
 	});
 	exports.toggleProjectSearch = toggleProjectSearch;
 	exports.toggleFileSearch = toggleFileSearch;
 	exports.toggleSymbolSearch = toggleSymbolSearch;
+	exports.toggleFrameworkGrouping = toggleFrameworkGrouping;
 	exports.setSelectedSymbolType = setSelectedSymbolType;
 	exports.setFileSearchQuery = setFileSearchQuery;
 	exports.toggleFileSearchModifier = toggleFileSearchModifier;
 	exports.showSource = showSource;
 	exports.togglePaneCollapse = togglePaneCollapse;
 	exports.highlightLineRange = highlightLineRange;
 	exports.clearHighlightLineRange = clearHighlightLineRange;
 
@@ -19850,22 +19861,34 @@ return /******/ (function(modules) { // 
 
 	    dispatch({
 	      type: _constants2.default.TOGGLE_SYMBOL_SEARCH,
 	      value: toggleValue
 	    });
 	  };
 	}
 
-	function setSelectedSymbolType(symbolType) {
+	function toggleFrameworkGrouping(toggleValue) {
 	  return (_ref4) => {
 	    var dispatch = _ref4.dispatch,
 	        getState = _ref4.getState;
 
 	    dispatch({
+	      type: _constants2.default.TOGGLE_FRAMEWORK_GROUPING,
+	      value: toggleValue
+	    });
+	  };
+	}
+
+	function setSelectedSymbolType(symbolType) {
+	  return (_ref5) => {
+	    var dispatch = _ref5.dispatch,
+	        getState = _ref5.getState;
+
+	    dispatch({
 	      type: _constants2.default.SET_SYMBOL_SEARCH_TYPE,
 	      symbolType
 	    });
 	  };
 	}
 
 	function setFileSearchQuery(query) {
 	  return {
@@ -19874,19 +19897,19 @@ return /******/ (function(modules) { // 
 	  };
 	}
 
 	function toggleFileSearchModifier(modifier) {
 	  return { type: _constants2.default.TOGGLE_FILE_SEARCH_MODIFIER, modifier };
 	}
 
 	function showSource(sourceId) {
-	  return (_ref5) => {
-	    var dispatch = _ref5.dispatch,
-	        getState = _ref5.getState;
+	  return (_ref6) => {
+	    var dispatch = _ref6.dispatch,
+	        getState = _ref6.getState;
 
 	    var source = (0, _selectors.getSource)(getState(), sourceId);
 	    dispatch({
 	      type: _constants2.default.SHOW_SOURCE,
 	      sourceUrl: source.get("url")
 	    });
 	  };
 	}
@@ -24673,17 +24696,17 @@ return /******/ (function(modules) { // 
 	  enableBreakpoint: _react.PropTypes.func.isRequired,
 	  removeBreakpoint: _react.PropTypes.func.isRequired,
 	  setBreakpointCondition: _react.PropTypes.func.isRequired,
 	  selectSource: _react.PropTypes.func,
 	  jumpToMappedLocation: _react.PropTypes.func,
 	  toggleBlackBox: _react.PropTypes.func,
 	  showSource: _react.PropTypes.func,
 	  coverageOn: _react.PropTypes.bool,
-	  pauseData: _reactImmutableProptypes2.default.map,
+	  pauseData: _react.PropTypes.object,
 	  selectedFrame: _react.PropTypes.object,
 	  getExpression: _react.PropTypes.func.isRequired,
 	  addExpression: _react.PropTypes.func.isRequired,
 	  horizontal: _react.PropTypes.bool,
 	  query: _react.PropTypes.string.isRequired,
 	  searchModifiers: _reactImmutableProptypes2.default.recordOf({
 	    caseSensitive: _react.PropTypes.bool.isRequired,
 	    regexMatch: _react.PropTypes.bool.isRequired,
@@ -26498,17 +26521,17 @@ return /******/ (function(modules) { // 
 
 
 	    popoverTarget.classList.add("selected-token");
 
 	    if (!value || !value.type == "object") {
 	      return;
 	    }
 
-	    if (value.actor && !loadedObjects.has(value.actor)) {
+	    if (value.actor && !loadedObjects[value.actor]) {
 	      loadObjectProperties(value);
 	    }
 	  }
 
 	  componentWillUnmount() {
 	    var popoverTarget = this.props.popoverTarget;
 
 	    popoverTarget.classList.remove("selected-token");
@@ -26550,17 +26573,17 @@ return /******/ (function(modules) { // 
 	  }
 
 	  renderObjectInspector(root) {
 	    var _props2 = this.props,
 	        loadObjectProperties = _props2.loadObjectProperties,
 	        loadedObjects = _props2.loadedObjects;
 
 
-	    var getObjectProperties = id => loadedObjects.get(id);
+	    var getObjectProperties = id => loadedObjects[id];
 	    var roots = this.getChildren(root, getObjectProperties);
 
 	    return ObjectInspector({
 	      roots,
 	      getObjectProperties,
 	      autoExpandDepth: 0,
 	      onDoubleClick: () => {},
 	      loadObjectProperties
@@ -28149,17 +28172,17 @@ return /******/ (function(modules) { // 
 	      className: "secondary-panes",
 	      style: { overflowX: "hidden" }
 	    }, CommandBar(), WhyPaused(), this.props.horizontal ? this.renderHorizontalLayout() : this.renderVerticalLayout());
 	  }
 	}
 
 	SecondaryPanes.propTypes = {
 	  evaluateExpressions: _react.PropTypes.func.isRequired,
-	  pauseData: _reactImmutableProptypes2.default.map,
+	  pauseData: _react.PropTypes.object,
 	  horizontal: _react.PropTypes.bool,
 	  breakpoints: _reactImmutableProptypes2.default.map.isRequired,
 	  breakpointsDisabled: _react.PropTypes.bool,
 	  breakpointsLoading: _react.PropTypes.bool,
 	  toggleAllBreakpoints: _react.PropTypes.func.isRequired
 	};
 
 	SecondaryPanes.contextTypes = {
@@ -28351,17 +28374,17 @@ return /******/ (function(modules) { // 
 	      contents: { value }
 	    };
 
 	    return _react.DOM.div({
 	      className: "expression-container",
 	      key: path || input
 	    }, ObjectInspector({
 	      roots: [root],
-	      getObjectProperties: id => loadedObjects.get(id),
+	      getObjectProperties: id => loadedObjects[id],
 	      autoExpandDepth: 0,
 	      onDoubleClick: (item, options) => this.editExpression(expression, options),
 	      loadObjectProperties
 	    }), CloseButton({ handleClick: e => this.deleteExpression(e, expression) }));
 	  }
 
 	  componentDidUpdate() {
 	    if (this._input) {
@@ -28428,60 +28451,57 @@ return /******/ (function(modules) { // 
 	});
 
 	var _react = __webpack_require__(2);
 
 	var _redux = __webpack_require__(3);
 
 	var _reactRedux = __webpack_require__(151);
 
-	var _reactImmutableProptypes = __webpack_require__(150);
-
-	var _reactImmutableProptypes2 = _interopRequireDefault(_reactImmutableProptypes);
-
 	var _actions = __webpack_require__(244);
 
 	var _actions2 = _interopRequireDefault(_actions);
 
 	var _selectors = __webpack_require__(242);
 
 	var _isString = __webpack_require__(602);
 
 	var _isString2 = _interopRequireDefault(_isString);
 
 	var _pause = __webpack_require__(255);
 
 	__webpack_require__(723);
 
 	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
+	var get = __webpack_require__(67);
+
 	function renderExceptionSummary(exception) {
 	  if ((0, _isString2.default)(exception)) {
 	    return exception;
 	  }
 
-	  var message = exception.getIn(["preview", "message"]);
-	  var name = exception.getIn(["preview", "name"]);
+	  var message = get(exception, "preview.message");
+	  var name = get(exception, "preview.name");
 
 	  return `${name}: ${message}`;
 	}
 
-
 	class WhyPaused extends _react.Component {
 	  renderMessage(pauseInfo) {
 	    if (!pauseInfo) {
 	      return null;
 	    }
 
-	    var message = pauseInfo.getIn(["why", "message"]);
+	    var message = get(pauseInfo, "why.message");
 	    if (message) {
 	      return _react.DOM.div({ className: "message" }, message);
 	    }
 
-	    var exception = pauseInfo.getIn(["why", "exception"]);
+	    var exception = get(pauseInfo, "why.exception");
 	    if (exception) {
 	      return _react.DOM.div({ className: "message" }, renderExceptionSummary(exception));
 	    }
 
 	    return null;
 	  }
 
 	  render() {
@@ -28495,17 +28515,17 @@ return /******/ (function(modules) { // 
 
 	    return _react.DOM.div({ className: "pane why-paused" }, _react.DOM.div(null, L10N.getStr(reason)), this.renderMessage(pauseInfo));
 	  }
 	}
 
 	WhyPaused.displayName = "WhyPaused";
 
 	WhyPaused.propTypes = {
-	  pauseInfo: _reactImmutableProptypes2.default.map
+	  pauseInfo: _react.PropTypes.object
 	};
 
 	exports.default = (0, _reactRedux.connect)(state => ({
 	  pauseInfo: (0, _selectors.getPause)(state)
 	}), dispatch => (0, _redux.bindActionCreators)(_actions2.default, dispatch))(WhyPaused);
 
 /***/ },
 /* 723 */
@@ -28555,28 +28575,29 @@ return /******/ (function(modules) { // 
 	var _Close = __webpack_require__(378);
 
 	var _Close2 = _interopRequireDefault(_Close);
 
 	__webpack_require__(726);
 
 	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
+	var get = __webpack_require__(67);
+
+
 	function isCurrentlyPausedAtBreakpoint(pause, breakpoint) {
-	  if (!pause || pause.get("isInterrupted")) {
+	  if (!pause || pause.isInterrupted) {
 	    return false;
 	  }
 
 	  var bpId = (0, _breakpoints.makeLocationId)(breakpoint.location);
-	  var pausedId = (0, _breakpoints.makeLocationId)(pause.getIn(["frame", "location"]).toJS());
-
+	  var pausedId = (0, _breakpoints.makeLocationId)(get(pause, "frame.location"));
 	  return bpId === pausedId;
 	}
 
-
 	function renderSourceLocation(source, line, column) {
 	  var url = source.get("url") ? (0, _path.basename)(source.get("url")) : null;
 	  var bpLocation = line + (column ? `:${column}` : "");
 	  // const line = url !== "" ? `: ${line}` : "";
 	  return url ? _react.DOM.div({ className: "location" }, `${(0, _utils.endTruncateStr)(url, 30)}: ${bpLocation}`) : null;
 	}
 
 	class Breakpoints extends _react.PureComponent {
@@ -28813,17 +28834,17 @@ return /******/ (function(modules) { // 
 	      className: (0, _classnames2.default)({
 	        expanded: expanded,
 	        hidden: nodeIsPrimitive(item)
 	      })
 	    }), _react.DOM.span({ className: "object-label" }, item.name), _react.DOM.span({ className: "object-delimiter" }, objectValue ? ": " : ""), _react.DOM.span({ className: "object-value" }, objectValue || ""));
 	  }
 
 	  getObjectProperties(item) {
-	    this.props.loadedObjects.get(item.contents.value.objectId);
+	    this.props.loadedObjects[item.contents.value.objectId];
 	  }
 
 	  getChildren(item) {
 	    var obj = item.contents;
 
 	    // Nodes can either have children already, or be an object with
 	    // properties that we need to go and fetch.
 	    if (nodeHasChildren(item)) {
@@ -28933,20 +28954,16 @@ return /******/ (function(modules) { // 
 	});
 
 	var _react = __webpack_require__(2);
 
 	var _redux = __webpack_require__(3);
 
 	var _reactRedux = __webpack_require__(151);
 
-	var _reactImmutableProptypes = __webpack_require__(150);
-
-	var _reactImmutableProptypes2 = _interopRequireDefault(_reactImmutableProptypes);
-
 	var _actions = __webpack_require__(244);
 
 	var _actions2 = _interopRequireDefault(_actions);
 
 	var _selectors = __webpack_require__(242);
 
 	var _scopes = __webpack_require__(732);
 
@@ -28955,16 +28972,17 @@ return /******/ (function(modules) { // 
 	var _ObjectInspector3 = _interopRequireDefault(_ObjectInspector2);
 
 	__webpack_require__(729);
 
 	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 	var ObjectInspector = (0, _react.createFactory)(_ObjectInspector3.default);
 
+
 	function info(text) {
 	  return _react.DOM.div({ className: "pane-info" }, text);
 	}
 
 	class Scopes extends _react.PureComponent {
 
 	  constructor(props) {
 	    var pauseInfo = props.pauseInfo,
@@ -29003,28 +29021,28 @@ return /******/ (function(modules) { // 
 	        loadedObjects = _props2.loadedObjects;
 	    var scopes = this.state.scopes;
 
 
 	    var scopeInspector = info(L10N.getStr("scopes.notAvailable"));
 	    if (scopes) {
 	      scopeInspector = ObjectInspector({
 	        roots: scopes,
-	        getObjectProperties: id => loadedObjects.get(id),
+	        getObjectProperties: id => loadedObjects[id],
 	        loadObjectProperties: loadObjectProperties
 	      });
 	    }
 
 	    return _react.DOM.div({ className: "pane scopes-list" }, pauseInfo ? scopeInspector : info(L10N.getStr("scopes.notPaused")));
 	  }
 	}
 
 	Scopes.propTypes = {
-	  pauseInfo: _reactImmutableProptypes2.default.map,
-	  loadedObjects: _reactImmutableProptypes2.default.map,
+	  pauseInfo: _react.PropTypes.object,
+	  loadedObjects: _react.PropTypes.object,
 	  loadObjectProperties: _react.PropTypes.func,
 	  selectedFrame: _react.PropTypes.object
 	};
 
 	Scopes.displayName = "Scopes";
 
 	exports.default = (0, _reactRedux.connect)(state => ({
 	  pauseInfo: (0, _selectors.getPause)(state),
@@ -29048,58 +29066,47 @@ return /******/ (function(modules) { // 
 	var _toPairs = __webpack_require__(195);
 
 	var _toPairs2 = _interopRequireDefault(_toPairs);
 
 	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 	function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
 
+	var get = __webpack_require__(67);
+
 	// Create the tree nodes representing all the variables and arguments
 	// for the bindings from a scope.
 	function getBindingVariables(bindings, parentName) {
 	  var args = bindings.arguments.map(arg => (0, _toPairs2.default)(arg)[0]);
 	  var variables = (0, _toPairs2.default)(bindings.variables);
 
 	  return args.concat(variables).map(binding => ({
 	    name: binding[0],
 	    path: `${parentName}/${binding[0]}`,
 	    contents: binding[1]
 	  }));
 	}
 
-	// Support dehydrating immutable objects, while ignoring
-	// primitive values like strings, numbers...
-	function dehydrateValue(value) {
-	  if (typeof value == "object" && !!value && value.toJS) {
-	    value = value.toJS();
-	  }
-
-	  return value;
-	}
-
 	function getSpecialVariables(pauseInfo, path) {
-	  var thrown = pauseInfo.getIn(["why", "frameFinished", "throw"], undefined);
-
-	  var returned = pauseInfo.getIn(["why", "frameFinished", "return"], undefined);
+	  var thrown = get(pauseInfo, "why.frameFinished.throw", undefined);
+
+	  var returned = get(pauseInfo, "why.frameFinished.return", undefined);
 
 	  var vars = [];
 
 	  if (thrown !== undefined) {
-	    thrown = dehydrateValue(thrown);
 	    vars.push({
 	      name: "<exception>",
 	      path: `${path}/<exception>`,
 	      contents: { value: thrown }
 	    });
 	  }
 
 	  if (returned !== undefined) {
-	    returned = dehydrateValue(returned);
-
 	    // Do not display a return value of "undefined",
 	    if (!returned || !returned.type || returned.type !== "undefined") {
 	      vars.push({
 	        name: "<return>",
 	        path: `${path}/<return>`,
 	        contents: { value: returned }
 	      });
 	    }
@@ -29131,17 +29138,17 @@ return /******/ (function(modules) { // 
 
 	  if (!selectedScope) {
 	    return null;
 	  }
 
 	  var scopes = [];
 
 	  var scope = selectedScope;
-	  var pausedScopeActor = pauseInfo.getIn(["frame", "scope"]).get("actor");
+	  var pausedScopeActor = get(pauseInfo, "frame.scope.actor");
 	  var scopeIndex = 1;
 
 	  do {
 	    var _scope = scope,
 	        type = _scope.type,
 	        actor = _scope.actor;
 
 	    var key = `${actor}-${scopeIndex}`;
@@ -29640,17 +29647,17 @@ return /******/ (function(modules) { // 
 	  }
 
 	  render() {
 	    return _react.DOM.div({ className: "command-bar" }, this.renderPauseButton(), this.renderStepButtons(), this.renderPauseOnExceptions());
 	  }
 	}
 
 	CommandBar.contextTypes = {
-	  shortcuts: Object
+	  shortcuts: _react.PropTypes.object
 	};
 
 	CommandBar.displayName = "CommandBar";
 
 	exports.default = (0, _reactRedux.connect)(state => {
 	  return {
 	    pause: (0, _selectors.getPause)(state),
 	    isWaitingOnBreak: (0, _selectors.getIsWaitingOnBreak)(state),
@@ -31383,16 +31390,25 @@ return /******/ (function(modules) { // 
 	        store,
 	        actions,
 	        selectors,
 	        client: client.clientCommands,
 	        connection
 	      };
 	    };
 
+	    if (!isFirefoxPanel()) {
+	      console.group("Developement Notes");
+	      var baseUrl = "https://devtools-html.github.io/debugger.html";
+	      var localDevelopmentUrl = `${baseUrl}/docs/local-development.html`;
+	      console.log("Debugging Tips", localDevelopmentUrl);
+	      console.log("getGlobalsForTesting", window.getGlobalsForTesting());
+	      console.groupEnd();
+	    }
+
 	    bootstrapApp(connection, { store, actions });
 
 	    return { store, actions, selectors, client: commands };
 	  });
 
 	  return function onConnect(_x, _x2) {
 	    return _ref.apply(this, arguments);
 	  };
@@ -31401,20 +31417,23 @@ return /******/ (function(modules) { // 
 	function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
 
 	var firefox = __webpack_require__(889);
 	var chrome = __webpack_require__(893);
 
 	var _require = __webpack_require__(226),
 	    prefs = _require.prefs;
 
-	var _require2 = __webpack_require__(897),
-	    bootstrapApp = _require2.bootstrapApp,
-	    bootstrapStore = _require2.bootstrapStore,
-	    bootstrapWorkers = _require2.bootstrapWorkers;
+	var _require2 = __webpack_require__(828),
+	    isFirefoxPanel = _require2.isFirefoxPanel;
+
+	var _require3 = __webpack_require__(897),
+	    bootstrapApp = _require3.bootstrapApp,
+	    bootstrapStore = _require3.bootstrapStore,
+	    bootstrapWorkers = _require3.bootstrapWorkers;
 
 	function loadFromPrefs(actions) {
 	  var pauseOnExceptions = prefs.pauseOnExceptions,
 	      ignoreCaughtExceptions = prefs.ignoreCaughtExceptions;
 
 	  if (pauseOnExceptions || ignoreCaughtExceptions) {
 	    return actions.pauseOnExceptions(pauseOnExceptions, ignoreCaughtExceptions);
 	  }
@@ -37188,22 +37207,104 @@ return /******/ (function(modules) { // 
 	  rep: wrapRender(GripMap),
 	  supportsObject
 	};
 
 /***/ },
 /* 960 */
 /***/ function(module, exports) {
 
-	module.exports = "# This Source Code Form is subject to the terms of the Mozilla Public\n# License, v. 2.0. If a copy of the MPL was not distributed with this\n# file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n# LOCALIZATION NOTE These strings are used inside the Debugger\n# which is available from the Web Developer sub-menu -> 'Debugger'.\n# The correct localization of this file might be to keep it in\n# English, or another language commonly spoken among web developers.\n# You want to make that choice consistent across the developer tools.\n# A good criteria is the language in which you'd find the best\n# documentation on web development on the web.\n\n# LOCALIZATION NOTE (collapsePanes): This is the tooltip for the button\n# that collapses the left and right panes in the debugger UI.\ncollapsePanes=Collapse panes\n\n# LOCALIZATION NOTE (copySourceUrl): This is the text that appears in the\n# context menu to copy the source URL of file open.\ncopySourceUrl=Copy Source Url\n\n# LOCALIZATION NOTE (copySourceUrl.accesskey): Access key to copy the source URL of a file from\n# the context menu.\ncopySourceUrl.accesskey=u\n\n# LOCALIZATION NOTE (copyStackTrace): This is the text that appears in the\n# context menu to copy the stack trace methods, file names and row number.\ncopyStackTrace=Copy Stack Trace\n\n# LOCALIZATION NOTE (copyStackTrace.accesskey): Access key to copy the stack trace data from\n# the context menu.\ncopyStackTrace.accesskey=c\n\n# LOCALIZATION NOTE (expandPanes): This is the tooltip for the button\n# that expands the left and right panes in the debugger UI.\nexpandPanes=Expand panes\n\n# LOCALIZATION NOTE (pauseButtonTooltip): The tooltip that is displayed for the pause\n# button when the debugger is in a running state.\npauseButtonTooltip=Pause %S\n\n# LOCALIZATION NOTE (pausePendingButtonTooltip): The tooltip that is displayed for\n# the pause button after it's been clicked but before the next JavaScript to run.\npausePendingButtonTooltip=Waiting for next execution\n\n# LOCALIZATION NOTE (resumeButtonTooltip): The label that is displayed on the pause\n# button when the debugger is in a paused state.\nresumeButtonTooltip=Resume %S\n\n# LOCALIZATION NOTE (stepOverTooltip): The label that is displayed on the\n# button that steps over a function call.\nstepOverTooltip=Step Over %S\n\n# LOCALIZATION NOTE (stepInTooltip): The label that is displayed on the\n# button that steps into a function call.\nstepInTooltip=Step In %S\n\n# LOCALIZATION NOTE (stepOutTooltip): The label that is displayed on the\n# button that steps out of a function call.\nstepOutTooltip=Step Out %S\n\n# LOCALIZATION NOTE (noWorkersText): The text to display in the workers list\n# when there are no workers.\nnoWorkersText=This page has no workers.\n\n# LOCALIZATION NOTE (noSourcesText): The text to display in the sources list\n# when there are no sources.\nnoSourcesText=This page has no sources.\n\n# LOCALIZATION NOTE (noEventListenersText): The text to display in the events tab\n# when there are no events.\nnoEventListenersText=No event listeners to display\n\n# LOCALIZATION NOTE (eventListenersHeader): The text to display in the events\n# header.\neventListenersHeader=Event Listeners\n\n# LOCALIZATION NOTE (noStackFramesText): The text to display in the call stack tab\n# when there are no stack frames.\nnoStackFramesText=No stack frames to display\n\n# LOCALIZATION NOTE (eventCheckboxTooltip): The tooltip text to display when\n# the user hovers over the checkbox used to toggle an event breakpoint.\neventCheckboxTooltip=Toggle breaking on this event\n\n# LOCALIZATION NOTE (eventOnSelector): The text to display in the events tab\n# for every event item, between the event type and event selector.\neventOnSelector=on\n\n# LOCALIZATION NOTE (eventInSource): The text to display in the events tab\n# for every event item, between the event selector and listener's owner source.\neventInSource=in\n\n# LOCALIZATION NOTE (eventNodes): The text to display in the events tab when\n# an event is listened on more than one target node.\neventNodes=%S nodes\n\n# LOCALIZATION NOTE (eventNative): The text to display in the events tab when\n# a listener is added from plugins, thus getting translated to native code.\neventNative=[native code]\n\n# LOCALIZATION NOTE (*Events): The text to display in the events tab for\n# each group of sub-level event entries.\nanimationEvents=Animation\naudioEvents=Audio\nbatteryEvents=Battery\nclipboardEvents=Clipboard\ncompositionEvents=Composition\ndeviceEvents=Device\ndisplayEvents=Display\ndragAndDropEvents=Drag and Drop\ngamepadEvents=Gamepad\nindexedDBEvents=IndexedDB\ninteractionEvents=Interaction\nkeyboardEvents=Keyboard\nmediaEvents=HTML5 Media\nmouseEvents=Mouse\nmutationEvents=Mutation\nnavigationEvents=Navigation\npointerLockEvents=Pointer Lock\nsensorEvents=Sensor\nstorageEvents=Storage\ntimeEvents=Time\ntouchEvents=Touch\notherEvents=Other\n\n# LOCALIZATION NOTE (blackboxCheckboxTooltip2): The tooltip text to display when\n# the user hovers over the checkbox used to toggle blackboxing its associated\n# source.\nblackboxCheckboxTooltip2=Toggle blackboxing\n\n# LOCALIZATION NOTE (sources.search.key2): Key shortcut to open the search for\n# searching all the source files the debugger has seen.\nsources.search.key2=CmdOrCtrl+P\n\n# LOCALIZATION NOTE (sources.search.alt.key): A second key shortcut to open the\n# search for searching all the source files the debugger has seen.\nsources.search.alt.key=CmdOrCtrl+O\n\n# LOCALIZATION NOTE (sources.noSourcesAvailable): Text shown when the debugger\n# does not have any sources.\nsources.noSourcesAvailable=This page has no sources\n\n# LOCALIZATION NOTE (sourceSearch.search.key2): Key shortcut to open the search\n# for searching within a the currently opened files in the editor\nsourceSearch.search.key2=CmdOrCtrl+F\n\n# LOCALIZATION NOTE (sourceSearch.search.placeholder): placeholder text in\n# the source search input bar\nsourceSearch.search.placeholder=Search in file…\n\n# LOCALIZATION NOTE (sourceSearch.search.again.key2): Key shortcut to highlight\n# the next occurrence of the last search triggered from a source search\nsourceSearch.search.again.key2=CmdOrCtrl+G\n\n# LOCALIZATION NOTE (sourceSearch.search.againPrev.key2): Key shortcut to highlight\n# the previous occurrence of the last search triggered from a source search\nsourceSearch.search.againPrev.key2=CmdOrCtrl+Shift+G\n\n# LOCALIZATION NOTE (sourceSearch.resultsSummary1): Shows a summary of\n# the number of matches for autocomplete\nsourceSearch.resultsSummary1=%d results\n\n# LOCALIZATION NOTE (noMatchingStringsText): The text to display in the\n# global search results when there are no matching strings after filtering.\nnoMatchingStringsText=No matches found\n\n# LOCALIZATION NOTE (emptySearchText): This is the text that appears in the\n# filter text box when it is empty and the scripts container is selected.\nemptySearchText=Search scripts (%S)\n\n# LOCALIZATION NOTE (emptyVariablesFilterText): This is the text that\n# appears in the filter text box for the variables view container.\nemptyVariablesFilterText=Filter variables\n\n# LOCALIZATION NOTE (emptyPropertiesFilterText): This is the text that\n# appears in the filter text box for the editor's variables view bubble.\nemptyPropertiesFilterText=Filter properties\n\n# LOCALIZATION NOTE (searchPanelFilter): This is the text that appears in the\n# filter panel popup for the filter scripts operation.\nsearchPanelFilter=Filter scripts (%S)\n\n# LOCALIZATION NOTE (searchPanelGlobal): This is the text that appears in the\n# filter panel popup for the global search operation.\nsearchPanelGlobal=Search in all files (%S)\n\n# LOCALIZATION NOTE (searchPanelFunction): This is the text that appears in the\n# filter panel popup for the function search operation.\nsearchPanelFunction=Search for function definition (%S)\n\n# LOCALIZATION NOTE (searchPanelToken): This is the text that appears in the\n# filter panel popup for the token search operation.\nsearchPanelToken=Find in this file (%S)\n\n# LOCALIZATION NOTE (searchPanelGoToLine): This is the text that appears in the\n# filter panel popup for the line search operation.\nsearchPanelGoToLine=Go to line (%S)\n\n# LOCALIZATION NOTE (searchPanelVariable): This is the text that appears in the\n# filter panel popup for the variables search operation.\nsearchPanelVariable=Filter variables (%S)\n\n# LOCALIZATION NOTE (breakpointMenuItem): The text for all the elements that\n# are displayed in the breakpoints menu item popup.\nbreakpointMenuItem.setConditional=Configure conditional breakpoint\nbreakpointMenuItem.enableSelf=Enable breakpoint\nbreakpointMenuItem.disableSelf=Disable breakpoint\nbreakpointMenuItem.deleteSelf=Remove breakpoint\nbreakpointMenuItem.enableOthers=Enable others\nbreakpointMenuItem.disableOthers=Disable others\nbreakpointMenuItem.deleteOthers=Remove others\nbreakpointMenuItem.enableAll=Enable all breakpoints\nbreakpointMenuItem.disableAll=Disable all breakpoints\nbreakpointMenuItem.deleteAll=Remove all breakpoints\n\n# LOCALIZATION NOTE (breakpoints.header): Breakpoints right sidebar pane header.\nbreakpoints.header=Breakpoints\n\n# LOCALIZATION NOTE (breakpoints.none): The text that appears when there are\n# no breakpoints present\nbreakpoints.none=No Breakpoints\n\n# LOCALIZATION NOTE (breakpoints.enable): The text that may appear as a tooltip\n# when hovering over the 'disable breakpoints' switch button in right sidebar\nbreakpoints.enable=Enable Breakpoints\n\n# LOCALIZATION NOTE (breakpoints.disable): The text that may appear as a tooltip\n# when hovering over the 'disable breakpoints' switch button in right sidebar\nbreakpoints.disable=Disable Breakpoints\n\n# LOCALIZATION NOTE (breakpoints.removeBreakpointTooltip): The tooltip that is displayed\n# for remove breakpoint button in right sidebar\nbreakpoints.removeBreakpointTooltip=Remove Breakpoint\n\n# LOCALIZATION NOTE (callStack.header): Call Stack right sidebar pane header.\ncallStack.header=Call Stack\n\n# LOCALIZATION NOTE (callStack.notPaused): Call Stack right sidebar pane\n# message when not paused.\ncallStack.notPaused=Not Paused\n\n# LOCALIZATION NOTE (callStack.collapse): Call Stack right sidebar pane\n# message to hide some of the frames that are shown.\ncallStack.collapse=Collapse Rows\n\n# LOCALIZATION NOTE (callStack.expand): Call Stack right sidebar pane\n# message to show more of the frames.\ncallStack.expand=Expand Rows\n\n# LOCALIZATION NOTE (editor.searchResults): Editor Search bar message\n# for the summarizing the selected search result. e.g. 5 of 10 results.\neditor.searchResults=%d of %d results\n\n# LOCALIZATION NOTE (sourceSearch.singleResult): Copy shown when there is one result.\neditor.singleResult=1 result\n\n# LOCALIZATION NOTE (editor.noResults): Editor Search bar message\n# for when no results found.\neditor.noResults=no results\n\n# LOCALIZATION NOTE (editor.searchResults.nextResult): Editor Search bar\n# tooltip for traversing to the Next Result\neditor.searchResults.nextResult=Next Result\n\n# LOCALIZATION NOTE (editor.searchResults.prevResult): Editor Search bar\n# tooltip for traversing to the Previous Result\neditor.searchResults.prevResult=Previous Result\n\n# LOCALIZATION NOTE (editor.searchTypeToggleTitle): Search bar title for\n# toggling search type buttons(function search, variable search)\neditor.searchTypeToggleTitle=Search for:\n\n# LOCALIZATION NOTE (editor.addBreakpoint): Editor gutter context menu item\n# for adding a breakpoint on a line.\neditor.addBreakpoint=Add Breakpoint\n\n# LOCALIZATION NOTE (editor.disableBreakpoint): Editor gutter context menu item\n# for disabling a breakpoint on a line.\neditor.disableBreakpoint=Disable Breakpoint\n\n# LOCALIZATION NOTE (editor.enableBreakpoint): Editor gutter context menu item\n# for enabling a breakpoint on a line.\neditor.enableBreakpoint=Enable Breakpoint\n\n# LOCALIZATION NOTE (editor.removeBreakpoint): Editor gutter context menu item\n# for removing a breakpoint on a line.\neditor.removeBreakpoint=Remove Breakpoint\n\n# LOCALIZATION NOTE (editor.editBreakpoint): Editor gutter context menu item\n# for setting a breakpoint condition on a line.\neditor.editBreakpoint=Edit Breakpoint\n\n# LOCALIZATION NOTE (editor.addConditionalBreakpoint): Editor gutter context\n# menu item for adding a breakpoint condition on a line.\neditor.addConditionalBreakpoint=Add Conditional Breakpoint\n\n# LOCALIZATION NOTE (editor.conditionalPanel.placeholder): Placeholder text for\n# input element inside ConditionalPanel component\neditor.conditionalPanel.placeholder=This breakpoint will pause when the expression is true\n\n# LOCALIZATION NOTE (editor.conditionalPanel.placeholder): Tooltip text for\n# close button inside ConditionalPanel component\neditor.conditionalPanel.close=Cancel edit breakpoint and close\n\n# LOCALIZATION NOTE (editor.jumpToMappedLocation1): Context menu item\n# for navigating to a source mapped location\neditor.jumpToMappedLocation1=Jump to %S location\n\n# LOCALIZATION NOTE (generated): Source Map term for a server source location\ngenerated=generated\n\n# LOCALIZATION NOTE (original): Source Map term for a debugger UI source location\noriginal=original\n\n# LOCALIZATION NOTE (expressions.placeholder): Placeholder text for expression\n# input element\nexpressions.placeholder=Add Watch Expression\n\n# LOCALIZATION NOTE (sourceTabs.closeTab): Editor source tab context menu item\n# for closing the selected tab below the mouse.\nsourceTabs.closeTab=Close tab\n\n# LOCALIZATION NOTE (sourceTabs.closeTab.accesskey): Access key to close the currently select\n# source tab from the editor context menu item.\nsourceTabs.closeTab.accesskey=c\n\n# LOCALIZATION NOTE (sourceTabs.closeOtherTabs): Editor source tab context menu item\n# for closing the other tabs.\nsourceTabs.closeOtherTabs=Close others\n\n# LOCALIZATION NOTE (sourceTabs.closeOtherTabs.accesskey): Access key to close other source tabs\n# from the editor context menu.\nsourceTabs.closeOtherTabs.accesskey=o\n\n# LOCALIZATION NOTE (sourceTabs.closeTabsToEnd): Editor source tab context menu item\n# for closing the tabs to the end (the right for LTR languages) of the selected tab.\nsourceTabs.closeTabsToEnd=Close tabs to the right\n\n# LOCALIZATION NOTE (sourceTabs.closeTabsToEnd.accesskey): Access key to close source tabs\n# after the selected tab from the editor context menu.\nsourceTabs.closeTabsToEnd.accesskey=e\n\n# LOCALIZATION NOTE (sourceTabs.closeAllTabs): Editor source tab context menu item\n# for closing all tabs.\nsourceTabs.closeAllTabs=Close all tabs\n\n# LOCALIZATION NOTE (sourceTabs.closeAllTabs.accesskey): Access key to close all tabs from the\n# editor context menu.\nsourceTabs.closeAllTabs.accesskey=a\n\n# LOCALIZATION NOTE (sourceTabs.revealInTree): Editor source tab context menu item\n# for revealing source in tree.\nsourceTabs.revealInTree=Reveal in Tree\n\n# LOCALIZATION NOTE (sourceTabs.revealInTree.accesskey): Access key to reveal a source in the\n# tree from the context menu.\nsourceTabs.revealInTree.accesskey=r\n\n# LOCALIZATION NOTE (sourceTabs.copyLink): Editor source tab context menu item\n# for copying a link address.\nsourceTabs.copyLink=Copy Link Address\n\n# LOCALIZATION NOTE (sourceTabs.copyLink.accesskey): Access key to copy a link addresss from the\n# editor context menu.\nsourceTabs.copyLink.accesskey=l\n\n# LOCALIZATION NOTE (sourceTabs.prettyPrint): Editor source tab context menu item\n# for pretty printing the source.\nsourceTabs.prettyPrint=Pretty Print Source\n\n# LOCALIZATION NOTE (sourceTabs.prettyPrint.accesskey): Access key to pretty print a source from\n# the editor context menu.\nsourceTabs.prettyPrint.accesskey=p\n\n# LOCALIZATION NOTE (sourceFooter.blackbox): Tooltip text associated\n# with the blackbox button\nsourceFooter.blackbox=Blackbox Source\n\n# LOCALIZATION NOTE (sourceFooter.unblackbox): Tooltip text associated\n# with the blackbox button\nsourceFooter.unblackbox=Unblackbox Source\n\n# LOCALIZATION NOTE (sourceFooter.blackbox.accesskey): Access key to blackbox\n# an associated source\nsourceFooter.blackbox.accesskey=b\n\n# LOCALIZATION NOTE (sourceFooter.blackboxed): Text associated\n# with a blackboxed source\nsourceFooter.blackboxed=Blackboxed Source\n\n# LOCALIZATION NOTE (sourceTabs.closeTabButtonTooltip): The tooltip that is displayed\n# for close tab button in source tabs.\nsourceTabs.closeTabButtonTooltip=Close tab\n\n# LOCALIZATION NOTE (sourceTabs.newTabButtonTooltip): The tooltip that is displayed for\n# new tab button in source tabs.\nsourceTabs.newTabButtonTooltip=Search for sources (%S)\n\n# LOCALIZATION NOTE (scopes.header): Scopes right sidebar pane header.\nscopes.header=Scopes\n\n# LOCALIZATION NOTE (scopes.notAvailable): Scopes right sidebar pane message\n# for when the debugger is paused, but there isn't pause data.\nscopes.notAvailable=Scopes Unavailable\n\n# LOCALIZATION NOTE (scopes.notPaused): Scopes right sidebar pane message\n# for when the debugger is not paused.\nscopes.notPaused=Not Paused\n\n# LOCALIZATION NOTE (scopes.block): Refers to a block of code in\n# the scopes pane when the debugger is paused.\nscopes.block=Block\n\n# LOCALIZATION NOTE (sources.header): Sources left sidebar header\nsources.header=Sources\n\n# LOCALIZATION NOTE (sources.search): Sources left sidebar prompt\n# e.g. Cmd+P to search. On a mac, we use the command unicode character.\n# On windows, it's ctrl.\nsources.search=%S to search\n\n# LOCALIZATION NOTE (watchExpressions.header): Watch Expressions right sidebar\n# pane header.\nwatchExpressions.header=Watch Expressions\n\n# LOCALIZATION NOTE (watchExpressions.refreshButton): Watch Expressions header\n# button for refreshing the expressions.\nwatchExpressions.refreshButton=Refresh\n\n# LOCALIZATION NOTE (welcome.search): The center pane welcome panel's\n# search prompt. e.g. cmd+p to search for files. On windows, it's ctrl, on\n# a mac we use the unicode character.\nwelcome.search=%S to search for sources\n\n# LOCALIZATION NOTE (sourceSearch.search): The center pane Source Search\n# prompt for searching for files.\nsourceSearch.search=Search Sources…\n\n# LOCALIZATION NOTE (sourceSearch.noResults): The center pane Source Search\n# message when the query did not match any of the sources.\nsourceSearch.noResults=No files matching %S found\n\n# LOCALIZATION NOTE (ignoreExceptions): The pause on exceptions button tooltip\n# when the debugger will not pause on exceptions.\nignoreExceptions=Ignore exceptions. Click to pause on uncaught exceptions\n\n# LOCALIZATION NOTE (pauseOnUncaughtExceptions): The pause on exceptions button\n# tooltip when the debugger will pause on uncaught exceptions.\npauseOnUncaughtExceptions=Pause on uncaught exceptions. Click to pause on all exceptions\n\n# LOCALIZATION NOTE (pauseOnExceptions): The pause on exceptions button tooltip\n# when the debugger will pause on all exceptions.\npauseOnExceptions=Pause on all exceptions. Click to ignore exceptions\n\n# LOCALIZATION NOTE (loadingText): The text that is displayed in the script\n# editor when the loading process has started but there is no file to display\n# yet.\nloadingText=Loading\\u2026\n\n# LOCALIZATION NOTE (errorLoadingText2): The text that is displayed in the debugger\n# viewer when there is an error loading a file\nerrorLoadingText2=Error loading this URL: %S\n\n# LOCALIZATION NOTE (addWatchExpressionText): The text that is displayed in the\n# watch expressions list to add a new item.\naddWatchExpressionText=Add watch expression\n\n# LOCALIZATION NOTE (addWatchExpressionButton): The button that is displayed in the\n# variables view popup.\naddWatchExpressionButton=Watch\n\n# LOCALIZATION NOTE (emptyVariablesText): The text that is displayed in the\n# variables pane when there are no variables to display.\nemptyVariablesText=No variables to display\n\n# LOCALIZATION NOTE (scopeLabel): The text that is displayed in the variables\n# pane as a header for each variable scope (e.g. \"Global scope, \"With scope\",\n# etc.).\nscopeLabel=%S scope\n\n# LOCALIZATION NOTE (watchExpressionsScopeLabel): The name of the watch\n# expressions scope. This text is displayed in the variables pane as a header for\n# the watch expressions scope.\nwatchExpressionsScopeLabel=Watch expressions\n\n# LOCALIZATION NOTE (globalScopeLabel): The name of the global scope. This text\n# is added to scopeLabel and displayed in the variables pane as a header for\n# the global scope.\nglobalScopeLabel=Global\n\n# LOCALIZATION NOTE (variablesViewErrorStacktrace): This is the text that is\n# shown before the stack trace in an error.\nvariablesViewErrorStacktrace=Stack trace:\n\n# LOCALIZATION NOTE (variablesViewMoreObjects): the text that is displayed\n# when you have an object preview that does not show all of the elements. At the end of the list\n# you see \"N more...\" in the web console output.\n# This is a semi-colon list of plural forms.\n# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals\n# #1 number of remaining items in the object\n# example: 3 more…\nvariablesViewMoreObjects=#1 more…;#1 more…\n\n# LOCALIZATION NOTE (variablesEditableNameTooltip): The text that is displayed\n# in the variables list on an item with an editable name.\nvariablesEditableNameTooltip=Double click to edit\n\n# LOCALIZATION NOTE (variablesEditableValueTooltip): The text that is displayed\n# in the variables list on an item with an editable value.\nvariablesEditableValueTooltip=Click to change value\n\n# LOCALIZATION NOTE (variablesCloseButtonTooltip): The text that is displayed\n# in the variables list on an item which can be removed.\nvariablesCloseButtonTooltip=Click to remove\n\n# LOCALIZATION NOTE (variablesEditButtonTooltip): The text that is displayed\n# in the variables list on a getter or setter which can be edited.\nvariablesEditButtonTooltip=Click to set value\n\n# LOCALIZATION NOTE (variablesEditableValueTooltip): The text that is displayed\n# in a tooltip on the \"open in inspector\" button in the the variables list for a\n# DOMNode item.\nvariablesDomNodeValueTooltip=Click to select the node in the inspector\n\n# LOCALIZATION NOTE (configurable|...|Tooltip): The text that is displayed\n# in the variables list on certain variables or properties as tooltips.\n# Expanations of what these represent can be found at the following links:\n# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty\n# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/isExtensible\n# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/isFrozen\n# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/isSealed\n# It's probably best to keep these in English.\nconfigurableTooltip=configurable\nenumerableTooltip=enumerable\nwritableTooltip=writable\nfrozenTooltip=frozen\nsealedTooltip=sealed\nextensibleTooltip=extensible\noverriddenTooltip=overridden\nWebIDLTooltip=WebIDL\n\n# LOCALIZATION NOTE (variablesSeparatorLabel): The text that is displayed\n# in the variables list as a separator between the name and value.\nvariablesSeparatorLabel=:\n\n# LOCALIZATION NOTE (watchExpressionsSeparatorLabel2): The text that is displayed\n# in the watch expressions list as a separator between the code and evaluation.\nwatchExpressionsSeparatorLabel2=\\u0020→\n\n# LOCALIZATION NOTE (functionSearchSeparatorLabel): The text that is displayed\n# in the functions search panel as a separator between function's inferred name\n# and its real name (if available).\nfunctionSearchSeparatorLabel=←\n\n# LOCALIZATION NOTE(symbolSearch.search.functionsPlaceholder): The placeholder\n# text displayed when the user searches for functions in a file\nsymbolSearch.search.functionsPlaceholder=Search functions…\n\n# LOCALIZATION NOTE(symbolSearch.search.variablesPlaceholder): The placeholder\n# text displayed when the user searches for variables in a file\nsymbolSearch.search.variablesPlaceholder=Search variables…\n\n# LOCALIZATION NOTE(symbolSearch.search.key2): The Key Shortcut for\n# searching for a function or variable\nsymbolSearch.search.key2=CmdOrCtrl+Shift+O\n\n# LOCALIZATION NOTE(symbolSearch.searchModifier.regex): A search option\n# when searching text in a file\nsymbolSearch.searchModifier.regex=Regex\n\n# LOCALIZATION NOTE(symbolSearch.searchModifier.caseSensitive): A search option\n# when searching text in a file\nsymbolSearch.searchModifier.caseSensitive=Case sensitive\n\n# LOCALIZATION NOTE(symbolSearch.searchModifier.wholeWord): A search option\n# when searching text in a file\nsymbolSearch.searchModifier.wholeWord=Whole word\n\n# LOCALIZATION NOTE (resumptionOrderPanelTitle): This is the text that appears\n# as a description in the notification panel popup, when multiple debuggers are\n# open in separate tabs and the user tries to resume them in the wrong order.\n# The substitution parameter is the URL of the last paused window that must be\n# resumed first.\nresumptionOrderPanelTitle=There are one or more paused debuggers. Please resume the most-recently paused debugger first at: %S\n\nvariablesViewOptimizedOut=(optimized away)\nvariablesViewUninitialized=(uninitialized)\nvariablesViewMissingArgs=(unavailable)\n\nanonymousSourcesLabel=Anonymous Sources\n\nexperimental=This is an experimental feature\n\n# LOCALIZATION NOTE (whyPaused.debuggerStatement): The text that is displayed\n# in a info block explaining how the debugger is currently paused due to a `debugger`\n# statement in the code\nwhyPaused.debuggerStatement=Paused on debugger statement\n\n# LOCALIZATION NOTE (whyPaused.breakpoint): The text that is displayed\n# in a info block explaining how the debugger is currently paused on a breakpoint\nwhyPaused.breakpoint=Paused on breakpoint\n\n# LOCALIZATION NOTE (whyPaused.exception): The text that is displayed\n# in a info block explaining how the debugger is currently paused on an exception\nwhyPaused.exception=Paused on exception\n\n# LOCALIZATION NOTE (whyPaused.resumeLimit): The text that is displayed\n# in a info block explaining how the debugger is currently paused while stepping\n# in or out of the stack\nwhyPaused.resumeLimit=Paused while stepping\n\n# LOCALIZATION NOTE (whyPaused.pauseOnDOMEvents): The text that is displayed\n# in a info block explaining how the debugger is currently paused on a\n# dom event\nwhyPaused.pauseOnDOMEvents=Paused on event listener\n\n# LOCALIZATION NOTE (whyPaused.breakpointConditionThrown): The text that is displayed\n# in an info block when evaluating a conditional breakpoint throws an error\nwhyPaused.breakpointConditionThrown=Error with conditional breakpoint\n\n# LOCALIZATION NOTE (whyPaused.xhr): The text that is displayed\n# in a info block explaining how the debugger is currently paused on an\n# xml http request\nwhyPaused.xhr=Paused on XMLHttpRequest\n\n# LOCALIZATION NOTE (whyPaused.promiseRejection): The text that is displayed\n# in a info block explaining how the debugger is currently paused on a\n# promise rejection\nwhyPaused.promiseRejection=Paused on promise rejection\n\n# LOCALIZATION NOTE (whyPaused.assert): The text that is displayed\n# in a info block explaining how the debugger is currently paused on an\n# assert\nwhyPaused.assert=Paused on assertion\n\n# LOCALIZATION NOTE (whyPaused.debugCommand): The text that is displayed\n# in a info block explaining how the debugger is currently paused on a\n# debugger statement\nwhyPaused.debugCommand=Paused on debugged function\n\n# LOCALIZATION NOTE (whyPaused.other): The text that is displayed\n# in a info block explaining how the debugger is currently paused on an event\n# listener breakpoint set\nwhyPaused.other=Debugger paused\n\n# LOCALIZATION NOTE (ctrl): The text that is used for documenting\n# keyboard shortcuts that use the control key\nctrl=Ctrl\n"
+	module.exports = "# This Source Code Form is subject to the terms of the Mozilla Public\n# License, v. 2.0. If a copy of the MPL was not distributed with this\n# file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n# LOCALIZATION NOTE These strings are used inside the Debugger\n# which is available from the Web Developer sub-menu -> 'Debugger'.\n# The correct localization of this file might be to keep it in\n# English, or another language commonly spoken among web developers.\n# You want to make that choice consistent across the developer tools.\n# A good criteria is the language in which you'd find the best\n# documentation on web development on the web.\n\n# LOCALIZATION NOTE (collapsePanes): This is the tooltip for the button\n# that collapses the left and right panes in the debugger UI.\ncollapsePanes=Collapse panes\n\n# LOCALIZATION NOTE (copySourceUrl): This is the text that appears in the\n# context menu to copy the source URL of file open.\ncopySourceUrl=Copy Source Url\n\n# LOCALIZATION NOTE (copySourceUrl.accesskey): Access key to copy the source URL of a file from\n# the context menu.\ncopySourceUrl.accesskey=u\n\n# LOCALIZATION NOTE (copyStackTrace): This is the text that appears in the\n# context menu to copy the stack trace methods, file names and row number.\ncopyStackTrace=Copy Stack Trace\n\n# LOCALIZATION NOTE (copyStackTrace.accesskey): Access key to copy the stack trace data from\n# the context menu.\ncopyStackTrace.accesskey=c\n\n# LOCALIZATION NOTE (expandPanes): This is the tooltip for the button\n# that expands the left and right panes in the debugger UI.\nexpandPanes=Expand panes\n\n# LOCALIZATION NOTE (pauseButtonTooltip): The tooltip that is displayed for the pause\n# button when the debugger is in a running state.\npauseButtonTooltip=Pause %S\n\n# LOCALIZATION NOTE (pausePendingButtonTooltip): The tooltip that is displayed for\n# the pause button after it's been clicked but before the next JavaScript to run.\npausePendingButtonTooltip=Waiting for next execution\n\n# LOCALIZATION NOTE (resumeButtonTooltip): The label that is displayed on the pause\n# button when the debugger is in a paused state.\nresumeButtonTooltip=Resume %S\n\n# LOCALIZATION NOTE (stepOverTooltip): The label that is displayed on the\n# button that steps over a function call.\nstepOverTooltip=Step Over %S\n\n# LOCALIZATION NOTE (stepInTooltip): The label that is displayed on the\n# button that steps into a function call.\nstepInTooltip=Step In %S\n\n# LOCALIZATION NOTE (stepOutTooltip): The label that is displayed on the\n# button that steps out of a function call.\nstepOutTooltip=Step Out %S\n\n# LOCALIZATION NOTE (noWorkersText): The text to display in the workers list\n# when there are no workers.\nnoWorkersText=This page has no workers.\n\n# LOCALIZATION NOTE (noSourcesText): The text to display in the sources list\n# when there are no sources.\nnoSourcesText=This page has no sources.\n\n# LOCALIZATION NOTE (noEventListenersText): The text to display in the events tab\n# when there are no events.\nnoEventListenersText=No event listeners to display\n\n# LOCALIZATION NOTE (eventListenersHeader): The text to display in the events\n# header.\neventListenersHeader=Event Listeners\n\n# LOCALIZATION NOTE (noStackFramesText): The text to display in the call stack tab\n# when there are no stack frames.\nnoStackFramesText=No stack frames to display\n\n# LOCALIZATION NOTE (eventCheckboxTooltip): The tooltip text to display when\n# the user hovers over the checkbox used to toggle an event breakpoint.\neventCheckboxTooltip=Toggle breaking on this event\n\n# LOCALIZATION NOTE (eventOnSelector): The text to display in the events tab\n# for every event item, between the event type and event selector.\neventOnSelector=on\n\n# LOCALIZATION NOTE (eventInSource): The text to display in the events tab\n# for every event item, between the event selector and listener's owner source.\neventInSource=in\n\n# LOCALIZATION NOTE (eventNodes): The text to display in the events tab when\n# an event is listened on more than one target node.\neventNodes=%S nodes\n\n# LOCALIZATION NOTE (eventNative): The text to display in the events tab when\n# a listener is added from plugins, thus getting translated to native code.\neventNative=[native code]\n\n# LOCALIZATION NOTE (*Events): The text to display in the events tab for\n# each group of sub-level event entries.\nanimationEvents=Animation\naudioEvents=Audio\nbatteryEvents=Battery\nclipboardEvents=Clipboard\ncompositionEvents=Composition\ndeviceEvents=Device\ndisplayEvents=Display\ndragAndDropEvents=Drag and Drop\ngamepadEvents=Gamepad\nindexedDBEvents=IndexedDB\ninteractionEvents=Interaction\nkeyboardEvents=Keyboard\nmediaEvents=HTML5 Media\nmouseEvents=Mouse\nmutationEvents=Mutation\nnavigationEvents=Navigation\npointerLockEvents=Pointer Lock\nsensorEvents=Sensor\nstorageEvents=Storage\ntimeEvents=Time\ntouchEvents=Touch\notherEvents=Other\n\n# LOCALIZATION NOTE (blackboxCheckboxTooltip2): The tooltip text to display when\n# the user hovers over the checkbox used to toggle blackboxing its associated\n# source.\nblackboxCheckboxTooltip2=Toggle blackboxing\n\n# LOCALIZATION NOTE (sources.search.key2): Key shortcut to open the search for\n# searching all the source files the debugger has seen.\nsources.search.key2=CmdOrCtrl+P\n\n# LOCALIZATION NOTE (sources.search.alt.key): A second key shortcut to open the\n# search for searching all the source files the debugger has seen.\nsources.search.alt.key=CmdOrCtrl+O\n\n# LOCALIZATION NOTE (sources.noSourcesAvailable): Text shown when the debugger\n# does not have any sources.\nsources.noSourcesAvailable=This page has no sources\n\n# LOCALIZATION NOTE (sourceSearch.search.key2): Key shortcut to open the search\n# for searching within a the currently opened files in the editor\nsourceSearch.search.key2=CmdOrCtrl+F\n\n# LOCALIZATION NOTE (sourceSearch.search.placeholder): placeholder text in\n# the source search input bar\nsourceSearch.search.placeholder=Search in file…\n\n# LOCALIZATION NOTE (sourceSearch.search.again.key2): Key shortcut to highlight\n# the next occurrence of the last search triggered from a source search\nsourceSearch.search.again.key2=CmdOrCtrl+G\n\n# LOCALIZATION NOTE (sourceSearch.search.againPrev.key2): Key shortcut to highlight\n# the previous occurrence of the last search triggered from a source search\nsourceSearch.search.againPrev.key2=CmdOrCtrl+Shift+G\n\n# LOCALIZATION NOTE (sourceSearch.resultsSummary1): Shows a summary of\n# the number of matches for autocomplete\nsourceSearch.resultsSummary1=%d results\n\n# LOCALIZATION NOTE (noMatchingStringsText): The text to display in the\n# global search results when there are no matching strings after filtering.\nnoMatchingStringsText=No matches found\n\n# LOCALIZATION NOTE (emptySearchText): This is the text that appears in the\n# filter text box when it is empty and the scripts container is selected.\nemptySearchText=Search scripts (%S)\n\n# LOCALIZATION NOTE (emptyVariablesFilterText): This is the text that\n# appears in the filter text box for the variables view container.\nemptyVariablesFilterText=Filter variables\n\n# LOCALIZATION NOTE (emptyPropertiesFilterText): This is the text that\n# appears in the filter text box for the editor's variables view bubble.\nemptyPropertiesFilterText=Filter properties\n\n# LOCALIZATION NOTE (searchPanelFilter): This is the text that appears in the\n# filter panel popup for the filter scripts operation.\nsearchPanelFilter=Filter scripts (%S)\n\n# LOCALIZATION NOTE (searchPanelGlobal): This is the text that appears in the\n# filter panel popup for the global search operation.\nsearchPanelGlobal=Search in all files (%S)\n\n# LOCALIZATION NOTE (searchPanelFunction): This is the text that appears in the\n# filter panel popup for the function search operation.\nsearchPanelFunction=Search for function definition (%S)\n\n# LOCALIZATION NOTE (searchPanelToken): This is the text that appears in the\n# filter panel popup for the token search operation.\nsearchPanelToken=Find in this file (%S)\n\n# LOCALIZATION NOTE (searchPanelGoToLine): This is the text that appears in the\n# filter panel popup for the line search operation.\nsearchPanelGoToLine=Go to line (%S)\n\n# LOCALIZATION NOTE (searchPanelVariable): This is the text that appears in the\n# filter panel popup for the variables search operation.\nsearchPanelVariable=Filter variables (%S)\n\n# LOCALIZATION NOTE (breakpointMenuItem): The text for all the elements that\n# are displayed in the breakpoints menu item popup.\nbreakpointMenuItem.setConditional=Configure conditional breakpoint\nbreakpointMenuItem.enableSelf=Enable breakpoint\nbreakpointMenuItem.disableSelf=Disable breakpoint\nbreakpointMenuItem.deleteSelf=Remove breakpoint\nbreakpointMenuItem.enableOthers=Enable others\nbreakpointMenuItem.disableOthers=Disable others\nbreakpointMenuItem.deleteOthers=Remove others\nbreakpointMenuItem.enableAll=Enable all breakpoints\nbreakpointMenuItem.disableAll=Disable all breakpoints\nbreakpointMenuItem.deleteAll=Remove all breakpoints\n\n# LOCALIZATION NOTE (breakpoints.header): Breakpoints right sidebar pane header.\nbreakpoints.header=Breakpoints\n\n# LOCALIZATION NOTE (breakpoints.none): The text that appears when there are\n# no breakpoints present\nbreakpoints.none=No Breakpoints\n\n# LOCALIZATION NOTE (breakpoints.enable): The text that may appear as a tooltip\n# when hovering over the 'disable breakpoints' switch button in right sidebar\nbreakpoints.enable=Enable Breakpoints\n\n# LOCALIZATION NOTE (breakpoints.disable): The text that may appear as a tooltip\n# when hovering over the 'disable breakpoints' switch button in right sidebar\nbreakpoints.disable=Disable Breakpoints\n\n# LOCALIZATION NOTE (breakpoints.removeBreakpointTooltip): The tooltip that is displayed\n# for remove breakpoint button in right sidebar\nbreakpoints.removeBreakpointTooltip=Remove Breakpoint\n\n# LOCALIZATION NOTE (callStack.header): Call Stack right sidebar pane header.\ncallStack.header=Call Stack\n\n# LOCALIZATION NOTE (callStack.notPaused): Call Stack right sidebar pane\n# message when not paused.\ncallStack.notPaused=Not Paused\n\n# LOCALIZATION NOTE (callStack.collapse): Call Stack right sidebar pane\n# message to hide some of the frames that are shown.\ncallStack.collapse=Collapse Rows\n\n# LOCALIZATION NOTE (callStack.expand): Call Stack right sidebar pane\n# message to show more of the frames.\ncallStack.expand=Expand Rows\n\n# LOCALIZATION NOTE (editor.searchResults): Editor Search bar message\n# for the summarizing the selected search result. e.g. 5 of 10 results.\neditor.searchResults=%d of %d results\n\n# LOCALIZATION NOTE (sourceSearch.singleResult): Copy shown when there is one result.\neditor.singleResult=1 result\n\n# LOCALIZATION NOTE (editor.noResults): Editor Search bar message\n# for when no results found.\neditor.noResults=no results\n\n# LOCALIZATION NOTE (editor.searchResults.nextResult): Editor Search bar\n# tooltip for traversing to the Next Result\neditor.searchResults.nextResult=Next Result\n\n# LOCALIZATION NOTE (editor.searchResults.prevResult): Editor Search bar\n# tooltip for traversing to the Previous Result\neditor.searchResults.prevResult=Previous Result\n\n# LOCALIZATION NOTE (editor.searchTypeToggleTitle): Search bar title for\n# toggling search type buttons(function search, variable search)\neditor.searchTypeToggleTitle=Search for:\n\n# LOCALIZATION NOTE (editor.addBreakpoint): Editor gutter context menu item\n# for adding a breakpoint on a line.\neditor.addBreakpoint=Add Breakpoint\n\n# LOCALIZATION NOTE (editor.disableBreakpoint): Editor gutter context menu item\n# for disabling a breakpoint on a line.\neditor.disableBreakpoint=Disable Breakpoint\n\n# LOCALIZATION NOTE (editor.enableBreakpoint): Editor gutter context menu item\n# for enabling a breakpoint on a line.\neditor.enableBreakpoint=Enable Breakpoint\n\n# LOCALIZATION NOTE (editor.removeBreakpoint): Editor gutter context menu item\n# for removing a breakpoint on a line.\neditor.removeBreakpoint=Remove Breakpoint\n\n# LOCALIZATION NOTE (editor.editBreakpoint): Editor gutter context menu item\n# for setting a breakpoint condition on a line.\neditor.editBreakpoint=Edit Breakpoint\n\n# LOCALIZATION NOTE (editor.addConditionalBreakpoint): Editor gutter context\n# menu item for adding a breakpoint condition on a line.\neditor.addConditionalBreakpoint=Add Conditional Breakpoint\n\n# LOCALIZATION NOTE (editor.conditionalPanel.placeholder): Placeholder text for\n# input element inside ConditionalPanel component\neditor.conditionalPanel.placeholder=This breakpoint will pause when the expression is true\n\n# LOCALIZATION NOTE (editor.conditionalPanel.placeholder): Tooltip text for\n# close button inside ConditionalPanel component\neditor.conditionalPanel.close=Cancel edit breakpoint and close\n\n# LOCALIZATION NOTE (editor.jumpToMappedLocation1): Context menu item\n# for navigating to a source mapped location\neditor.jumpToMappedLocation1=Jump to %S location\n\n# LOCALIZATION NOTE (framework.disableGrouping): This is the text that appears in the\n# context menu to disable framework grouping.\nframework.disableGrouping=Disable Framework Grouping\n\n# LOCALIZATION NOTE (framework.enableGrouping): This is the text that appears in the\n# context menu to enable framework grouping.\nframework.enableGrouping=Enable Framework Grouping\n\n# LOCALIZATION NOTE (framework.accesskey): Access key to toggle framework grouping from\n# the context menu.\nframework.accesskey=u\n\n# LOCALIZATION NOTE (generated): Source Map term for a server source location\ngenerated=generated\n\n# LOCALIZATION NOTE (original): Source Map term for a debugger UI source location\noriginal=original\n\n# LOCALIZATION NOTE (expressions.placeholder): Placeholder text for expression\n# input element\nexpressions.placeholder=Add Watch Expression\n\n# LOCALIZATION NOTE (sourceTabs.closeTab): Editor source tab context menu item\n# for closing the selected tab below the mouse.\nsourceTabs.closeTab=Close tab\n\n# LOCALIZATION NOTE (sourceTabs.closeTab.accesskey): Access key to close the currently select\n# source tab from the editor context menu item.\nsourceTabs.closeTab.accesskey=c\n\n# LOCALIZATION NOTE (sourceTabs.closeOtherTabs): Editor source tab context menu item\n# for closing the other tabs.\nsourceTabs.closeOtherTabs=Close others\n\n# LOCALIZATION NOTE (sourceTabs.closeOtherTabs.accesskey): Access key to close other source tabs\n# from the editor context menu.\nsourceTabs.closeOtherTabs.accesskey=o\n\n# LOCALIZATION NOTE (sourceTabs.closeTabsToEnd): Editor source tab context menu item\n# for closing the tabs to the end (the right for LTR languages) of the selected tab.\nsourceTabs.closeTabsToEnd=Close tabs to the right\n\n# LOCALIZATION NOTE (sourceTabs.closeTabsToEnd.accesskey): Access key to close source tabs\n# after the selected tab from the editor context menu.\nsourceTabs.closeTabsToEnd.accesskey=e\n\n# LOCALIZATION NOTE (sourceTabs.closeAllTabs): Editor source tab context menu item\n# for closing all tabs.\nsourceTabs.closeAllTabs=Close all tabs\n\n# LOCALIZATION NOTE (sourceTabs.closeAllTabs.accesskey): Access key to close all tabs from the\n# editor context menu.\nsourceTabs.closeAllTabs.accesskey=a\n\n# LOCALIZATION NOTE (sourceTabs.revealInTree): Editor source tab context menu item\n# for revealing source in tree.\nsourceTabs.revealInTree=Reveal in Tree\n\n# LOCALIZATION NOTE (sourceTabs.revealInTree.accesskey): Access key to reveal a source in the\n# tree from the context menu.\nsourceTabs.revealInTree.accesskey=r\n\n# LOCALIZATION NOTE (sourceTabs.copyLink): Editor source tab context menu item\n# for copying a link address.\nsourceTabs.copyLink=Copy Link Address\n\n# LOCALIZATION NOTE (sourceTabs.copyLink.accesskey): Access key to copy a link addresss from the\n# editor context menu.\nsourceTabs.copyLink.accesskey=l\n\n# LOCALIZATION NOTE (sourceTabs.prettyPrint): Editor source tab context menu item\n# for pretty printing the source.\nsourceTabs.prettyPrint=Pretty Print Source\n\n# LOCALIZATION NOTE (sourceTabs.prettyPrint.accesskey): Access key to pretty print a source from\n# the editor context menu.\nsourceTabs.prettyPrint.accesskey=p\n\n# LOCALIZATION NOTE (sourceFooter.blackbox): Tooltip text associated\n# with the blackbox button\nsourceFooter.blackbox=Blackbox Source\n\n# LOCALIZATION NOTE (sourceFooter.unblackbox): Tooltip text associated\n# with the blackbox button\nsourceFooter.unblackbox=Unblackbox Source\n\n# LOCALIZATION NOTE (sourceFooter.blackbox.accesskey): Access key to blackbox\n# an associated source\nsourceFooter.blackbox.accesskey=b\n\n# LOCALIZATION NOTE (sourceFooter.blackboxed): Text associated\n# with a blackboxed source\nsourceFooter.blackboxed=Blackboxed Source\n\n# LOCALIZATION NOTE (sourceTabs.closeTabButtonTooltip): The tooltip that is displayed\n# for close tab button in source tabs.\nsourceTabs.closeTabButtonTooltip=Close tab\n\n# LOCALIZATION NOTE (sourceTabs.newTabButtonTooltip): The tooltip that is displayed for\n# new tab button in source tabs.\nsourceTabs.newTabButtonTooltip=Search for sources (%S)\n\n# LOCALIZATION NOTE (scopes.header): Scopes right sidebar pane header.\nscopes.header=Scopes\n\n# LOCALIZATION NOTE (scopes.notAvailable): Scopes right sidebar pane message\n# for when the debugger is paused, but there isn't pause data.\nscopes.notAvailable=Scopes Unavailable\n\n# LOCALIZATION NOTE (scopes.notPaused): Scopes right sidebar pane message\n# for when the debugger is not paused.\nscopes.notPaused=Not Paused\n\n# LOCALIZATION NOTE (scopes.block): Refers to a block of code in\n# the scopes pane when the debugger is paused.\nscopes.block=Block\n\n# LOCALIZATION NOTE (sources.header): Sources left sidebar header\nsources.header=Sources\n\n# LOCALIZATION NOTE (sources.search): Sources left sidebar prompt\n# e.g. Cmd+P to search. On a mac, we use the command unicode character.\n# On windows, it's ctrl.\nsources.search=%S to search\n\n# LOCALIZATION NOTE (watchExpressions.header): Watch Expressions right sidebar\n# pane header.\nwatchExpressions.header=Watch Expressions\n\n# LOCALIZATION NOTE (watchExpressions.refreshButton): Watch Expressions header\n# button for refreshing the expressions.\nwatchExpressions.refreshButton=Refresh\n\n# LOCALIZATION NOTE (welcome.search): The center pane welcome panel's\n# search prompt. e.g. cmd+p to search for files. On windows, it's ctrl, on\n# a mac we use the unicode character.\nwelcome.search=%S to search for sources\n\n# LOCALIZATION NOTE (sourceSearch.search): The center pane Source Search\n# prompt for searching for files.\nsourceSearch.search=Search Sources…\n\n# LOCALIZATION NOTE (sourceSearch.noResults): The center pane Source Search\n# message when the query did not match any of the sources.\nsourceSearch.noResults=No files matching %S found\n\n# LOCALIZATION NOTE (ignoreExceptions): The pause on exceptions button tooltip\n# when the debugger will not pause on exceptions.\nignoreExceptions=Ignore exceptions. Click to pause on uncaught exceptions\n\n# LOCALIZATION NOTE (pauseOnUncaughtExceptions): The pause on exceptions button\n# tooltip when the debugger will pause on uncaught exceptions.\npauseOnUncaughtExceptions=Pause on uncaught exceptions. Click to pause on all exceptions\n\n# LOCALIZATION NOTE (pauseOnExceptions): The pause on exceptions button tooltip\n# when the debugger will pause on all exceptions.\npauseOnExceptions=Pause on all exceptions. Click to ignore exceptions\n\n# LOCALIZATION NOTE (loadingText): The text that is displayed in the script\n# editor when the loading process has started but there is no file to display\n# yet.\nloadingText=Loading\\u2026\n\n# LOCALIZATION NOTE (errorLoadingText2): The text that is displayed in the debugger\n# viewer when there is an error loading a file\nerrorLoadingText2=Error loading this URL: %S\n\n# LOCALIZATION NOTE (addWatchExpressionText): The text that is displayed in the\n# watch expressions list to add a new item.\naddWatchExpressionText=Add watch expression\n\n# LOCALIZATION NOTE (addWatchExpressionButton): The button that is displayed in the\n# variables view popup.\naddWatchExpressionButton=Watch\n\n# LOCALIZATION NOTE (emptyVariablesText): The text that is displayed in the\n# variables pane when there are no variables to display.\nemptyVariablesText=No variables to display\n\n# LOCALIZATION NOTE (scopeLabel): The text that is displayed in the variables\n# pane as a header for each variable scope (e.g. \"Global scope, \"With scope\",\n# etc.).\nscopeLabel=%S scope\n\n# LOCALIZATION NOTE (watchExpressionsScopeLabel): The name of the watch\n# expressions scope. This text is displayed in the variables pane as a header for\n# the watch expressions scope.\nwatchExpressionsScopeLabel=Watch expressions\n\n# LOCALIZATION NOTE (globalScopeLabel): The name of the global scope. This text\n# is added to scopeLabel and displayed in the variables pane as a header for\n# the global scope.\nglobalScopeLabel=Global\n\n# LOCALIZATION NOTE (variablesViewErrorStacktrace): This is the text that is\n# shown before the stack trace in an error.\nvariablesViewErrorStacktrace=Stack trace:\n\n# LOCALIZATION NOTE (variablesViewMoreObjects): the text that is displayed\n# when you have an object preview that does not show all of the elements. At the end of the list\n# you see \"N more...\" in the web console output.\n# This is a semi-colon list of plural forms.\n# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals\n# #1 number of remaining items in the object\n# example: 3 more…\nvariablesViewMoreObjects=#1 more…;#1 more…\n\n# LOCALIZATION NOTE (variablesEditableNameTooltip): The text that is displayed\n# in the variables list on an item with an editable name.\nvariablesEditableNameTooltip=Double click to edit\n\n# LOCALIZATION NOTE (variablesEditableValueTooltip): The text that is displayed\n# in the variables list on an item with an editable value.\nvariablesEditableValueTooltip=Click to change value\n\n# LOCALIZATION NOTE (variablesCloseButtonTooltip): The text that is displayed\n# in the variables list on an item which can be removed.\nvariablesCloseButtonTooltip=Click to remove\n\n# LOCALIZATION NOTE (variablesEditButtonTooltip): The text that is displayed\n# in the variables list on a getter or setter which can be edited.\nvariablesEditButtonTooltip=Click to set value\n\n# LOCALIZATION NOTE (variablesEditableValueTooltip): The text that is displayed\n# in a tooltip on the \"open in inspector\" button in the the variables list for a\n# DOMNode item.\nvariablesDomNodeValueTooltip=Click to select the node in the inspector\n\n# LOCALIZATION NOTE (configurable|...|Tooltip): The text that is displayed\n# in the variables list on certain variables or properties as tooltips.\n# Expanations of what these represent can be found at the following links:\n# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty\n# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/isExtensible\n# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/isFrozen\n# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/isSealed\n# It's probably best to keep these in English.\nconfigurableTooltip=configurable\nenumerableTooltip=enumerable\nwritableTooltip=writable\nfrozenTooltip=frozen\nsealedTooltip=sealed\nextensibleTooltip=extensible\noverriddenTooltip=overridden\nWebIDLTooltip=WebIDL\n\n# LOCALIZATION NOTE (variablesSeparatorLabel): The text that is displayed\n# in the variables list as a separator between the name and value.\nvariablesSeparatorLabel=:\n\n# LOCALIZATION NOTE (watchExpressionsSeparatorLabel2): The text that is displayed\n# in the watch expressions list as a separator between the code and evaluation.\nwatchExpressionsSeparatorLabel2=\\u0020→\n\n# LOCALIZATION NOTE (functionSearchSeparatorLabel): The text that is displayed\n# in the functions search panel as a separator between function's inferred name\n# and its real name (if available).\nfunctionSearchSeparatorLabel=←\n\n# LOCALIZATION NOTE(symbolSearch.search.functionsPlaceholder): The placeholder\n# text displayed when the user searches for functions in a file\nsymbolSearch.search.functionsPlaceholder=Search functions…\n\n# LOCALIZATION NOTE(symbolSearch.search.variablesPlaceholder): The placeholder\n# text displayed when the user searches for variables in a file\nsymbolSearch.search.variablesPlaceholder=Search variables…\n\n# LOCALIZATION NOTE(symbolSearch.search.key2): The Key Shortcut for\n# searching for a function or variable\nsymbolSearch.search.key2=CmdOrCtrl+Shift+O\n\n# LOCALIZATION NOTE(symbolSearch.searchModifier.regex): A search option\n# when searching text in a file\nsymbolSearch.searchModifier.regex=Regex\n\n# LOCALIZATION NOTE(symbolSearch.searchModifier.caseSensitive): A search option\n# when searching text in a file\nsymbolSearch.searchModifier.caseSensitive=Case sensitive\n\n# LOCALIZATION NOTE(symbolSearch.searchModifier.wholeWord): A search option\n# when searching text in a file\nsymbolSearch.searchModifier.wholeWord=Whole word\n\n# LOCALIZATION NOTE (resumptionOrderPanelTitle): This is the text that appears\n# as a description in the notification panel popup, when multiple debuggers are\n# open in separate tabs and the user tries to resume them in the wrong order.\n# The substitution parameter is the URL of the last paused window that must be\n# resumed first.\nresumptionOrderPanelTitle=There are one or more paused debuggers. Please resume the most-recently paused debugger first at: %S\n\nvariablesViewOptimizedOut=(optimized away)\nvariablesViewUninitialized=(uninitialized)\nvariablesViewMissingArgs=(unavailable)\n\nanonymousSourcesLabel=Anonymous Sources\n\nexperimental=This is an experimental feature\n\n# LOCALIZATION NOTE (whyPaused.debuggerStatement): The text that is displayed\n# in a info block explaining how the debugger is currently paused due to a `debugger`\n# statement in the code\nwhyPaused.debuggerStatement=Paused on debugger statement\n\n# LOCALIZATION NOTE (whyPaused.breakpoint): The text that is displayed\n# in a info block explaining how the debugger is currently paused on a breakpoint\nwhyPaused.breakpoint=Paused on breakpoint\n\n# LOCALIZATION NOTE (whyPaused.exception): The text that is displayed\n# in a info block explaining how the debugger is currently paused on an exception\nwhyPaused.exception=Paused on exception\n\n# LOCALIZATION NOTE (whyPaused.resumeLimit): The text that is displayed\n# in a info block explaining how the debugger is currently paused while stepping\n# in or out of the stack\nwhyPaused.resumeLimit=Paused while stepping\n\n# LOCALIZATION NOTE (whyPaused.pauseOnDOMEvents): The text that is displayed\n# in a info block explaining how the debugger is currently paused on a\n# dom event\nwhyPaused.pauseOnDOMEvents=Paused on event listener\n\n# LOCALIZATION NOTE (whyPaused.breakpointConditionThrown): The text that is displayed\n# in an info block when evaluating a conditional breakpoint throws an error\nwhyPaused.breakpointConditionThrown=Error with conditional breakpoint\n\n# LOCALIZATION NOTE (whyPaused.xhr): The text that is displayed\n# in a info block explaining how the debugger is currently paused on an\n# xml http request\nwhyPaused.xhr=Paused on XMLHttpRequest\n\n# LOCALIZATION NOTE (whyPaused.promiseRejection): The text that is displayed\n# in a info block explaining how the debugger is currently paused on a\n# promise rejection\nwhyPaused.promiseRejection=Paused on promise rejection\n\n# LOCALIZATION NOTE (whyPaused.assert): The text that is displayed\n# in a info block explaining how the debugger is currently paused on an\n# assert\nwhyPaused.assert=Paused on assertion\n\n# LOCALIZATION NOTE (whyPaused.debugCommand): The text that is displayed\n# in a info block explaining how the debugger is currently paused on a\n# debugger statement\nwhyPaused.debugCommand=Paused on debugged function\n\n# LOCALIZATION NOTE (whyPaused.other): The text that is displayed\n# in a info block explaining how the debugger is currently paused on an event\n# listener breakpoint set\nwhyPaused.other=Debugger paused\n\n# LOCALIZATION NOTE (ctrl): The text that is used for documenting\n# keyboard shortcuts that use the control key\nctrl=Ctrl\n"
 
 /***/ },
 /* 961 */,
 /* 962 */,
-/* 963 */,
+/* 963 */
+/***/ function(module, exports, __webpack_require__) {
+
+	var baseKeys = __webpack_require__(217),
+	    getTag = __webpack_require__(198),
+	    isArguments = __webpack_require__(208),
+	    isArray = __webpack_require__(70),
+	    isArrayLike = __webpack_require__(220),
+	    isBuffer = __webpack_require__(210),
+	    isPrototype = __webpack_require__(218),
+	    isTypedArray = __webpack_require__(212);
+
+	/** `Object#toString` result references. */
+	var mapTag = '[object Map]',
+	    setTag = '[object Set]';
+
+	/** Used for built-in method references. */
+	var objectProto = Object.prototype;
+
+	/** Used to check objects for own properties. */
+	var hasOwnProperty = objectProto.hasOwnProperty;
+
+	/**
+	 * Checks if `value` is an empty object, collection, map, or set.
+	 *
+	 * Objects are considered empty if they have no own enumerable string keyed
+	 * properties.
+	 *
+	 * Array-like values such as `arguments` objects, arrays, buffers, strings, or
+	 * jQuery-like collections are considered empty if they have a `length` of `0`.
+	 * Similarly, maps and sets are considered empty if they have a `size` of `0`.
+	 *
+	 * @static
+	 * @memberOf _
+	 * @since 0.1.0
+	 * @category Lang
+	 * @param {*} value The value to check.
+	 * @returns {boolean} Returns `true` if `value` is empty, else `false`.
+	 * @example
+	 *
+	 * _.isEmpty(null);
+	 * // => true
+	 *
+	 * _.isEmpty(true);
+	 * // => true
+	 *
+	 * _.isEmpty(1);
+	 * // => true
+	 *
+	 * _.isEmpty([1, 2, 3]);
+	 * // => false
+	 *
+	 * _.isEmpty({ 'a': 1 });
+	 * // => false
+	 */
+	function isEmpty(value) {
+	  if (value == null) {
+	    return true;
+	  }
+	  if (isArrayLike(value) &&
+	      (isArray(value) || typeof value == 'string' || typeof value.splice == 'function' ||
+	        isBuffer(value) || isTypedArray(value) || isArguments(value))) {
+	    return !value.length;
+	  }
+	  var tag = getTag(value);
+	  if (tag == mapTag || tag == setTag) {
+	    return !value.size;
+	  }
+	  if (isPrototype(value)) {
+	    return !baseKeys(value).length;
+	  }
+	  for (var key in value) {
+	    if (hasOwnProperty.call(value, key)) {
+	      return false;
+	    }
+	  }
+	  return true;
+	}
+
+	module.exports = isEmpty;
+
+
+/***/ },
 /* 964 */,
 /* 965 */
 /***/ function(module, exports) {
 
 	
 	/**
 	 * slice() reference.
 	 */
@@ -47153,34 +47254,46 @@ return /******/ (function(modules) { // 
 	var FrameComponent = (0, _react.createFactory)(_Frame2.default);
 
 	var Group = (0, _react.createFactory)(_Group3.default);
 
 	var NUM_FRAMES_SHOWN = 7;
 
 	class Frames extends _react.Component {
 
+	  collapseFrames(frames) {
+	    var frameworkGroupingOn = this.props.frameworkGroupingOn;
+
+	    if (!frameworkGroupingOn) {
+	      return frames;
+	    }
+
+	    return (0, _frame.collapseFrames)(frames);
+	  }
+
 	  constructor() {
 	    super(...arguments);
 
 	    this.state = {
 	      showAllFrames: false
 	    };
 
 	    this.toggleFramesDisplay = this.toggleFramesDisplay.bind(this);
 	    this.copyStackTrace = this.copyStackTrace.bind(this);
+	    this.toggleFrameworkGrouping = this.toggleFrameworkGrouping.bind(this);
 	  }
 
 	  shouldComponentUpdate(nextProps, nextState) {
 	    var _props = this.props,
 	        frames = _props.frames,
-	        selectedFrame = _props.selectedFrame;
+	        selectedFrame = _props.selectedFrame,
+	        frameworkGroupingOn = _props.frameworkGroupingOn;
 	    var showAllFrames = this.state.showAllFrames;
 
-	    return frames !== nextProps.frames || selectedFrame !== nextProps.selectedFrame || showAllFrames !== nextState.showAllFrames;
+	    return frames !== nextProps.frames || selectedFrame !== nextProps.selectedFrame || showAllFrames !== nextState.showAllFrames || frameworkGroupingOn !== nextProps.frameworkGroupingOn;
 	  }
 
 	  toggleFramesDisplay() {
 	    this.setState({
 	      showAllFrames: !this.state.showAllFrames
 	    });
 	  }
 
@@ -47192,35 +47305,48 @@ return /******/ (function(modules) { // 
 
 	  copyStackTrace() {
 	    var frames = this.props.frames;
 
 	    var framesToCopy = frames.map(f => (0, _frame.formatCopyName)(f)).join("\n");
 	    (0, _clipboard.copyToTheClipboard)(framesToCopy);
 	  }
 
-	  renderFrames(frames) {
+	  toggleFrameworkGrouping() {
 	    var _props2 = this.props,
-	        selectFrame = _props2.selectFrame,
-	        selectedFrame = _props2.selectedFrame;
-
-
-	    var framesOrGroups = this.truncateFrames((0, _frame.collapseFrames)(frames));
+	        toggleFrameworkGrouping = _props2.toggleFrameworkGrouping,
+	        frameworkGroupingOn = _props2.frameworkGroupingOn;
+
+	    toggleFrameworkGrouping(!frameworkGroupingOn);
+	  }
+
+	  renderFrames(frames) {
+	    var _props3 = this.props,
+	        selectFrame = _props3.selectFrame,
+	        selectedFrame = _props3.selectedFrame,
+	        frameworkGroupingOn = _props3.frameworkGroupingOn;
+
+
+	    var framesOrGroups = this.truncateFrames(this.collapseFrames(frames));
 
 
 	    return _react.DOM.ul({}, framesOrGroups.map(frameOrGroup => frameOrGroup.id ? FrameComponent({
 	      frame: frameOrGroup,
+	      toggleFrameworkGrouping: this.toggleFrameworkGrouping,
 	      copyStackTrace: this.copyStackTrace,
+	      frameworkGroupingOn,
 	      frames,
 	      selectFrame,
 	      selectedFrame,
 	      key: frameOrGroup.id
 	    }) : Group({
 	      group: frameOrGroup,
+	      toggleFrameworkGrouping: this.toggleFrameworkGrouping,
 	      copyStackTrace: this.copyStackTrace,
+	      frameworkGroupingOn,
 	      selectFrame,
 	      selectedFrame,
 	      key: frameOrGroup[0].id
 	    })));
 	  }
 
 	  renderToggleButton(frames) {
 	    var buttonMessage = this.state.showAllFrames ? L10N.getStr("callStack.collapse") : L10N.getStr("callStack.expand");
@@ -47242,16 +47368,18 @@ return /******/ (function(modules) { // 
 	    }
 
 	    return _react.DOM.div({ className: "pane frames" }, this.renderFrames(frames), this.renderToggleButton(frames));
 	  }
 	}
 
 	Frames.propTypes = {
 	  frames: _react.PropTypes.array,
+	  frameworkGroupingOn: _react.PropTypes.bool.isRequired,
+	  toggleFrameworkGrouping: _react.PropTypes.func.isRequired,
 	  selectedFrame: _react.PropTypes.object,
 	  selectFrame: _react.PropTypes.func.isRequired
 	};
 
 	Frames.displayName = "Frames";
 
 	function getSourceForFrame(sources, frame) {
 	  return (0, _selectors.getSourceInSources)(sources, frame.location.sourceId);
@@ -47263,23 +47391,24 @@ return /******/ (function(modules) { // 
 	  });
 	}
 
 	var getAndProcessFrames = (0, _reselect.createSelector)(_selectors.getFrames, _selectors.getSources, (frames, sources) => {
 	  if (!frames) {
 	    return null;
 	  }
 
-	  frames = frames.toJS().filter(frame => getSourceForFrame(sources, frame)).filter(frame => !get(frame, "source.isBlackBoxed")).map(frame => appendSource(sources, frame)).map(_frame.annotateFrame);
+	  frames = frames.filter(frame => getSourceForFrame(sources, frame)).filter(frame => !get(frame, "source.isBlackBoxed")).map(frame => appendSource(sources, frame)).map(_frame.annotateFrame);
 
 	  return frames;
 	});
 
 	exports.default = (0, _reactRedux.connect)(state => ({
 	  frames: getAndProcessFrames(state),
+	  frameworkGroupingOn: (0, _selectors.getFrameworkGroupingState)(state),
 	  selectedFrame: (0, _selectors.getSelectedFrame)(state)
 	}), dispatch => (0, _redux.bindActionCreators)(_actions2.default, dispatch))(Frames);
 
 /***/ },
 /* 1013 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
@@ -47334,19 +47463,21 @@ return /******/ (function(modules) { // 
 
 	  constructor() {
 	    super(...arguments);
 	  }
 
 	  onContextMenu(event) {
 	    var _props = this.props,
 	        frame = _props.frame,
-	        copyStackTrace = _props.copyStackTrace;
-
-	    (0, _FrameMenu2.default)(frame, copyStackTrace, event);
+	        copyStackTrace = _props.copyStackTrace,
+	        toggleFrameworkGrouping = _props.toggleFrameworkGrouping,
+	        frameworkGroupingOn = _props.frameworkGroupingOn;
+
+	    (0, _FrameMenu2.default)(frame, frameworkGroupingOn, { copyStackTrace, toggleFrameworkGrouping }, event);
 	  }
 
 	  onMouseDown(e, frame, selectedFrame) {
 	    if (e.nativeEvent.which == 3 && selectedFrame.id != frame.id) {
 	      return;
 	    }
 	    this.props.selectFrame(frame);
 	  }
@@ -47688,40 +47819,46 @@ return /******/ (function(modules) { // 
 	    var self = this;
 
 	    self.toggleFrames = this.toggleFrames.bind(this);
 	  }
 
 	  onContextMenu(event) {
 	    var _props = this.props,
 	        group = _props.group,
-	        copyStackTrace = _props.copyStackTrace;
+	        copyStackTrace = _props.copyStackTrace,
+	        toggleFrameworkGrouping = _props.toggleFrameworkGrouping,
+	        frameworkGroupingOn = _props.frameworkGroupingOn;
 
 	    var frame = group[0];
-	    (0, _FrameMenu2.default)(frame, copyStackTrace, event);
+	    (0, _FrameMenu2.default)(frame, frameworkGroupingOn, { copyStackTrace, toggleFrameworkGrouping }, event);
 	  }
 
 	  toggleFrames() {
 	    this.setState({ expanded: !this.state.expanded });
 	  }
 
 	  renderFrames() {
 	    var _props2 = this.props,
 	        group = _props2.group,
 	        selectFrame = _props2.selectFrame,
 	        selectedFrame = _props2.selectedFrame,
+	        toggleFrameworkGrouping = _props2.toggleFrameworkGrouping,
+	        frameworkGroupingOn = _props2.frameworkGroupingOn,
 	        copyStackTrace = _props2.copyStackTrace;
 	    var expanded = this.state.expanded;
 
 	    if (!expanded) {
 	      return null;
 	    }
 	    return _react.DOM.div({ className: "frames-list" }, group.map(frame => FrameComponent({
 	      frame,
 	      copyStackTrace,
+	      toggleFrameworkGrouping,
+	      frameworkGroupingOn,
 	      selectFrame,
 	      selectedFrame,
 	      key: frame.id,
 	      hideLocation: true,
 	      shouldMapDisplayName: false
 	    })));
 	  }
 
@@ -47779,16 +47916,20 @@ return /******/ (function(modules) { // 
 	});
 
 	var _react = __webpack_require__(2);
 
 	var _range = __webpack_require__(1026);
 
 	var _range2 = _interopRequireDefault(_range);
 
+	var _isEmpty = __webpack_require__(963);
+
+	var _isEmpty2 = _interopRequireDefault(_isEmpty);
+
 	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 	class HighlightLines extends _react.Component {
 
 	  constructor() {
 	    super();
 	    this.highlightLineRange = this.highlightLineRange.bind(this);
 	  }
@@ -47821,17 +47962,17 @@ return /******/ (function(modules) { // 
 
 	    if (!editor) {
 	      return;
 	    }
 
 	    var codeMirror = editor.codeMirror;
 
 
-	    if (!highlightedLineRange || !editor || !codeMirror) {
+	    if ((0, _isEmpty2.default)(highlightedLineRange) || !editor || !codeMirror) {
 	      return;
 	    }
 
 	    var start = highlightedLineRange.start,
 	        end = highlightedLineRange.end;
 
 
 	    (0, _range2.default)(start - 1, end).forEach(line => {
@@ -47847,17 +47988,17 @@ return /******/ (function(modules) { // 
 
 	    if (!editor) {
 	      return;
 	    }
 
 	    var codeMirror = editor.codeMirror;
 
 
-	    if (!highlightedLineRange || !codeMirror) {
+	    if ((0, _isEmpty2.default)(highlightedLineRange) || !codeMirror) {
 	      return;
 	    }
 
 	    var start = highlightedLineRange.start,
 	        end = highlightedLineRange.end;
 
 
 	    editor.alignLine(start);
@@ -47867,16 +48008,17 @@ return /******/ (function(modules) { // 
 	    });
 	  }
 
 	  render() {
 	    return null;
 	  }
 	}
 
+
 	HighlightLines.displayName = "HighlightLines";
 
 	exports.default = HighlightLines;
 
 /***/ },
 /* 1026 */
 /***/ function(module, exports, __webpack_require__) {
 
@@ -48064,48 +48206,59 @@ return /******/ (function(modules) { // 
 	var _clipboard = __webpack_require__(423);
 
 	var _kebabCase = __webpack_require__(1034);
 
 	function formatMenuElement(labelString, accesskeyString, click) {
 	  var disabled = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
 
 	  var label = L10N.getStr(labelString);
+	  var accesskey = L10N.getStr(accesskeyString);
 	  var id = `node-menu-${(0, _kebabCase.kebabCase)(label)}`;
 	  return {
 	    id,
 	    label,
-	    accesskey: L10N.getStr(accesskeyString),
+	    accesskey,
 	    disabled,
 	    click
 	  };
 	}
 
 
 	function copySourceElement(url) {
 	  return formatMenuElement("copySourceUrl", "copySourceUrl.accesskey", () => (0, _clipboard.copyToTheClipboard)(url));
 	}
 
 	function copyStackTraceElement(copyStackTrace) {
 	  return formatMenuElement("copyStackTrace", "copyStackTrace.accesskey", () => copyStackTrace());
 	}
 
-	function FrameMenu(frame, copyStackTrace, event) {
+	function toggleFrameworkGroupingElement(toggleFrameworkGrouping, frameworkGroupingOn) {
+	  var actionType = frameworkGroupingOn ? "framework.disableGrouping" : "framework.enableGrouping";
+
+	  return formatMenuElement(actionType, "framework.accesskey", () => toggleFrameworkGrouping());
+	}
+
+	function FrameMenu(frame, frameworkGroupingOn, callbacks, event) {
 	  event.stopPropagation();
 	  event.preventDefault();
 
 	  var menuOptions = [];
 
 	  var source = frame.source;
+
+	  var toggleFrameworkElement = toggleFrameworkGroupingElement(callbacks.toggleFrameworkGrouping, frameworkGroupingOn);
+	  menuOptions.push(toggleFrameworkElement);
+
 	  if (source) {
 	    var copySourceUrl = copySourceElement(source.url);
 	    menuOptions.push(copySourceUrl);
 	  }
 
-	  var copyStackTraceItem = copyStackTraceElement(copyStackTrace);
+	  var copyStackTraceItem = copyStackTraceElement(callbacks.copyStackTrace);
 
 	  menuOptions.push(copyStackTraceItem);
 
 	  (0, _devtoolsLaunchpad.showMenu)(event, menuOptions);
 	}
 
 /***/ },
 /* 1033 */,
--- a/devtools/client/debugger/new/panel.js
+++ b/devtools/client/debugger/new/panel.js
@@ -60,17 +60,16 @@ DebuggerPanel.prototype = {
     // Frames is null when the debugger is not paused.
     if (!frames) {
       return {
         frames: [],
         selected: -1
       };
     }
 
-    frames = frames.toJS();
     const selectedFrame = this._selectors.getSelectedFrame(this._getState());
     const selected = frames.findIndex(frame => frame.id == selectedFrame.id);
 
     frames.forEach(frame => {
       frame.actor = frame.id;
     });
 
     return { frames, selected };
--- a/devtools/client/debugger/new/parser-worker.js
+++ b/devtools/client/debugger/new/parser-worker.js
@@ -29192,17 +29192,17 @@ return /******/ (function(modules) { // 
 	    return end.column >= column;
 	  }
 
 	  // node is either inside the block body or outside of it
 	  return start.line < line && end.line > line;
 	}
 
 	function isLexicalScope(path) {
-	  return isFunction(path) || t.isProgram(path);
+	  return t.isBlockStatement(path) || isFunction(path) || t.isProgram(path);
 	}
 
 	function getSymbols(source) {
 	  if (symbolDeclarations.has(source.id)) {
 	    var _symbols = symbolDeclarations.get(source.id);
 	    if (_symbols) {
 	      return _symbols;
 	    }
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-chrome-debugging.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-chrome-debugging.js
@@ -63,26 +63,26 @@ registerCleanupFunction(function() {
   gThreadClient = null;
   gNewGlobal = null;
   gNewChromeSource = null;
 
   customLoader = null;
   DebuggerServer = null;
 });
 
-add_task(function* () {
+add_task(function*() {
   gClient = initDebuggerClient();
 
   const [type] = yield gClient.connect();
   is(type, "browser", "Root actor should identify itself as a browser.");
 
   const response = yield gClient.getProcess();
   let actor = response.form.actor;
   gThreadClient = yield attachThread(gClient, actor);
   gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, "about:mozilla");
 
   // listen for a new source and global
   gThreadClient.addListener("newSource", onNewSource);
   gClient.addListener("newGlobal", onNewGlobal);
-  yield promise.all([ gNewGlobal.promise, gNewChromeSource.promise ]);
+  yield promise.all([gNewGlobal.promise, gNewChromeSource.promise]);
 
   yield resumeAndCloseConnection();
 });
--- a/devtools/client/debugger/new/test/mochitest/head.js
+++ b/devtools/client/debugger/new/test/mochitest/head.js
@@ -203,19 +203,21 @@ function waitForElement(dbg, selector) {
 function assertPausedLocation(dbg, source, line) {
   const { selectors: { getSelectedSource, getPause }, getState } = dbg;
   source = findSource(dbg, source);
 
   // Check the selected source
   is(getSelectedSource(getState()).get("id"), source.id);
 
   // Check the pause location
-  const location = getPause(getState()).getIn(["frame", "location"]);
-  is(location.get("sourceId"), source.id);
-  is(location.get("line"), line);
+  const pause = getPause(getState());
+  const location = pause && pause.frame && pause.frame.location;
+
+  is(location.sourceId, source.id);
+  is(location.line, line);
 
   // Check the debug line
   ok(
     getCM(dbg).lineInfo(line - 1).wrapClass.includes("debug-line"),
     "Line is highlighted as paused"
   );
 }
 
@@ -275,17 +277,17 @@ function waitForPaused(dbg) {
     yield waitForThreadEvents(dbg, "paused"), yield waitForState(dbg, state => {
       const pause = dbg.selectors.getPause(state);
       // Make sure we have the paused state.
       if (!pause) {
         return false;
       }
       // Make sure the source text is completely loaded for the
       // source we are paused in.
-      const sourceId = pause.getIn(["frame", "location", "sourceId"]);
+      const sourceId = pause && pause.frame && pause.frame.location.sourceId;
       const sourceText = dbg.selectors.getSourceText(dbg.getState(), sourceId);
       return sourceText && !sourceText.get("loading");
     });
   });
 }
 
 function createDebuggerContext(toolbox) {
   const panel = toolbox.getPanel("jsdebugger");
--- a/devtools/client/framework/source-map-url-service.js
+++ b/devtools/client/framework/source-map-url-service.js
@@ -25,16 +25,17 @@ function SourceMapURLService(target, sou
   target.on("source-updated", this._onSourceUpdated);
   target.on("will-navigate", this.reset);
 }
 
 /**
  * Reset the service.  This flushes the internal cache.
  */
 SourceMapURLService.prototype.reset = function () {
+  this._sourceMapService.clearSourceMaps();
   this._urls.clear();
 };
 
 /**
  * Shut down the service, unregistering its event listeners and
  * flushing the cache.  After this call the service will no longer
  * function.
  */
@@ -78,12 +79,18 @@ SourceMapURLService.prototype.originalPo
   if (!urlInfo) {
     return null;
   }
   // Call getOriginalURLs to make sure the source map has been
   // fetched.  We don't actually need the result of this though.
   await this._sourceMapService.getOriginalURLs(urlInfo);
   const location = { sourceId: urlInfo.id, line, column, sourceUrl: url };
   let resolvedLocation = await this._sourceMapService.getOriginalLocation(location);
-  return resolvedLocation === location ? null : resolvedLocation;
+  if (!resolvedLocation ||
+      (resolvedLocation.line === location.line &&
+       resolvedLocation.column === location.column &&
+       resolvedLocation.sourceUrl === location.sourceUrl)) {
+    return null;
+  }
+  return resolvedLocation;
 };
 
 exports.SourceMapURLService = SourceMapURLService;
--- a/devtools/client/framework/test/browser.ini
+++ b/devtools/client/framework/test/browser.ini
@@ -6,44 +6,54 @@ support-files =
   browser_toolbox_options_disable_js_iframe.html
   browser_toolbox_options_disable_cache.sjs
   browser_toolbox_sidebar_tool.xul
   browser_toolbox_window_title_changes_page.html
   browser_toolbox_window_title_frame_select_page.html
   code_binary_search.coffee
   code_binary_search.js
   code_binary_search.map
+  code_bundle_reload_1.js
+  code_bundle_reload_1.js.map
+  code_bundle_reload_2.js
+  code_bundle_reload_2.js.map
   code_inline_bundle.js
   code_inline_original.js
   code_math.js
+  code_reload_1.js
+  code_reload_2.js
   doc_empty-tab-01.html
+  doc_reload.html
   head.js
   shared-head.js
   shared-redux-head.js
   helper_disable_cache.js
   doc_theme.css
   doc_viewsource.html
   browser_toolbox_options_enable_serviceworkers_testing_frame_script.js
   browser_toolbox_options_enable_serviceworkers_testing.html
   serviceworker.js
+  sjs_code_reload.sjs
+  sjs_code_bundle_reload_map.sjs
   test_browser_toolbox_debugger.js
 
 [browser_browser_toolbox.js]
 [browser_browser_toolbox_debugger.js]
 [browser_devtools_api.js]
 [browser_devtools_api_destroy.js]
 [browser_dynamic_tool_enabling.js]
 [browser_ignore_toolbox_network_requests.js]
 [browser_keybindings_01.js]
 [browser_keybindings_02.js]
 [browser_keybindings_03.js]
 [browser_menu_api.js]
 [browser_new_activation_workflow.js]
 [browser_source_map-01.js]
 [browser_source_map-inline.js]
+[browser_source_map-reload.js]
 [browser_target_from_url.js]
 [browser_target_events.js]
 [browser_target_remote.js]
 [browser_target_support.js]
 [browser_toolbox_custom_host.js]
 [browser_toolbox_dynamic_registration.js]
 [browser_toolbox_getpanelwhenready.js]
 [browser_toolbox_highlight.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/framework/test/browser_source_map-reload.js
@@ -0,0 +1,48 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that reloading re-reads the source maps.
+
+"use strict";
+
+const INITIAL_URL = URL_ROOT + "doc_empty-tab-01.html";
+const PAGE_URL = URL_ROOT + "doc_reload.html";
+const JS_URL = URL_ROOT + "sjs_code_reload.sjs";
+
+const ORIGINAL_URL_1 = "webpack:///code_reload_1.js";
+const ORIGINAL_URL_2 = "webpack:///code_reload_2.js";
+
+const GENERATED_LINE = 86;
+const ORIGINAL_LINE = 13;
+
+add_task(function* () {
+  // Start with the empty page, then navigate, so that we can properly
+  // listen for new sources arriving.
+  const toolbox = yield openNewTabAndToolbox(INITIAL_URL, "webconsole");
+  const service = toolbox.sourceMapURLService;
+  const tab = toolbox.target.tab;
+
+  let sourceSeen = waitForSourceLoad(toolbox, JS_URL);
+  tab.linkedBrowser.loadURI(PAGE_URL);
+  yield sourceSeen;
+
+  info(`checking original location for ${JS_URL}:${GENERATED_LINE}`);
+  let newLoc = yield service.originalPositionFor(JS_URL, GENERATED_LINE);
+  is(newLoc.sourceUrl, ORIGINAL_URL_1, "check mapped URL");
+  is(newLoc.line, ORIGINAL_LINE, "check mapped line number");
+
+  // Reload the page.  The sjs ensures that a different source file
+  // will be loaded.
+  sourceSeen = waitForSourceLoad(toolbox, JS_URL);
+  yield refreshTab(tab);
+  yield sourceSeen;
+
+  info(`checking post-reload original location for ${JS_URL}:${GENERATED_LINE}`);
+  newLoc = yield service.originalPositionFor(JS_URL, GENERATED_LINE);
+  is(newLoc.sourceUrl, ORIGINAL_URL_2, "check post-reload mapped URL");
+  is(newLoc.line, ORIGINAL_LINE, "check post-reload mapped line number");
+
+  yield toolbox.destroy();
+  gBrowser.removeCurrentTab();
+  finish();
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/framework/test/code_bundle_reload_1.js
@@ -0,0 +1,94 @@
+/******/ (function(modules) { // webpackBootstrap
+/******/ 	// The module cache
+/******/ 	var installedModules = {};
+/******/
+/******/ 	// The require function
+/******/ 	function __webpack_require__(moduleId) {
+/******/
+/******/ 		// Check if module is in cache
+/******/ 		if(installedModules[moduleId]) {
+/******/ 			return installedModules[moduleId].exports;
+/******/ 		}
+/******/ 		// Create a new module (and put it into the cache)
+/******/ 		var module = installedModules[moduleId] = {
+/******/ 			i: moduleId,
+/******/ 			l: false,
+/******/ 			exports: {}
+/******/ 		};
+/******/
+/******/ 		// Execute the module function
+/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+/******/
+/******/ 		// Flag the module as loaded
+/******/ 		module.l = true;
+/******/
+/******/ 		// Return the exports of the module
+/******/ 		return module.exports;
+/******/ 	}
+/******/
+/******/
+/******/ 	// expose the modules object (__webpack_modules__)
+/******/ 	__webpack_require__.m = modules;
+/******/
+/******/ 	// expose the module cache
+/******/ 	__webpack_require__.c = installedModules;
+/******/
+/******/ 	// identity function for calling harmony imports with the correct context
+/******/ 	__webpack_require__.i = function(value) { return value; };
+/******/
+/******/ 	// define getter function for harmony exports
+/******/ 	__webpack_require__.d = function(exports, name, getter) {
+/******/ 		if(!__webpack_require__.o(exports, name)) {
+/******/ 			Object.defineProperty(exports, name, {
+/******/ 				configurable: false,
+/******/ 				enumerable: true,
+/******/ 				get: getter
+/******/ 			});
+/******/ 		}
+/******/ 	};
+/******/
+/******/ 	// getDefaultExport function for compatibility with non-harmony modules
+/******/ 	__webpack_require__.n = function(module) {
+/******/ 		var getter = module && module.__esModule ?
+/******/ 			function getDefault() { return module['default']; } :
+/******/ 			function getModuleExports() { return module; };
+/******/ 		__webpack_require__.d(getter, 'a', getter);
+/******/ 		return getter;
+/******/ 	};
+/******/
+/******/ 	// Object.prototype.hasOwnProperty.call
+/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
+/******/
+/******/ 	// __webpack_public_path__
+/******/ 	__webpack_require__.p = "";
+/******/
+/******/ 	// Load entry module and return exports
+/******/ 	return __webpack_require__(__webpack_require__.s = 0);
+/******/ })
+/************************************************************************/
+/******/ ([
+/* 0 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Original source code for the inline source map test.
+// The generated file was made with
+//    webpack --devtool source-map code_reload_1.js code_bundle_reload_1.js
+//    perl -pi -e 's/sjs_code_bundle_reload_map.sjs/sjs_code_bundle_reload_map.sjs/' \
+//         code_bundle_reload_1.js
+
+
+
+function f() {
+  console.log("The first version of the script");
+}
+
+f();
+
+
+/***/ })
+/******/ ]);
+//# sourceMappingURL=sjs_code_bundle_reload_map.sjs
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/devtools/client/framework/test/code_bundle_reload_1.js.map
@@ -0,0 +1,1 @@
+{"version":3,"sources":["webpack:///webpack/bootstrap 59857d9393d4518a63ff","webpack:///./code_reload_1.js"],"names":[],"mappings":";AAAA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA,mDAA2C,cAAc;;AAEzD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;AAEA;AACA;;;;;;;;AChEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA","file":"code_bundle_reload_1.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// identity function for calling harmony imports with the correct context\n \t__webpack_require__.i = function(value) { return value; };\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 59857d9393d4518a63ff","/* Any copyright is dedicated to the Public Domain.\n http://creativecommons.org/publicdomain/zero/1.0/ */\n\n// Original source code for the inline source map test.\n// The generated file was made with\n//    webpack --devtool source-map code_reload_1.js code_bundle_reload_1.js\n//    perl -pi -e 's/code_bundle_reload_1.js.map/sjs_code_bundle_reload_map.sjs/' \\\n//         code_bundle_reload_1.js\n\n\"use strict\";\n\nfunction f() {\n  console.log(\"The first version of the script\");\n}\n\nf();\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./code_reload_1.js\n// module id = 0\n// module chunks = 0"],"sourceRoot":""}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/devtools/client/framework/test/code_bundle_reload_2.js
@@ -0,0 +1,94 @@
+/******/ (function(modules) { // webpackBootstrap
+/******/ 	// The module cache
+/******/ 	var installedModules = {};
+/******/
+/******/ 	// The require function
+/******/ 	function __webpack_require__(moduleId) {
+/******/
+/******/ 		// Check if module is in cache
+/******/ 		if(installedModules[moduleId]) {
+/******/ 			return installedModules[moduleId].exports;
+/******/ 		}
+/******/ 		// Create a new module (and put it into the cache)
+/******/ 		var module = installedModules[moduleId] = {
+/******/ 			i: moduleId,
+/******/ 			l: false,
+/******/ 			exports: {}
+/******/ 		};
+/******/
+/******/ 		// Execute the module function
+/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+/******/
+/******/ 		// Flag the module as loaded
+/******/ 		module.l = true;
+/******/
+/******/ 		// Return the exports of the module
+/******/ 		return module.exports;
+/******/ 	}
+/******/
+/******/
+/******/ 	// expose the modules object (__webpack_modules__)
+/******/ 	__webpack_require__.m = modules;
+/******/
+/******/ 	// expose the module cache
+/******/ 	__webpack_require__.c = installedModules;
+/******/
+/******/ 	// identity function for calling harmony imports with the correct context
+/******/ 	__webpack_require__.i = function(value) { return value; };
+/******/
+/******/ 	// define getter function for harmony exports
+/******/ 	__webpack_require__.d = function(exports, name, getter) {
+/******/ 		if(!__webpack_require__.o(exports, name)) {
+/******/ 			Object.defineProperty(exports, name, {
+/******/ 				configurable: false,
+/******/ 				enumerable: true,
+/******/ 				get: getter
+/******/ 			});
+/******/ 		}
+/******/ 	};
+/******/
+/******/ 	// getDefaultExport function for compatibility with non-harmony modules
+/******/ 	__webpack_require__.n = function(module) {
+/******/ 		var getter = module && module.__esModule ?
+/******/ 			function getDefault() { return module['default']; } :
+/******/ 			function getModuleExports() { return module; };
+/******/ 		__webpack_require__.d(getter, 'a', getter);
+/******/ 		return getter;
+/******/ 	};
+/******/
+/******/ 	// Object.prototype.hasOwnProperty.call
+/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
+/******/
+/******/ 	// __webpack_public_path__
+/******/ 	__webpack_require__.p = "";
+/******/
+/******/ 	// Load entry module and return exports
+/******/ 	return __webpack_require__(__webpack_require__.s = 0);
+/******/ })
+/************************************************************************/
+/******/ ([
+/* 0 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Original source code for the inline source map test.
+// The generated file was made with
+//    webpack --devtool source-map code_reload_2.js code_bundle_reload_2.js
+//    perl -pi -e 's/sjs_code_bundle_reload_map.sjs/sjs_code_bundle_reload_map.sjs/' \
+//         code_bundle_reload_2.js
+
+
+
+function f() {
+  console.log("The second version of the script");
+}
+
+f();
+
+
+/***/ })
+/******/ ]);
+//# sourceMappingURL=sjs_code_bundle_reload_map.sjs
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/devtools/client/framework/test/code_bundle_reload_2.js.map
@@ -0,0 +1,1 @@
+{"version":3,"sources":["webpack:///webpack/bootstrap 9497621dfe5d6f67322e","webpack:///./code_reload_2.js"],"names":[],"mappings":";AAAA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA,mDAA2C,cAAc;;AAEzD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;AAEA;AACA;;;;;;;;AChEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA","file":"code_bundle_reload_2.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// identity function for calling harmony imports with the correct context\n \t__webpack_require__.i = function(value) { return value; };\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 9497621dfe5d6f67322e","/* Any copyright is dedicated to the Public Domain.\n http://creativecommons.org/publicdomain/zero/1.0/ */\n\n// Original source code for the inline source map test.\n// The generated file was made with\n//    webpack --devtool source-map code_reload_2.js code_bundle_reload_2.js\n//    perl -pi -e 's/code_bundle_reload_2.js.map/sjs_code_bundle_reload_map.sjs/' \\\n//         code_bundle_reload_2.js\n\n\"use strict\";\n\nfunction f() {\n  console.log(\"The second version of the script\");\n}\n\nf();\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./code_reload_2.js\n// module id = 0\n// module chunks = 0"],"sourceRoot":""}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/devtools/client/framework/test/code_reload_1.js
@@ -0,0 +1,16 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Original source code for the inline source map test.
+// The generated file was made with
+//    webpack --devtool source-map code_reload_1.js code_bundle_reload_1.js
+//    perl -pi -e 's/code_bundle_reload_1.js.map/sjs_code_bundle_reload_map.sjs/' \
+//         code_bundle_reload_1.js
+
+"use strict";
+
+function f() {
+  console.log("The first version of the script");
+}
+
+f();
new file mode 100644
--- /dev/null
+++ b/devtools/client/framework/test/code_reload_2.js
@@ -0,0 +1,16 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Original source code for the inline source map test.
+// The generated file was made with
+//    webpack --devtool source-map code_reload_2.js code_bundle_reload_2.js
+//    perl -pi -e 's/code_bundle_reload_2.js.map/sjs_code_bundle_reload_map.sjs/' \
+//         code_bundle_reload_2.js
+
+"use strict";
+
+function f() {
+  console.log("The second version of the script");
+}
+
+f();
new file mode 100644
--- /dev/null
+++ b/devtools/client/framework/test/doc_reload.html
@@ -0,0 +1,15 @@
+<!-- Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/ -->
+<!doctype html>
+
+<html>
+  <script src="sjs_code_reload.sjs"></script>
+  <head>
+    <meta charset="utf-8"/>
+    <title>Empty test page 1</title>
+  </head>
+
+  <body>
+  </body>
+
+</html>
new file mode 100644
--- /dev/null
+++ b/devtools/client/framework/test/sjs_code_bundle_reload_map.sjs
@@ -0,0 +1,26 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/* globals getState, setState */
+/* exported handleRequest */
+
+"use strict";
+
+function handleRequest(request, response) {
+  response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
+  response.setHeader("Pragma", "no-cache");
+  response.setHeader("Expires", "0");
+  response.setHeader("Access-Control-Allow-Origin", "*", false);
+
+  // Redirect to a different file each time.
+  let counter = 1 + +getState("counter");
+
+  let index = request.path.lastIndexOf("/");
+  let newPath = request.path.substr(0, index + 1) +
+      "code_bundle_reload_" + counter + ".js.map";
+  let newUrl = request.scheme + "://" + request.host + newPath;
+
+  response.setStatusLine(request.httpVersion, 302, "Found");
+  response.setHeader("Location", newUrl);
+  setState("counter", "" + counter);
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/framework/test/sjs_code_reload.sjs
@@ -0,0 +1,26 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/* globals getState, setState */
+/* exported handleRequest */
+
+"use strict";
+
+function handleRequest(request, response) {
+  response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
+  response.setHeader("Pragma", "no-cache");
+  response.setHeader("Expires", "0");
+  response.setHeader("Access-Control-Allow-Origin", "*", false);
+
+  // Redirect to a different file each time.
+  let counter = 1 + +getState("counter");
+
+  let index = request.path.lastIndexOf("/");
+  let newPath = request.path.substr(0, index + 1) +
+      "code_bundle_reload_" + counter + ".js";
+  let newUrl = request.scheme + "://" + request.host + newPath;
+
+  response.setStatusLine(request.httpVersion, 302, "Found");
+  response.setHeader("Location", newUrl);
+  setState("counter", "" + counter);
+}
--- a/devtools/client/inspector/test/browser.ini
+++ b/devtools/client/inspector/test/browser.ini
@@ -63,16 +63,17 @@ skip-if = os == "mac" # Full keyboard na
 [browser_inspector_destroy-after-navigation.js]
 [browser_inspector_destroy-before-ready.js]
 [browser_inspector_expand-collapse.js]
 [browser_inspector_gcli-inspect-command.js]
 [browser_inspector_highlighter-01.js]
 [browser_inspector_highlighter-02.js]
 [browser_inspector_highlighter-03.js]
 [browser_inspector_highlighter-04.js]
+[browser_inspector_highlighter-05.js]
 [browser_inspector_highlighter-by-type.js]
 [browser_inspector_highlighter-cancel.js]
 [browser_inspector_highlighter-comments.js]
 [browser_inspector_highlighter-cssgrid_01.js]
 [browser_inspector_highlighter-cssgrid_02.js]
 [browser_inspector_highlighter-csstransform_01.js]
 [browser_inspector_highlighter-csstransform_02.js]
 [browser_inspector_highlighter-embed.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/test/browser_inspector_highlighter-05.js
@@ -0,0 +1,69 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+// This is testing that the Anonymous Content is properly inserted into the document.
+// Usually that is happening during the "interactive" state of the document, to have them
+// ready as soon as possible.
+// However, in some conditions, that's not possible since we don't have access yet to
+// the `CustomContentContainer`, that is used to add the Anonymous Content.
+// That can happen if the page has some external resource, as <link>, that takes time
+// to load and / or returns the wrong content. This is not happening, for instance, with
+// images.
+//
+// In those case, we want to be sure that if we're not able to insert the Anonymous
+// Content at the "interactive" state, we're doing so when the document is loaded.
+//
+// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1365075
+
+const server = createTestHTTPServer();
+const filepath = "/slow.css";
+const cssuri = `http://localhost:${server.identity.primaryPort}${filepath}`;
+
+// Register a slow css file handler so we can simulate a long loading time.
+server.registerContentType("css", "text/css");
+server.registerPathHandler(filepath, (metadata, response) => {
+  info("CSS has been requested");
+  response.processAsync();
+  setTimeout(() => {
+    info("CSS is responding");
+    response.finish();
+  }, 2000);
+});
+
+const TEST_URL = "data:text/html," + encodeURIComponent(`
+  <!DOCTYPE html>
+  <html>
+    <head>
+      <link href="${cssuri}" rel="stylesheet" />
+    </head>
+    <body>
+      <p>Slow page</p>
+     </body>
+  </html>
+`);
+
+add_task(function* () {
+  info("Open the inspector to a blank page.");
+  let { inspector, tab, testActor } = yield openInspectorForURL("about:blank");
+
+  let pageLoaded = waitForPageLoad(tab);
+
+  info("Navigate to the test url and waiting for the page to be loaded.");
+  yield navigateTo(inspector, TEST_URL);
+  yield pageLoaded;
+
+  info("Shows the box model highligher for the <p> node.");
+  let divFront = yield getNodeFront("p", inspector);
+  yield inspector.highlighter.showBoxModel(divFront);
+
+  info("Check the node is highlighted.");
+  is(yield testActor.isHighlighting(), true,
+    "Box Model highlighter is working as expected.");
+});
+
+const waitForPageLoad = (tab) => new Promise(resolve => {
+  tab.linkedBrowser.addEventListener("load", resolve, {capture: true, once: true});
+});
--- a/devtools/client/locales/en-US/debugger.properties
+++ b/devtools/client/locales/en-US/debugger.properties
@@ -301,16 +301,28 @@ editor.conditionalPanel.placeholder=This
 # LOCALIZATION NOTE (editor.conditionalPanel.placeholder): Tooltip text for
 # close button inside ConditionalPanel component
 editor.conditionalPanel.close=Cancel edit breakpoint and close
 
 # LOCALIZATION NOTE (editor.jumpToMappedLocation1): Context menu item
 # for navigating to a source mapped location
 editor.jumpToMappedLocation1=Jump to %S location
 
+# LOCALIZATION NOTE (framework.disableGrouping): This is the text that appears in the
+# context menu to disable framework grouping.
+framework.disableGrouping=Disable Framework Grouping
+
+# LOCALIZATION NOTE (framework.enableGrouping): This is the text that appears in the
+# context menu to enable framework grouping.
+framework.enableGrouping=Enable Framework Grouping
+
+# LOCALIZATION NOTE (framework.accesskey): Access key to toggle framework grouping from
+# the context menu.
+framework.accesskey=u
+
 # LOCALIZATION NOTE (generated): Source Map term for a server source location
 generated=generated
 
 # LOCALIZATION NOTE (original): Source Map term for a debugger UI source location
 original=original
 
 # LOCALIZATION NOTE (expressions.placeholder): Placeholder text for expression
 # input element
--- a/devtools/client/preferences/debugger.js
+++ b/devtools/client/preferences/debugger.js
@@ -25,16 +25,17 @@ pref("devtools.debugger.workers", false)
 
 // The default Debugger UI settings
 pref("devtools.debugger.ui.panes-workers-and-sources-width", 200);
 pref("devtools.debugger.ui.panes-instruments-width", 300);
 pref("devtools.debugger.ui.panes-visible-on-startup", false);
 pref("devtools.debugger.ui.variables-sorting-enabled", true);
 pref("devtools.debugger.ui.variables-only-enum-visible", false);
 pref("devtools.debugger.ui.variables-searchbox-visible", false);
+pref("devtools.debugger.ui.framework-grouping-on", true);
 pref("devtools.debugger.call-stack-visible", false);
 pref("devtools.debugger.scopes-visible", false);
 pref("devtools.debugger.start-panel-collapsed", false);
 pref("devtools.debugger.end-panel-collapsed", false);
 pref("devtools.debugger.tabs", "[]");
 pref("devtools.debugger.pending-selected-location", "{}");
 pref("devtools.debugger.pending-breakpoints", "[]");
 pref("devtools.debugger.expressions", "[]");
--- a/devtools/client/shared/components/stack-trace.js
+++ b/devtools/client/shared/components/stack-trace.js
@@ -30,23 +30,26 @@ const AsyncFrame = createFactory(createC
 
 const StackTrace = createClass({
   displayName: "StackTrace",
 
   propTypes: {
     stacktrace: PropTypes.array.isRequired,
     onViewSourceInDebugger: PropTypes.func.isRequired,
     onViewSourceInScratchpad: PropTypes.func,
+    // Service to enable the source map feature.
+    sourceMapService: PropTypes.object,
   },
 
   render() {
     let {
       stacktrace,
       onViewSourceInDebugger,
-      onViewSourceInScratchpad
+      onViewSourceInScratchpad,
+      sourceMapService,
     } = this.props;
 
     let frames = [];
     stacktrace.forEach((s, i) => {
       if (s.asyncCause) {
         frames.push("\t", AsyncFrame({
           key: `${i}-asyncframe`,
           asyncCause: s.asyncCause
@@ -62,17 +65,18 @@ const StackTrace = createClass({
           line: s.lineNumber,
           column: s.columnNumber,
         },
         showFunctionName: true,
         showAnonymousFunctionName: true,
         showFullSourceUrl: true,
         onClick: (/^Scratchpad\/\d+$/.test(source))
           ? onViewSourceInScratchpad
-          : onViewSourceInDebugger
+          : onViewSourceInDebugger,
+        sourceMapService,
       }), "\n");
     });
 
     return dom.div({ className: "stack-trace" }, frames);
   }
 });
 
 module.exports = StackTrace;
--- a/devtools/client/shared/components/test/mochitest/chrome.ini
+++ b/devtools/client/shared/components/test/mochitest/chrome.ini
@@ -6,16 +6,17 @@ support-files =
 [test_HSplitBox_01.html]
 [test_notification_box_01.html]
 [test_notification_box_02.html]
 [test_notification_box_03.html]
 [test_searchbox.html]
 [test_searchbox-with-autocomplete.html]
 [test_sidebar_toggle.html]
 [test_stack-trace.html]
+[test_stack-trace-source-maps.html]
 [test_tabs_accessibility.html]
 [test_tabs_menu.html]
 [test_tree_01.html]
 [test_tree_02.html]
 [test_tree_03.html]
 [test_tree_04.html]
 [test_tree_05.html]
 [test_tree_06.html]
new file mode 100644
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_stack-trace-source-maps.html
@@ -0,0 +1,105 @@
+<!-- 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/. -->
+<!DOCTYPE HTML>
+<html>
+<!--
+Test the rendering of a stack trace with source maps
+-->
+<head>
+  <meta charset="utf-8">
+  <title>StackTrace component test</title>
+  <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<script src="head.js"></script>
+<script>
+/* import-globals-from head.js */
+"use strict";
+
+window.onload = function () {
+  let ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
+  let React = browserRequire("devtools/client/shared/vendor/react");
+  let StackTrace = React.createFactory(
+    browserRequire("devtools/client/shared/components/stack-trace")
+  );
+  ok(StackTrace, "Got the StackTrace factory");
+
+  add_task(function* () {
+    let stacktrace = [
+      {
+        filename: "https://bugzilla.mozilla.org/bundle.js",
+        lineNumber: 99,
+        columnNumber: 10
+      },
+      {
+        functionName: "loadFunc",
+        filename: "https://bugzilla.mozilla.org/bundle.js",
+        lineNumber: 108,
+      }
+    ];
+
+    let props = {
+      stacktrace,
+      onViewSourceInDebugger: () => {},
+      onViewSourceInScratchpad: () => {},
+      // A mock source map service.
+      sourceMapService: {
+	originalPositionFor: function (url, line, column) {
+	  let newLine = line === 99 ? 1 : 7;
+	  // Return a phony promise-like thing that resolves
+	  // immediately.
+	  return {
+	    then: function (consequence) {
+	      consequence({
+		sourceId: "whatever",
+		sourceUrl: "https://bugzilla.mozilla.org/original.js",
+		line: newLine,
+		column,
+	      });
+	    },
+	  };
+	}
+      },
+    };
+
+    let trace = ReactDOM.render(StackTrace(props), window.document.body);
+    yield forceRender(trace);
+
+    let traceEl = ReactDOM.findDOMNode(trace);
+    ok(traceEl, "Rendered StackTrace has an element");
+
+    // Get the child nodes and filter out the text-only whitespace ones
+    let frameEls = Array.from(traceEl.childNodes)
+      .filter(n => n.className && n.className.includes("frame"));
+    ok(frameEls, "Rendered StackTrace has frames");
+    is(frameEls.length, 2, "StackTrace has 2 frames");
+
+    checkFrameString({
+      el: frameEls[0],
+      functionName: "<anonymous>",
+      source: "https://bugzilla.mozilla.org/original.js",
+      file: "original.js",
+      line: 1,
+      column: 10,
+      shouldLink: true,
+      tooltip: "View source in Debugger → https://bugzilla.mozilla.org/original.js:1:10",
+    });
+
+    checkFrameString({
+      el: frameEls[1],
+      functionName: "loadFunc",
+      source: "https://bugzilla.mozilla.org/original.js",
+      file: "original.js",
+      line: 7,
+      column: null,
+      shouldLink: true,
+      tooltip: "View source in Debugger → https://bugzilla.mozilla.org/original.js:7",
+    });
+  });
+};
+</script>
+</body>
+</html>
--- a/devtools/client/styleeditor/StyleSheetEditor.jsm
+++ b/devtools/client/styleeditor/StyleSheetEditor.jsm
@@ -16,17 +16,17 @@ const Editor = require("devtools/client/
 const promise = require("promise");
 const {shortSource, prettifyCSS} = require("devtools/shared/inspector/css-logic");
 const {console} = require("resource://gre/modules/Console.jsm");
 const Services = require("Services");
 const EventEmitter = require("devtools/shared/event-emitter");
 const {Task} = require("devtools/shared/task");
 const {FileUtils} = require("resource://gre/modules/FileUtils.jsm");
 const {NetUtil} = require("resource://gre/modules/NetUtil.jsm");
-const {TextDecoder, OS} = Cu.import("resource://gre/modules/osfile.jsm", {});
+const {OS} = Cu.import("resource://gre/modules/osfile.jsm", {});
 const {
   getString,
   showFilePicker,
 } = require("resource://devtools/client/styleeditor/StyleEditorUtil.jsm");
 
 const LOAD_ERROR = "error-load";
 const SAVE_ERROR = "error-save";
 
--- a/devtools/client/webconsole/console-output.js
+++ b/devtools/client/webconsole/console-output.js
@@ -14,22 +14,21 @@ loader.lazyImporter(this, "escapeHTML", 
 loader.lazyRequireGetter(this, "promise");
 loader.lazyRequireGetter(this, "gDevTools", "devtools/client/framework/devtools", true);
 loader.lazyRequireGetter(this, "TableWidget", "devtools/client/shared/widgets/TableWidget", true);
 loader.lazyRequireGetter(this, "ObjectClient", "devtools/shared/client/main", true);
 
 const { extend } = require("sdk/core/heritage");
 const XHTML_NS = "http://www.w3.org/1999/xhtml";
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
-const STRINGS_URI = "devtools/client/locales/webconsole.properties";
 
 const WebConsoleUtils = require("devtools/client/webconsole/utils").Utils;
 const { getSourceNames } = require("devtools/client/shared/source-utils");
 const {Task} = require("devtools/shared/task");
-const l10n = new WebConsoleUtils.L10n(STRINGS_URI);
+const l10n = require("devtools/client/webconsole/webconsole-l10n");
 const nodeConstants = require("devtools/shared/dom-node-constants");
 const {PluralForm} = require("devtools/shared/plural-form");
 
 const MAX_STRING_GRIP_LENGTH = 36;
 const {ELLIPSIS} = require("devtools/shared/l10n");
 
 const validProtocols = /^(http|https|ftp|data|javascript|resource|chrome):/i;
 
@@ -3551,19 +3550,22 @@ Widgets.Stacktrace.prototype = extend(Wi
     if (this.element) {
       return this;
     }
 
     let result = this.element = this.document.createElementNS(XHTML_NS, "div");
     result.className = "stacktrace devtools-monospace";
 
     if (this.stacktrace) {
+      const target = this.message.output.toolboxTarget;
+      const toolbox = gDevTools.getToolbox(target);
       this.output.owner.ReactDOM.render(this.output.owner.StackTraceView({
         stacktrace: this.stacktrace,
-        onViewSourceInDebugger: frame => this.output.openLocationInDebugger(frame)
+        onViewSourceInDebugger: frame => this.output.openLocationInDebugger(frame),
+        sourceMapService: toolbox ? toolbox.sourceMapURLService : null,
       }), result);
     }
 
     return this;
   }
 });
 
 /**
--- a/devtools/client/webconsole/hudservice.js
+++ b/devtools/client/webconsole/hudservice.js
@@ -17,18 +17,17 @@ var Services = require("Services");
 loader.lazyRequireGetter(this, "Telemetry", "devtools/client/shared/telemetry");
 loader.lazyRequireGetter(this, "WebConsoleFrame", "devtools/client/webconsole/webconsole", true);
 loader.lazyRequireGetter(this, "gDevTools", "devtools/client/framework/devtools", true);
 loader.lazyRequireGetter(this, "DebuggerServer", "devtools/server/main", true);
 loader.lazyRequireGetter(this, "DebuggerClient", "devtools/shared/client/main", true);
 loader.lazyRequireGetter(this, "showDoorhanger", "devtools/client/shared/doorhanger", true);
 loader.lazyRequireGetter(this, "viewSource", "devtools/client/shared/view-source");
 
-const STRINGS_URI = "devtools/client/locales/webconsole.properties";
-var l10n = new WebConsoleUtils.L10n(STRINGS_URI);
+const l10n = require("devtools/client/webconsole/webconsole-l10n");
 
 const BROWSER_CONSOLE_WINDOW_FEATURES = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
 
 // The preference prefix for all of the Browser Console filters.
 const BROWSER_CONSOLE_FILTER_PREFS_PREFIX = "devtools.browserconsole.filter.";
 
 var gHudId = 0;
 
--- a/devtools/client/webconsole/jsterm.js
+++ b/devtools/client/webconsole/jsterm.js
@@ -22,18 +22,17 @@ loader.lazyRequireGetter(this, "ToolSide
 loader.lazyRequireGetter(this, "Messages", "devtools/client/webconsole/console-output", true);
 loader.lazyRequireGetter(this, "asyncStorage", "devtools/shared/async-storage");
 loader.lazyRequireGetter(this, "EnvironmentClient", "devtools/shared/client/main", true);
 loader.lazyRequireGetter(this, "ObjectClient", "devtools/shared/client/main", true);
 loader.lazyImporter(this, "VariablesView", "resource://devtools/client/shared/widgets/VariablesView.jsm");
 loader.lazyImporter(this, "VariablesViewController", "resource://devtools/client/shared/widgets/VariablesViewController.jsm");
 loader.lazyRequireGetter(this, "gDevTools", "devtools/client/framework/devtools", true);
 
-const STRINGS_URI = "devtools/client/locales/webconsole.properties";
-var l10n = new WebConsoleUtils.L10n(STRINGS_URI);
+const l10n = require("devtools/client/webconsole/webconsole-l10n");
 
 // Constants used for defining the direction of JSTerm input history navigation.
 const HISTORY_BACK = -1;
 const HISTORY_FORWARD = 1;
 
 const XHTML_NS = "http://www.w3.org/1999/xhtml";
 
 const HELP_URL = "https://developer.mozilla.org/docs/Tools/Web_Console/Helpers";
--- a/devtools/client/webconsole/moz.build
+++ b/devtools/client/webconsole/moz.build
@@ -14,13 +14,14 @@ DIRS += [
 DevToolsModules(
     'console-commands.js',
     'console-output.js',
     'hudservice.js',
     'jsterm.js',
     'panel.js',
     'utils.js',
     'webconsole-connection-proxy.js',
+    'webconsole-l10n.js',
     'webconsole.js',
 )
 
-with Files('**'):
-    BUG_COMPONENT = ('Firefox', 'Developer Tools: Console')
+with Files('**'):
+    BUG_COMPONENT = ('Firefox', 'Developer Tools: Console')
--- a/devtools/client/webconsole/net/components/net-info-body.js
+++ b/devtools/client/webconsole/net/components/net-info-body.js
@@ -33,17 +33,19 @@ const PropTypes = React.PropTypes;
  */
 var NetInfoBody = React.createClass({
   propTypes: {
     tabActive: PropTypes.number.isRequired,
     actions: PropTypes.object.isRequired,
     data: PropTypes.shape({
       request: PropTypes.object.isRequired,
       response: PropTypes.object.isRequired
-    })
+    }),
+    // Service to enable the source map feature.
+    sourceMapService: PropTypes.object,
   },
 
   displayName: "NetInfoBody",
 
   getDefaultProps() {
     return {
       tabActive: 0
     };
@@ -71,17 +73,17 @@ var NetInfoBody = React.createClass({
   },
 
   hasStackTrace() {
     let {cause} = this.state.data;
     return cause && cause.stacktrace && cause.stacktrace.length > 0;
   },
 
   getTabPanels() {
-    let actions = this.props.actions;
+    let { actions, sourceMapService } = this.props;
     let data = this.state.data;
     let {request} = data;
 
     // Flags for optional tabs. Some tabs are visible only if there
     // are data to display.
     let hasParams = request.queryString && request.queryString.length;
     let hasPostData = request.bodySize > 0;
 
@@ -148,17 +150,18 @@ var NetInfoBody = React.createClass({
     if (this.hasStackTrace()) {
       panels.push(
         TabPanel({
           className: "stacktrace-tab",
           key: "stacktrace",
           title: Locale.$STR("netRequest.callstack")},
           StackTraceTab({
             data: data,
-            actions: actions
+            actions: actions,
+            sourceMapService: sourceMapService,
           })
         )
       );
     }
 
     return panels;
   },
 
--- a/devtools/client/webconsole/net/components/stacktrace-tab.js
+++ b/devtools/client/webconsole/net/components/stacktrace-tab.js
@@ -8,22 +8,24 @@ const StackTrace = createFactory(require
 
 const StackTraceTab = createClass({
   displayName: "StackTraceTab",
 
   propTypes: {
     data: PropTypes.object.isRequired,
     actions: PropTypes.shape({
       onViewSourceInDebugger: PropTypes.func.isRequired
-    })
+    }),
+    // Service to enable the source map feature.
+    sourceMapService: PropTypes.object,
   },
 
   render() {
     let { stacktrace } = this.props.data.cause;
-    let { actions } = this.props;
+    let { actions, sourceMapService } = this.props;
     let onViewSourceInDebugger = actions.onViewSourceInDebugger.bind(actions);
 
-    return StackTrace({ stacktrace, onViewSourceInDebugger });
+    return StackTrace({ stacktrace, onViewSourceInDebugger, sourceMapService });
   }
 });
 
 // Exports from this module
 module.exports = StackTraceTab;
--- a/devtools/client/webconsole/net/net-request.js
+++ b/devtools/client/webconsole/net/net-request.js
@@ -158,17 +158,18 @@ NetRequest.prototype = {
     let doc = messageBody.ownerDocument;
     this.netInfoBodyBox = doc.createElementNS(XHTML_NS, "div");
     this.netInfoBodyBox.classList.add("netInfoBody");
     messageBody.appendChild(this.netInfoBodyBox);
 
     // As soon as Redux is in place state and actions will come from
     // separate modules.
     let body = NetInfoBody({
-      actions: this
+      actions: this,
+      sourceMapService: this.owner.sourceMapURLService,
     });
 
     // Render net info body!
     this.body = ReactDOM.render(body, this.netInfoBodyBox);
 
     this.refresh();
   },
 
--- a/devtools/client/webconsole/new-console-output/components/console-output.js
+++ b/devtools/client/webconsole/new-console-output/components/console-output.js
@@ -25,16 +25,17 @@ const ConsoleOutput = createClass({
   displayName: "ConsoleOutput",
 
   propTypes: {
     messages: PropTypes.object.isRequired,
     messagesUi: PropTypes.object.isRequired,
     serviceContainer: PropTypes.shape({
       attachRefToHud: PropTypes.func.isRequired,
       openContextMenu: PropTypes.func.isRequired,
+      sourceMapService: PropTypes.object,
     }),
     autoscroll: PropTypes.bool.isRequired,
     dispatch: PropTypes.func.isRequired,
     timestampsVisible: PropTypes.bool,
     groups: PropTypes.object.isRequired,
     messagesTableData: PropTypes.object.isRequired,
   },
 
--- a/devtools/client/webconsole/new-console-output/components/filter-bar.js
+++ b/devtools/client/webconsole/new-console-output/components/filter-bar.js
@@ -8,17 +8,16 @@ const {
   DOM: dom,
   PropTypes
 } = require("devtools/client/shared/vendor/react");
 const { connect } = require("devtools/client/shared/vendor/react-redux");
 const { getAllFilters } = require("devtools/client/webconsole/new-console-output/selectors/filters");
 const { getAllUi } = require("devtools/client/webconsole/new-console-output/selectors/ui");
 const {
   filterTextSet,
-  filtersClear,
   filterBarToggle,
   messagesClear
 } = require("devtools/client/webconsole/new-console-output/actions/index");
 const { l10n } = require("devtools/client/webconsole/new-console-output/utils/messages");
 const {
   MESSAGE_LEVEL
 } = require("../constants");
 const FilterButton = require("devtools/client/webconsole/new-console-output/components/filter-button");
@@ -44,20 +43,16 @@ const FilterBar = createClass({
   onClickMessagesClear: function () {
     this.props.dispatch(messagesClear());
   },
 
   onClickFilterBarToggle: function () {
     this.props.dispatch(filterBarToggle());
   },
 
-  onClickFiltersClear: function () {
-    this.props.dispatch(filtersClear());
-  },
-
   onSearchInput: function (e) {
     this.props.dispatch(filterTextSet(e.target.value));
   },
 
   render() {
     const {dispatch, filter, filterBarVisible} = this.props;
     let children = [];
 
--- a/devtools/client/webconsole/new-console-output/components/message-types/console-command.js
+++ b/devtools/client/webconsole/new-console-output/components/message-types/console-command.js
@@ -15,44 +15,42 @@ const Message = createFactory(require("d
 
 ConsoleCommand.displayName = "ConsoleCommand";
 
 ConsoleCommand.propTypes = {
   message: PropTypes.object.isRequired,
   autoscroll: PropTypes.bool.isRequired,
   indent: PropTypes.number.isRequired,
   timestampsVisible: PropTypes.bool.isRequired,
+  serviceContainer: PropTypes.object,
 };
 
 ConsoleCommand.defaultProps = {
   indent: 0,
 };
 
 /**
  * Displays input from the console.
  */
 function ConsoleCommand(props) {
   const {
     autoscroll,
     indent,
     message,
     timestampsVisible,
+    serviceContainer,
   } = props;
 
   const {
     source,
     type,
     level,
     messageText: messageBody,
   } = message;
 
-  const {
-    serviceContainer,
-  } = props;
-
   return Message({
     source,
     type,
     level,
     topLevelClasses: [],
     messageBody,
     scrollToMessage: autoscroll,
     serviceContainer,
--- a/devtools/client/webconsole/new-console-output/components/message-types/evaluation-result.js
+++ b/devtools/client/webconsole/new-console-output/components/message-types/evaluation-result.js
@@ -15,16 +15,17 @@ const Message = createFactory(require("d
 const GripMessageBody = require("devtools/client/webconsole/new-console-output/components/grip-message-body");
 
 EvaluationResult.displayName = "EvaluationResult";
 
 EvaluationResult.propTypes = {
   message: PropTypes.object.isRequired,
   indent: PropTypes.number.isRequired,
   timestampsVisible: PropTypes.bool.isRequired,
+  serviceContainer: PropTypes.object,
 };
 
 EvaluationResult.defaultProps = {
   indent: 0,
 };
 
 function EvaluationResult(props) {
   const {
--- a/devtools/client/webconsole/new-console-output/components/message-types/page-error.js
+++ b/devtools/client/webconsole/new-console-output/components/message-types/page-error.js
@@ -15,16 +15,17 @@ const Message = createFactory(require("d
 
 PageError.displayName = "PageError";
 
 PageError.propTypes = {
   message: PropTypes.object.isRequired,
   open: PropTypes.bool,
   indent: PropTypes.number.isRequired,
   timestampsVisible: PropTypes.bool.isRequired,
+  serviceContainer: PropTypes.object,
 };
 
 PageError.defaultProps = {
   open: false,
   indent: 0,
 };
 
 function PageError(props) {
--- a/devtools/client/webconsole/new-console-output/components/message.js
+++ b/devtools/client/webconsole/new-console-output/components/message.js
@@ -143,16 +143,17 @@ const Message = createClass({
       attachment = dom.div(
         {
           className: "stacktrace devtools-monospace"
         },
         StackTrace({
           stacktrace: stacktrace,
           onViewSourceInDebugger: serviceContainer.onViewSourceInDebugger,
           onViewSourceInScratchpad: serviceContainer.onViewSourceInScratchpad,
+          sourceMapService: serviceContainer.sourceMapService,
         })
       );
     }
 
     // If there is an expandable part, make it collapsible.
     let collapse = null;
     if (collapsible) {
       collapse = CollapseButton({
--- a/devtools/client/webconsole/new-console-output/selectors/messages.js
+++ b/devtools/client/webconsole/new-console-output/selectors/messages.js
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 const { l10n } = require("devtools/client/webconsole/new-console-output/utils/messages");
 const { getAllFilters } = require("devtools/client/webconsole/new-console-output/selectors/filters");
 const { getLogLimit } = require("devtools/client/webconsole/new-console-output/selectors/prefs");
 const { getGripPreviewItems } = require("devtools/client/shared/components/reps/reps");
+const { getSourceNames } = require("devtools/client/shared/source-utils");
 const {
   MESSAGE_TYPE,
   MESSAGE_SOURCE
 } = require("devtools/client/webconsole/new-console-output/constants");
 
 function getAllMessages(state) {
   let messages = getAllMessagesById(state);
   let logLimit = getLogLimit(state);
@@ -126,18 +127,19 @@ function matchSearchFilters(message, fil
 
 /**
  * Returns true if given text is included in provided stack frame.
  */
 function isTextInFrame(text, frame) {
   if (!frame) {
     return false;
   }
-  return Object.values(frame)
-    .join(":")
+
+  const { short } = getSourceNames(frame.source);
+  return `${short}:${frame.line}:${frame.column}`
     .toLocaleLowerCase()
     .includes(text.toLocaleLowerCase());
 }
 
 /**
  * Returns true if given text is included in provided parameters.
  */
 function isTextInParameters(text, parameters) {
--- a/devtools/client/webconsole/new-console-output/test/components/console-api-call.test.js
+++ b/devtools/client/webconsole/new-console-output/test/components/console-api-call.test.js
@@ -94,18 +94,17 @@ describe("ConsoleAPICall component:", ()
 
     it("renders a timestamp when passed a truthy timestampsVisible prop", () => {
       const message = stubPreparedMessages.get("console.log('foobar', 'test')");
       const wrapper = render(ConsoleApiCall({
         message,
         serviceContainer,
         timestampsVisible: true,
       }));
-      const L10n = require("devtools/client/webconsole/new-console-output/test/fixtures/L10n");
-      const { timestampString } = new L10n();
+      const { timestampString } = require("devtools/client/webconsole/webconsole-l10n");
 
       expect(wrapper.find(".timestamp").text()).toBe(timestampString(message.timeStamp));
     });
 
     it("does not render a timestamp when not asked to", () => {
       const message = stubPreparedMessages.get("console.log('foobar', 'test')");
       const wrapper = render(ConsoleApiCall({
         message,
--- a/devtools/client/webconsole/new-console-output/test/components/evaluation-result.test.js
+++ b/devtools/client/webconsole/new-console-output/test/components/evaluation-result.test.js
@@ -92,18 +92,17 @@ describe("EvaluationResult component:", 
   });
 
   it("has a timestamp when passed a truthy timestampsVisible prop", () => {
     const message = stubPreparedMessages.get("new Date(0)");
     const wrapper = render(EvaluationResult({
       message,
       timestampsVisible: true,
     }));
-    const L10n = require("devtools/client/webconsole/new-console-output/test/fixtures/L10n");
-    const { timestampString } = new L10n();
+    const { timestampString } = require("devtools/client/webconsole/webconsole-l10n");
 
     expect(wrapper.find(".timestamp").text()).toBe(timestampString(message.timeStamp));
   });
 
   it("does not have a timestamp when timestampsVisible prop is falsy", () => {
     const message = stubPreparedMessages.get("new Date(0)");
     const wrapper = render(EvaluationResult({
       message,
--- a/devtools/client/webconsole/new-console-output/test/components/network-event-message.test.js
+++ b/devtools/client/webconsole/new-console-output/test/components/network-event-message.test.js
@@ -24,18 +24,17 @@ describe("NetworkEventMessage component:
   describe("GET request", () => {
     it("renders as expected", () => {
       const message = stubPreparedMessages.get("GET request eventTimings");
       const wrapper = render(NetworkEventMessage({
         message,
         serviceContainer,
         timestampsVisible: true,
       }));
-      const L10n = require("devtools/client/webconsole/new-console-output/test/fixtures/L10n");
-      const { timestampString } = new L10n();
+      const { timestampString } = require("devtools/client/webconsole/webconsole-l10n");
 
       expect(wrapper.find(".timestamp").text()).toBe(timestampString(message.timeStamp));
       expect(wrapper.find(".message-body .method").text()).toBe("GET");
       expect(wrapper.find(".message-body .xhr").length).toBe(0);
       expect(wrapper.find(".message-body .url").length).toBe(1);
       expect(wrapper.find(".message-body .url").text()).toBe(EXPECTED_URL);
       expect(wrapper.find(".message-body .status").length).toBe(1);
       expect(wrapper.find(".message-body .status").text()).toMatch(EXPECTED_STATUS);
--- a/devtools/client/webconsole/new-console-output/test/components/page-error.test.js
+++ b/devtools/client/webconsole/new-console-output/test/components/page-error.test.js
@@ -27,18 +27,17 @@ const serviceContainer = require("devtoo
 describe("PageError component:", () => {
   it("renders", () => {
     const message = stubPreparedMessages.get("ReferenceError: asdf is not defined");
     const wrapper = render(PageError({
       message,
       serviceContainer,
       timestampsVisible: true,
     }));
-    const L10n = require("devtools/client/webconsole/new-console-output/test/fixtures/L10n");
-    const { timestampString } = new L10n();
+    const { timestampString } = require("devtools/client/webconsole/webconsole-l10n");
 
     expect(wrapper.find(".timestamp").text()).toBe(timestampString(message.timeStamp));
 
     expect(wrapper.find(".message-body").text())
       .toBe("ReferenceError: asdf is not defined[Learn More]");
 
     // The stacktrace should be closed by default.
     const frameLinks = wrapper.find(`.stack-trace`);
--- a/devtools/client/webconsole/new-console-output/test/mochitest/head.js
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/head.js
@@ -9,19 +9,17 @@
 "use strict";
 
 // shared-head.js handles imports, constants, and utility functions
 // Load the shared-head file first.
 Services.scriptloader.loadSubScript(
   "chrome://mochitests/content/browser/devtools/client/framework/test/shared-head.js",
   this);
 
-var {Utils: WebConsoleUtils} = require("devtools/client/webconsole/utils");
-const WEBCONSOLE_STRINGS_URI = "devtools/client/locales/webconsole.properties";
-var WCUL10n = new WebConsoleUtils.L10n(WEBCONSOLE_STRINGS_URI);
+var WCUL10n = require("devtools/client/webconsole/webconsole-l10n");
 
 Services.prefs.setBoolPref("devtools.webconsole.new-frontend-enabled", true);
 registerCleanupFunction(function* () {
   Services.prefs.clearUserPref("devtools.webconsole.new-frontend-enabled");
 
   let browserConsole = HUDService.getBrowserConsole();
   if (browserConsole) {
     if (browserConsole.jsterm) {
--- a/devtools/client/webconsole/new-console-output/test/require-helper.js
+++ b/devtools/client/webconsole/new-console-output/test/require-helper.js
@@ -22,18 +22,16 @@ requireHacker.global_hook("default", pat
     // For Rep's use of AMD
     case "devtools/client/shared/vendor/react.default":
       return `const React = require('devtools/client/shared/vendor/react-dev'); module.exports = React`;
   }
 
   // Some modules depend on Chrome APIs which don't work in mocha. When such a module
   // is required, replace it with a mock version.
   switch (path) {
-    case "devtools/client/webconsole/utils":
-      return `module.exports = require("devtools/client/webconsole/new-console-output/test/fixtures/WebConsoleUtils")`;
     case "devtools/shared/l10n":
       return `module.exports = require("devtools/client/webconsole/new-console-output/test/fixtures/LocalizationHelper")`;
     case "devtools/shared/plural-form":
       return `module.exports = require("devtools/client/webconsole/new-console-output/test/fixtures/PluralForm")`;
     case "Services":
     case "Services.default":
       return `module.exports = require("devtools/client/webconsole/new-console-output/test/fixtures/Services")`;
     case "devtools/shared/client/main":
--- a/devtools/client/webconsole/new-console-output/test/store/search.test.js
+++ b/devtools/client/webconsole/new-console-output/test/store/search.test.js
@@ -61,16 +61,28 @@ describe("Searching in grips", () => {
 
   describe("Search in logs with net messages", () => {
     it("matches on network messages", () => {
       store.dispatch(actions.filterToggle("net"));
       store.dispatch(actions.filterTextSet("get"));
       expect(getAllMessages(store.getState()).size).toEqual(1);
     });
   });
+
+  describe("Search in frame", () => {
+    it("matches on file name", () => {
+      store.dispatch(actions.filterTextSet("test-console-api.html:1:27"));
+      expect(getAllMessages(store.getState()).size).toEqual(7);
+    });
+
+    it("do not match on full url", () => {
+      store.dispatch(actions.filterTextSet("http://example.com/browser/devtools"));
+      expect(getAllMessages(store.getState()).size).toEqual(0);
+    });
+  });
 });
 
 function prepareBaseStore() {
   const store = setupStore([
     "console.log('foobar', 'test')",
     "console.warn('danger, will robinson!')",
     "console.table(['red', 'green', 'blue']);",
     "console.count('bar')",
--- a/devtools/client/webconsole/new-console-output/utils/messages.js
+++ b/devtools/client/webconsole/new-console-output/utils/messages.js
@@ -1,19 +1,17 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-const WebConsoleUtils = require("devtools/client/webconsole/utils").Utils;
-const STRINGS_URI = "devtools/client/locales/webconsole.properties";
-const l10n = new WebConsoleUtils.L10n(STRINGS_URI);
+const l10n = require("devtools/client/webconsole/webconsole-l10n");
 
 const {
   MESSAGE_SOURCE,
   MESSAGE_TYPE,
   MESSAGE_LEVEL,
 } = require("../constants");
 const {
   ConsoleMessage,
--- a/devtools/client/webconsole/test/head.js
+++ b/devtools/client/webconsole/test/head.js
@@ -32,18 +32,17 @@ const CATEGORY_SERVER = 7;
 const SEVERITY_ERROR = 0;
 const SEVERITY_WARNING = 1;
 const SEVERITY_INFO = 2;
 const SEVERITY_LOG = 3;
 
 // The indent of a console group in pixels.
 const GROUP_INDENT = 12;
 
-const WEBCONS