Browse Source

Re-sync to 67a5396d0abd77c66beeccc24dc38fe8f20082ab

nsITobin 2 months ago
parent
commit
27da11aedd

+ 0 - 332
comm-central/patches/TOP-CONTRIB-about-redirector-jscomp2esmodule.patch

@@ -1,332 +0,0 @@
-# HG changeset patch
-# User Matt A. Tobin <email@mattatobin.com>
-# Date 1659988365 0
-9999999 - Update suite AboutRedirector and change about: to about:version
-
-diff --git a/suite/base/content/utilityOverlay.js b/suite/base/content/utilityOverlay.js
---- a/suite/base/content/utilityOverlay.js
-+++ b/suite/base/content/utilityOverlay.js
-@@ -593,17 +593,17 @@ function isRestricted( url )
-   } catch (e) {
-     return false;
-   }
- }
- 
- function goAbout(aProtocol)
- {
-   var target;
--  var url = "about:" + (aProtocol || "");
-+  var url = "about:version" + (aProtocol || "");
-   var defaultAboutState = Services.prefs.getIntPref("browser.link.open_external");
- 
-   switch (defaultAboutState) {
-   case Ci.nsIBrowserDOMWindow.OPEN_NEWWINDOW:
-     target = "window";
-     break;
-   case Ci.nsIBrowserDOMWindow.OPEN_CURRENTWINDOW:
-     target = "current";
-diff --git a/suite/components/AboutRedirector.sys.mjs b/suite/components/AboutRedirector.sys.mjs
-new file mode 100644
---- /dev/null
-+++ b/suite/components/AboutRedirector.sys.mjs
-@@ -0,0 +1,121 @@
-+/* 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/. */
-+
-+export function AboutRedirector() {}
-+
-+AboutRedirector.prototype = {
-+  QueryInterface: ChromeUtils.generateQI(["nsIAboutModule"]),
-+
-+  // Each entry in the map has the key as the part after the "about:" and the
-+  // value as a record with url and flags entries. Note that each addition here
-+  // should be coupled with a corresponding addition in components.conf.
-+  _redirMap: {
-+    version: {
-+      url: "chrome://communicator/content/about.xhtml",
-+      flags:
-+        Ci.nsIAboutModule.ALLOW_SCRIPT,
-+    },
-+    blocked: {
-+      url: "chrome://communicator/content/blockedSite.xhtml",
-+      flags:
-+        Ci.nsIAboutModule.ALLOW_SCRIPT |
-+        Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT,
-+    },
-+    data: {
-+      url: "chrome://communicator/content/dataman/dataman.xhtml",
-+      flags:
-+        Ci.nsIAboutModule.ALLOW_SCRIPT,
-+    },
-+    feeds: {
-+      url: "chrome://communicator/content/feeds/subscribe.xhtml",
-+      flags:
-+        Ci.nsIAboutModule.ALLOW_SCRIPT |
-+        Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT,
-+    },
-+    life: {
-+      url: "chrome://communicator/content/aboutLife.xhtml",
-+      flags:
-+        Ci.nsIAboutModule.ALLOW_SCRIPT |
-+        Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT,
-+    },
-+    newserror: {
-+      url: "chrome://messenger/content/newsError.xhtml",
-+      flags:
-+        Ci.nsIAboutModule.ALLOW_SCRIPT,
-+    },
-+    privatebrowsing: {
-+      url: "chrome://communicator/content/aboutPrivateBrowsing.xhtml",
-+      flags:
-+        Ci.nsIAboutModule.ALLOW_SCRIPT,
-+    },
-+    rights: {
-+      url: "chrome://branding/content/aboutRights.xhtml",
-+      flags:
-+        Ci.nsIAboutModule.ALLOW_SCRIPT |
-+        Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT,
-+    },
-+    sessionrestore: {
-+      url: "chrome://communicator/content/aboutSessionRestore.xhtml",
-+      flags:
-+        Ci.nsIAboutModule.ALLOW_SCRIPT,
-+    },
-+    profiling: {
-+      url: "chrome://devtools/content/performance-new/aboutprofiling/index.xhtml",
-+      flags:
-+        Ci.nsIAboutModule.ALLOW_SCRIPT | Ci.nsIAboutModule.IS_SECURE_CHROME_UI,
-+    },
-+  },
-+
-+ /**
-+   * Gets the module name from the given URI.
-+   */
-+  _getModuleName(aURI) {
-+    // Strip out the first ? or #, and anything following it
-+    const name = /[^?#]+/.exec(aURI.pathQueryRef)[0];
-+    return name.toLowerCase();
-+  },
-+
-+  getURIFlags(aURI) {
-+    const name = this._getModuleName(aURI);
-+    if (!(name in this._redirMap)) {
-+      throw Components.Exception(`no about:${name}`, Cr.NS_ERROR_ILLEGAL_VALUE);
-+    }
-+    return this._redirMap[name].flags;
-+  },
-+
-+  newChannel(aURI, aLoadInfo) {
-+    const name = this._getModuleName(aURI);
-+    if (!(name in this._redirMap)) {
-+      throw Components.Exception(`no about:${name}`, Cr.NS_ERROR_ILLEGAL_VALUE);
-+    }
-+
-+    const newURI = Services.io.newURI(this._redirMap[name].url);
-+    const channel = Services.io.newChannelFromURIWithLoadInfo(
-+      newURI,
-+      aLoadInfo
-+    );
-+    channel.originalURI = aURI;
-+
-+    if (
-+      this._redirMap[name].flags &
-+      Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT
-+    ) {
-+      const principal = Services.scriptSecurityManager.createContentPrincipal(
-+        aURI,
-+        {}
-+      );
-+      channel.owner = principal;
-+    }
-+
-+    return channel;
-+  },
-+
-+  getChromeURI(aURI) {
-+    const name = this._getModuleName(aURI);
-+    if (!(name in this._redirMap)) {
-+      throw Components.Exception(`no about:${name}`, Cr.NS_ERROR_ILLEGAL_VALUE);
-+    }
-+    return Services.io.newURI(this._redirMap[name].url);
-+  },
-+};
-diff --git a/suite/components/SuiteComponents.manifest b/suite/components/SuiteComponents.manifest
---- a/suite/components/SuiteComponents.manifest
-+++ b/suite/components/SuiteComponents.manifest
-@@ -1,18 +1,7 @@
--component {d54f2c89-8fd6-4eeb-a7a4-51d4dcdf460f} nsAbout.js
--contract @mozilla.org/network/protocol/about;1?what= {d54f2c89-8fd6-4eeb-a7a4-51d4dcdf460f}
--contract @mozilla.org/network/protocol/about;1?what=blocked {d54f2c89-8fd6-4eeb-a7a4-51d4dcdf460f}
--contract @mozilla.org/network/protocol/about;1?what=certerror {d54f2c89-8fd6-4eeb-a7a4-51d4dcdf460f}
--contract @mozilla.org/network/protocol/about;1?what=data {d54f2c89-8fd6-4eeb-a7a4-51d4dcdf460f}
--contract @mozilla.org/network/protocol/about;1?what=feeds {d54f2c89-8fd6-4eeb-a7a4-51d4dcdf460f}
--contract @mozilla.org/network/protocol/about;1?what=life {d54f2c89-8fd6-4eeb-a7a4-51d4dcdf460f}
--contract @mozilla.org/network/protocol/about;1?what=newserror {d54f2c89-8fd6-4eeb-a7a4-51d4dcdf460f}
--contract @mozilla.org/network/protocol/about;1?what=privatebrowsing {d54f2c89-8fd6-4eeb-a7a4-51d4dcdf460f}
--contract @mozilla.org/network/protocol/about;1?what=rights {d54f2c89-8fd6-4eeb-a7a4-51d4dcdf460f}
--contract @mozilla.org/network/protocol/about;1?what=sessionrestore {d54f2c89-8fd6-4eeb-a7a4-51d4dcdf460f}
- component {22042bdb-56e4-47c6-8b12-fdfa859c05a9} nsGopherProtocolStubHandler.js
- contract @mozilla.org/network/protocol;1?name=gopher {22042bdb-56e4-47c6-8b12-fdfa859c05a9}
- component {bbbbe845-5a1b-40ee-813c-f84b8faaa07c} nsSuiteGlue.js
- contract @mozilla.org/suite/suiteglue;1 {bbbbe845-5a1b-40ee-813c-f84b8faaa07c}
- category app-startup nsSuiteGlue service,@mozilla.org/suite/suiteglue;1
- component {9d4c845d-3f09-402a-b66d-50f291d7d50f} nsSuiteGlue.js
- contract @mozilla.org/content-permission/prompt;1 {9d4c845d-3f09-402a-b66d-50f291d7d50f}
-diff --git a/suite/components/components.conf b/suite/components/components.conf
-new file mode 100644
---- /dev/null
-+++ b/suite/components/components.conf
-@@ -0,0 +1,25 @@
-+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-+# vim: set filetype=python:
-+# This Source Code Form is subject to the terms of the Mozilla Public
-+# License, v. 2.0. If a copy of the MPL was not distributed with this
-+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-+
-+Classes = [
-+  {
-+    'cid': '{d54f2c89-8fd6-4eeb-a7a4-51d4dcdf460f}',
-+    'contract_ids': [
-+      '@mozilla.org/network/protocol/about;1?what=version',
-+      '@mozilla.org/network/protocol/about;1?what=blocked',
-+      '@mozilla.org/network/protocol/about;1?what=certerror',
-+      '@mozilla.org/network/protocol/about;1?what=data',
-+      '@mozilla.org/network/protocol/about;1?what=feeds',
-+      '@mozilla.org/network/protocol/about;1?what=life',
-+      '@mozilla.org/network/protocol/about;1?what=newserror',
-+      '@mozilla.org/network/protocol/about;1?what=privatebrowsing',
-+      '@mozilla.org/network/protocol/about;1?what=rights',
-+      '@mozilla.org/network/protocol/about;1?what=sessionrestore',
-+    ],
-+    'esModule': 'resource://gre/modules/AboutRedirector.sys.mjs',
-+    'constructor': 'AboutRedirector',
-+  },
-+]
-diff --git a/suite/components/moz.build b/suite/components/moz.build
---- a/suite/components/moz.build
-+++ b/suite/components/moz.build
-@@ -41,13 +41,20 @@ MOCHITEST_CHROME_MANIFESTS += [
- 
- XPIDL_SOURCES += [
-     "nsISuiteGlue.idl",
- ]
- 
- XPIDL_MODULE = "suite-components"
- 
- EXTRA_COMPONENTS += [
--    "nsAbout.js",
-     "nsGopherProtocolStubHandler.js",
-     "nsSuiteGlue.js",
-     "SuiteComponents.manifest",
- ]
-+
-+EXTRA_JS_MODULES += [
-+    "AboutRedirector.sys.mjs",
-+]
-+
-+XPCOM_MANIFESTS += [
-+    'components.conf',
-+]
-\ No newline at end of file
-diff --git a/suite/components/nsAbout.js b/suite/components/nsAbout.js
-deleted file mode 100644
---- a/suite/components/nsAbout.js
-+++ /dev/null
-@@ -1,75 +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/. */
--
--var {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
--
--const SCRIPT = Ci.nsIAboutModule.ALLOW_SCRIPT;
--const UNTRUSTED = Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT;
--const HIDE = Ci.nsIAboutModule.HIDE_FROM_ABOUTABOUT;
--const INDEXEDDB = Ci.nsIAboutModule.ENABLE_INDEXED_DB;
--
--function About() { }
--About.prototype = {
--  Flags: SCRIPT,
--  URI: "chrome://communicator/content/about.xhtml",
--  blockedFlags: SCRIPT | UNTRUSTED | HIDE,
--  blockedURI: "chrome://communicator/content/blockedSite.xhtml",
--  certerrorFlags: SCRIPT | UNTRUSTED | HIDE,
--  certerrorURI: "chrome://communicator/content/certError.xhtml",
--  dataFlags: SCRIPT,
--  dataURI: "chrome://communicator/content/dataman/dataman.xhtml",
--  feedsFlags: SCRIPT | UNTRUSTED | HIDE,
--  feedsURI: "chrome://communicator/content/feeds/subscribe.xhtml",
--  lifeFlags: SCRIPT | UNTRUSTED | HIDE,
--  lifeURI: "chrome://communicator/content/aboutLife.xhtml",
--  newserrorFlags: SCRIPT | HIDE,
--  newserrorURI: "chrome://messenger/content/newsError.xhtml",
--  privatebrowsingFlags: SCRIPT,
--  privatebrowsingURI: "chrome://communicator/content/aboutPrivateBrowsing.xhtml",
--  rightsFlags: SCRIPT | UNTRUSTED,
--  rightsURI: "chrome://branding/content/aboutRights.xhtml",
--  sessionrestoreFlags: SCRIPT | HIDE,
--  sessionrestoreURI: "chrome://communicator/content/aboutSessionRestore.xhtml",
--  // synctabsFlags: SCRIPT,
--  // synctabsURI: "chrome://communicator/content/aboutSyncTabs.xhtml",
--
--  classID: Components.ID("{d54f2c89-8fd6-4eeb-a7a4-51d4dcdf460f}"),
--  QueryInterface: ChromeUtils.generateQI([Ci.nsIAboutModule]),
--
--  getModule: function(aURI) {
--    return aURI.pathQueryRef.replace(/-|\W.*$/g, "").toLowerCase();
--  },
--
--  getURIFlags: function(aURI) {
--    return this[this.getModule(aURI) + "Flags"];
--  },
--
--  newChannel: function(aURI, aLoadInfo) {
--    let module = this.getModule(aURI);
--    let newURI = Services.io.newURI(this[module + "URI"]);
--
--    // We want a happy family which is always providing a loadInfo object.
--    if (!aLoadInfo) {
--      // Write out an error so that we have a stack and can fix the caller.
--      Cu.reportError('aLoadInfo was not provided in nsAbout.newChannel!');
--    }
--
--    let channel = aLoadInfo ?
--                  Services.io.newChannelFromURIWithLoadInfo(newURI, aLoadInfo) :
--                  Services.io.newChannelFromURI(newURI, null,
--                                                Services.scriptSecurityManager.getSystemPrincipal(),
--                                                null,
--                                                Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
--                                                Ci.nsIContentPolicy.TYPE_OTHER);
--
--    channel.originalURI = aURI;
--    if (this[module + "Flags"] & UNTRUSTED) {
--      let principal = Services.scriptSecurityManager.createCodebasePrincipal(aURI, {});
--      channel.owner = principal;
--    }
--    return channel;
--  },
--};
--
--var NSGetFactory = XPCOMUtils.generateNSGetFactory([About]);
-diff --git a/suite/installer/package-manifest.in b/suite/installer/package-manifest.in
---- a/suite/installer/package-manifest.in
-+++ b/suite/installer/package-manifest.in
-@@ -157,17 +157,16 @@
- @RESPATH@/components/SuiteFeeds.manifest
- @RESPATH@/components/SuiteSidebar.manifest
- ; JavaScript components
- @RESPATH@/components/cryptoComponents.manifest
- @RESPATH@/components/FeedConverter.js
- @RESPATH@/components/FeedWriter.js
- @RESPATH@/components/jsconsole-clhandler.js
- @RESPATH@/components/jsconsole-clhandler.manifest
--@RESPATH@/components/nsAbout.js
- @RESPATH@/components/nsBrowserContentHandler.js
- @RESPATH@/components/nsComposerCmdLineHandler.js
- @RESPATH@/components/nsComposerCmdLineHandler.manifest
- @RESPATH@/components/nsGopherProtocolStubHandler.js
- @RESPATH@/components/nsPlacesAutoComplete.js
- @RESPATH@/components/nsPlacesAutoComplete.manifest
- @RESPATH@/components/nsSessionStartup.js
- @RESPATH@/components/nsSessionStartup.manifest

+ 0 - 44
comm-central/patches/TOP-CONTRIB-add-brand-ftl.patch

@@ -1,44 +0,0 @@
-# HG changeset patch
-# User Matt A. Tobin <email@mattatobin.com>
-# Date 1659988365 0
-9999999 - Add brand.ftl to suite branding
-
-diff --git a/suite/branding/seamonkey/locales/en-US/brand.ftl b/suite/branding/seamonkey/locales/en-US/brand.ftl
-new file mode 100644
---- /dev/null
-+++ b/suite/branding/seamonkey/locales/en-US/brand.ftl
-@@ -0,0 +1,21 @@
-+# 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/.
-+
-+## SeaMonkey Brand
-+##
-+## SeaMonkey must be treated as a brand, and kept in English.
-+## It cannot be:
-+## - Transliterated.
-+## - Translated.
-+##
-+## Reference: https://www.mozilla.org/styleguide/communications/translation/
-+
-+-brand-shorter-name = SeaMonkey
-+-brand-short-name = SeaMonkey
-+-brand-full-name = SeaMonkey
-+# This brand name can be used in messages where the product name needs to
-+# remain unchanged across different versions (Daily, Beta, etc.).
-+-brand-product-name = SeaMonkey
-+-vendor-short-name = SeaMonkey e.V.
-+trademarkInfo = { " " }
-diff --git a/suite/branding/seamonkey/locales/jar.mn b/suite/branding/seamonkey/locales/jar.mn
---- a/suite/branding/seamonkey/locales/jar.mn
-+++ b/suite/branding/seamonkey/locales/jar.mn
-@@ -1,6 +1,9 @@
- #filter substitution
- 
-+[localization] @AB_CD@.jar:
-+  branding                                 (en-US/**/*.ftl)
-+
- @AB_CD@.jar:
- % locale branding @AB_CD@ %locale/@AB_CD@/branding/
-   locale/@AB_CD@/branding/brand.dtd        (%brand.dtd)
-   locale/@AB_CD@/branding/brand.properties (%brand.properties)

+ 0 - 670
comm-central/patches/TOP-CONTRIB-devtools-with-chrome-clh.patch

@@ -1,670 +0,0 @@
-# HG changeset patch
-# User Matt A. Tobin <email@mattatobin.com>
-# Date 1659988365 0
-9999999 - Port a slightly modified version of devtools-loader to suite.
-Also, includes the --chrome flag normally handled by nsBrowserContentHandler.
-
-diff --git a/suite/browser/nsBrowserContentHandler.js b/suite/browser/nsBrowserContentHandler.js
---- a/suite/browser/nsBrowserContentHandler.js
-+++ b/suite/browser/nsBrowserContentHandler.js
-@@ -389,28 +389,31 @@ var nsBrowserContentHandler = {
-                                  nsIBrowserDOMWindow.OPEN_NEWTAB,
-                                  features,
-                                  Services.scriptSecurityManager.getSystemPrincipal());
-         cmdLine.preventDefault = true;
-       }
-     } catch (e) {
-     }
- 
-+    /* XXXTobin: This code is currently relocated into the devtools-loader clh
-+       until this component is converted to an ESModule.
-     try {
-       var chromeParam = cmdLine.handleFlagWithParam("chrome", false);
-       if (chromeParam) {
-         // only load URIs which do not inherit chrome privs
-         var uri = resolveURIInternal(cmdLine, chromeParam);
-         if (!Services.netUtils.URIChainHasFlags(uri, URI_INHERITS_SECURITY_CONTEXT)) {
-           openWindow(null, uri.spec, features);
-           cmdLine.preventDefault = true;
-         }
-       }
-     } catch (e) {
-     }
-+    */
- 
-     try {
-       var fileParam = cmdLine.handleFlagWithParam("file", false);
-       if (fileParam) {
-         fileParam = resolveURIInternal(cmdLine, fileParam);
-         handURIToExistingBrowser(fileParam,
-                                  nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW,
-                                  features,
-diff --git a/suite/components/devtools/all-devtools.js b/suite/components/devtools/all-devtools.js
-new file mode 100644
---- /dev/null
-+++ b/suite/components/devtools/all-devtools.js
-@@ -0,0 +1,368 @@
-+// Developer Tools related preferences
-+pref("devtools.chrome.enabled", true);
-+pref("devtools.debugger.remote-enabled", true);
-+pref("devtools.selfxss.count", 5);
-+// Enable extensionStorage storage actor by default
-+pref("devtools.storage.extensionStorage.enabled", true);
-+
-+// Toolbox preferences
-+pref("devtools.toolbox.footer.height", 250);
-+pref("devtools.toolbox.sidebar.width", 500);
-+pref("devtools.toolbox.host", "bottom");
-+pref("devtools.toolbox.previousHost", "right");
-+pref("devtools.toolbox.selectedTool", "inspector");
-+pref("devtools.toolbox.sideEnabled", true);
-+pref("devtools.toolbox.zoomValue", "1");
-+pref("devtools.toolbox.splitconsoleEnabled", false);
-+pref("devtools.toolbox.splitconsoleHeight", 100);
-+pref("devtools.toolbox.tabsOrder", "");
-+pref("devtools.netmonitor.features.newEditAndResend", false);
-+
-+// The fission pref for enabling the "Multiprocess Browser Toolbox", which will
-+// make it possible to debug anything in Firefox (See Bug 1570639 for more
-+// information).
-+pref("devtools.browsertoolbox.fission", true);
-+
-+// When the Multiprocess Browser Toolbox is enabled, you can configure the scope of it:
-+// - "everything" will enable debugging absolutely everything in the browser
-+//   All processes, all documents, all workers, all add-ons.
-+// - "parent-process" will restrict debugging to the parent process
-+//   All privileged javascript, documents and workers running in the parent process.
-+pref("devtools.browsertoolbox.scope", "everything");
-+
-+// Toolbox Button preferences
-+pref("devtools.command-button-pick.enabled", true);
-+pref("devtools.command-button-frames.enabled", true);
-+pref("devtools.command-button-splitconsole.enabled", true);
-+pref("devtools.command-button-responsive.enabled", true);
-+pref("devtools.command-button-screenshot.enabled", false);
-+pref("devtools.command-button-rulers.enabled", false);
-+pref("devtools.command-button-measure.enabled", false);
-+pref("devtools.command-button-noautohide.enabled", false);
-+pref("devtools.command-button-errorcount.enabled", true);
-+  pref("devtools.command-button-experimental-prefs.enabled", true);
-+
-+// Inspector preferences
-+// Enable the Inspector
-+pref("devtools.inspector.enabled", true);
-+// What was the last active sidebar in the inspector
-+pref("devtools.inspector.selectedSidebar", "layoutview");
-+pref("devtools.inspector.activeSidebar", "layoutview");
-+pref("devtools.inspector.remote", false);
-+
-+// Enable the 3 pane mode in the inspector
-+pref("devtools.inspector.three-pane-enabled", true);
-+// Enable the 3 pane mode in the chrome inspector
-+pref("devtools.inspector.chrome.three-pane-enabled", false);
-+// Collapse pseudo-elements by default in the rule-view
-+pref("devtools.inspector.show_pseudo_elements", false);
-+// The default size for image preview tooltips in the rule-view/computed-view/markup-view
-+pref("devtools.inspector.imagePreviewTooltipSize", 300);
-+// Enable user agent style inspection in rule-view
-+pref("devtools.inspector.showUserAgentStyles", false);
-+// Show native anonymous content and user agent shadow roots
-+pref("devtools.inspector.showAllAnonymousContent", false);
-+// Enable the inline CSS compatibility warning in inspector rule view
-+pref("devtools.inspector.ruleview.inline-compatibility-warning.enabled", false);
-+// Enable the compatibility tool in the inspector.
-+pref("devtools.inspector.compatibility.enabled", true);
-+// Enable color scheme simulation in the inspector.
-+pref("devtools.inspector.color-scheme-simulation.enabled", true);
-+
-+// Grid highlighter preferences
-+pref("devtools.gridinspector.gridOutlineMaxColumns", 50);
-+pref("devtools.gridinspector.gridOutlineMaxRows", 50);
-+pref("devtools.gridinspector.showGridAreas", false);
-+pref("devtools.gridinspector.showGridLineNumbers", false);
-+pref("devtools.gridinspector.showInfiniteLines", false);
-+// Max number of grid highlighters that can be displayed
-+pref("devtools.gridinspector.maxHighlighters", 3);
-+
-+// Whether or not simplified highlighters should be used when
-+// prefers-reduced-motion is enabled.
-+pref("devtools.inspector.simple-highlighters-reduced-motion", false);
-+
-+// Whether or not the box model panel is opened in the layout view
-+pref("devtools.layout.boxmodel.opened", true);
-+// Whether or not the flexbox panel is opened in the layout view
-+pref("devtools.layout.flexbox.opened", true);
-+// Whether or not the flexbox container panel is opened in the layout view
-+pref("devtools.layout.flex-container.opened", true);
-+// Whether or not the flexbox item panel is opened in the layout view
-+pref("devtools.layout.flex-item.opened", true);
-+// Whether or not the grid inspector panel is opened in the layout view
-+pref("devtools.layout.grid.opened", true);
-+
-+// Enable hovering Box Model values and jumping to their source CSS rule in the
-+// rule-view.
-+#if defined(NIGHTLY_BUILD)
-+  pref("devtools.layout.boxmodel.highlightProperty", true);
-+#else
-+  pref("devtools.layout.boxmodel.highlightProperty", false);
-+#endif
-+
-+// By how many times eyedropper will magnify pixels
-+pref("devtools.eyedropper.zoom", 6);
-+
-+// Enable to collapse attributes that are too long.
-+pref("devtools.markup.collapseAttributes", true);
-+// Length to collapse attributes
-+pref("devtools.markup.collapseAttributeLength", 120);
-+// Whether to auto-beautify the HTML on copy.
-+pref("devtools.markup.beautifyOnCopy", false);
-+// Whether or not the DOM mutation breakpoints context menu are enabled in the
-+// markup view.
-+pref("devtools.markup.mutationBreakpoints.enabled", true);
-+
-+// DevTools default color unit
-+pref("devtools.defaultColorUnit", "authored");
-+
-+// Enable the Memory tools
-+pref("devtools.memory.enabled", true);
-+
-+pref("devtools.memory.custom-census-displays", "{}");
-+pref("devtools.memory.custom-label-displays", "{}");
-+pref("devtools.memory.custom-tree-map-displays", "{}");
-+
-+pref("devtools.memory.max-individuals", 1000);
-+pref("devtools.memory.max-retaining-paths", 10);
-+
-+// Enable the Performance tools
-+pref("devtools.performance.enabled", true);
-+// But not the pop-up.
-+pref("devtools.performance.popup.feature-flag", false);
-+// Override the default preset, which is "web-developer" on beta and release.
-+pref("devtools.performance.recording.preset", "firefox-platform");
-+pref("devtools.performance.recording.preset.remote", "firefox-platform");
-+
-+// The default cache UI setting
-+pref("devtools.cache.disabled", false);
-+
-+// The default service workers UI setting
-+pref("devtools.serviceWorkers.testing.enabled", false);
-+
-+// Enable the Network Monitor
-+pref("devtools.netmonitor.enabled", true);
-+
-+pref("devtools.netmonitor.features.search", true);
-+pref("devtools.netmonitor.features.requestBlocking", true);
-+
-+// Enable the Application panel
-+pref("devtools.application.enabled", false);
-+
-+// Enable the custom formatters feature
-+// This preference represents the user's choice to enable the custom formatters feature.
-+// While the preference above will be removed once the feature is stable, this one is menat to stay.
-+pref("devtools.custom-formatters.enabled", false);
-+
-+// The default Network Monitor UI settings
-+pref("devtools.netmonitor.panes-network-details-width", 550);
-+pref("devtools.netmonitor.panes-network-details-height", 450);
-+pref("devtools.netmonitor.panes-search-width", 550);
-+pref("devtools.netmonitor.panes-search-height", 450);
-+pref("devtools.netmonitor.filters", "[\"all\"]");
-+pref("devtools.netmonitor.visibleColumns",
-+  "[\"status\",\"method\",\"domain\",\"file\",\"initiator\",\"type\",\"transferred\",\"contentSize\",\"waterfall\"]"
-+);
-+pref("devtools.netmonitor.columnsData",
-+  '[{"name":"status","minWidth":30,"width":5}, {"name":"method","minWidth":30,"width":5}, {"name":"domain","minWidth":30,"width":10}, {"name":"file","minWidth":30,"width":25}, {"name":"url","minWidth":30,"width":25},{"name":"initiator","minWidth":30,"width":10},{"name":"type","minWidth":30,"width":5},{"name":"transferred","minWidth":30,"width":10},{"name":"contentSize","minWidth":30,"width":5},{"name":"waterfall","minWidth":150,"width":15}]');
-+pref("devtools.netmonitor.msg.payload-preview-height", 128);
-+pref("devtools.netmonitor.msg.visibleColumns",
-+  '["data", "time"]'
-+);
-+pref("devtools.netmonitor.msg.displayed-messages.limit", 500);
-+
-+pref("devtools.netmonitor.response.ui.limit", 10240);
-+
-+// Save request/response bodies yes/no.
-+pref("devtools.netmonitor.saveRequestAndResponseBodies", true);
-+
-+// The default Network monitor HAR export setting
-+pref("devtools.netmonitor.har.defaultLogDir", "");
-+pref("devtools.netmonitor.har.defaultFileName", "%hostname_Archive [%date]");
-+pref("devtools.netmonitor.har.jsonp", false);
-+pref("devtools.netmonitor.har.jsonpCallback", "");
-+pref("devtools.netmonitor.har.includeResponseBodies", true);
-+pref("devtools.netmonitor.har.compress", false);
-+pref("devtools.netmonitor.har.forceExport", false);
-+pref("devtools.netmonitor.har.pageLoadedTimeout", 1500);
-+pref("devtools.netmonitor.har.enableAutoExportToFile", false);
-+
-+pref("devtools.netmonitor.features.webSockets", true);
-+
-+// netmonitor audit
-+pref("devtools.netmonitor.audits.slow", 500);
-+
-+// Disable the EventSource Inspector.
-+pref("devtools.netmonitor.features.serverSentEvents", false);
-+
-+// Enable the Storage Inspector
-+pref("devtools.storage.enabled", true);
-+
-+// Enable the Style Editor.
-+pref("devtools.styleeditor.enabled", true);
-+pref("devtools.styleeditor.autocompletion-enabled", true);
-+pref("devtools.styleeditor.showMediaSidebar", true);
-+pref("devtools.styleeditor.mediaSidebarWidth", 238);
-+pref("devtools.styleeditor.navSidebarWidth", 245);
-+pref("devtools.styleeditor.transitions", true);
-+
-+// Screenshot Option Settings.
-+pref("devtools.screenshot.clipboard.enabled", false);
-+pref("devtools.screenshot.audio.enabled", true);
-+
-+// Make sure the DOM panel is hidden by default
-+pref("devtools.dom.enabled", false);
-+
-+// Enable the Accessibility panel.
-+pref("devtools.accessibility.enabled", true);
-+
-+// Web console filters
-+pref("devtools.webconsole.filter.error", true);
-+pref("devtools.webconsole.filter.warn", true);
-+pref("devtools.webconsole.filter.info", true);
-+pref("devtools.webconsole.filter.log", true);
-+pref("devtools.webconsole.filter.debug", true);
-+pref("devtools.webconsole.filter.css", false);
-+pref("devtools.webconsole.filter.net", false);
-+pref("devtools.webconsole.filter.netxhr", false);
-+
-+// Webconsole autocomplete preference
-+pref("devtools.webconsole.input.autocomplete",true);
-+  pref("devtools.webconsole.input.context", false);
-+
-+// Set to true to eagerly show the results of webconsole terminal evaluations
-+// when they don't have side effects.
-+pref("devtools.webconsole.input.eagerEvaluation", true);
-+
-+// Browser console filters
-+pref("devtools.browserconsole.filter.error", true);
-+pref("devtools.browserconsole.filter.warn", true);
-+pref("devtools.browserconsole.filter.info", true);
-+pref("devtools.browserconsole.filter.log", true);
-+pref("devtools.browserconsole.filter.debug", true);
-+pref("devtools.browserconsole.filter.css", false);
-+pref("devtools.browserconsole.filter.net", false);
-+pref("devtools.browserconsole.filter.netxhr", false);
-+
-+// Max number of inputs to store in web console history.
-+pref("devtools.webconsole.inputHistoryCount", 300);
-+
-+// Persistent logging: |true| if you want the relevant tool to keep all of the
-+// logged messages after reloading the page, |false| if you want the output to
-+// be cleared each time page navigation happens.
-+pref("devtools.webconsole.persistlog", false);
-+pref("devtools.netmonitor.persistlog", false);
-+
-+// Web Console timestamp: |true| if you want the logs and instructions
-+// in the Web Console to display a timestamp, or |false| to not display
-+// any timestamps.
-+pref("devtools.webconsole.timestampMessages", false);
-+
-+// Enable the webconsole sidebar toggle in Nightly builds.
-+  pref("devtools.webconsole.sidebarToggle", false);
-+
-+// Saved editor mode state in the console.
-+pref("devtools.webconsole.input.editor", false);
-+pref("devtools.browserconsole.input.editor", false);
-+
-+// Editor width for webconsole and browserconsole.
-+pref("devtools.webconsole.input.editorWidth", 0);
-+pref("devtools.browserconsole.input.editorWidth", 0);
-+
-+// Display an onboarding UI for the Editor mode.
-+pref("devtools.webconsole.input.editorOnboarding", true);
-+
-+// Enable message grouping in the console, true by default
-+pref("devtools.webconsole.groupWarningMessages", true);
-+
-+// Saved state of the Display content messages checkbox in the browser console.
-+pref("devtools.browserconsole.contentMessages", true);
-+
-+// Enable network monitoring the browser toolbox console/browser console.
-+pref("devtools.browserconsole.enableNetworkMonitoring", false);
-+
-+// Enable client-side mapping service for source maps
-+pref("devtools.source-map.client-service.enabled", true);
-+
-+// The number of lines that are displayed in the web console.
-+pref("devtools.hud.loglimit", 10000);
-+
-+// The developer tools editor configuration:
-+// - tabsize: how many spaces to use when a Tab character is displayed.
-+// - expandtab: expand Tab characters to spaces.
-+// - keymap: which keymap to use (can be 'default', 'emacs' or 'vim')
-+// - autoclosebrackets: whether to permit automatic bracket/quote closing.
-+// - detectindentation: whether to detect the indentation from the file
-+// - enableCodeFolding: Whether to enable code folding or not.
-+pref("devtools.editor.tabsize", 2);
-+pref("devtools.editor.expandtab", true);
-+pref("devtools.editor.keymap", "default");
-+pref("devtools.editor.autoclosebrackets", true);
-+pref("devtools.editor.detectindentation", true);
-+pref("devtools.editor.enableCodeFolding", true);
-+pref("devtools.editor.autocomplete", true);
-+
-+// The angle of the viewport.
-+pref("devtools.responsive.viewport.angle", 0);
-+// The width of the viewport.
-+pref("devtools.responsive.viewport.width", 320);
-+// The height of the viewport.
-+pref("devtools.responsive.viewport.height", 480);
-+// The pixel ratio of the viewport.
-+pref("devtools.responsive.viewport.pixelRatio", 0);
-+// Whether or not the viewports are left aligned.
-+pref("devtools.responsive.leftAlignViewport.enabled", false);
-+// Whether to reload when touch simulation is toggled
-+pref("devtools.responsive.reloadConditions.touchSimulation", false);
-+// Whether to reload when user agent is changed
-+pref("devtools.responsive.reloadConditions.userAgent", false);
-+// Whether to show the notification about reloading to apply emulation
-+pref("devtools.responsive.reloadNotification.enabled", true);
-+// Whether or not touch simulation is enabled.
-+pref("devtools.responsive.touchSimulation.enabled", false);
-+// The user agent of the viewport.
-+pref("devtools.responsive.userAgent", "");
-+
-+// Show the custom user agent input in Nightly builds.
-+#if defined(NIGHTLY_BUILD)
-+  pref("devtools.responsive.showUserAgentInput", true);
-+#else
-+  pref("devtools.responsive.showUserAgentInput", false);
-+#endif
-+
-+// Show tab debug targets for This Firefox (on by default for local builds).
-+  pref("devtools.aboutdebugging.local-tab-debugging", true);
-+
-+// Show process debug targets.
-+pref("devtools.aboutdebugging.process-debugging", true);
-+// Stringified array of network locations that users can connect to.
-+pref("devtools.aboutdebugging.network-locations", "[]");
-+// Debug target pane collapse/expand settings.
-+pref("devtools.aboutdebugging.collapsibilities.installedExtension", false);
-+pref("devtools.aboutdebugging.collapsibilities.otherWorker", false);
-+pref("devtools.aboutdebugging.collapsibilities.serviceWorker", false);
-+pref("devtools.aboutdebugging.collapsibilities.sharedWorker", false);
-+pref("devtools.aboutdebugging.collapsibilities.tab", false);
-+pref("devtools.aboutdebugging.collapsibilities.temporaryExtension", false);
-+
-+// about:debugging: only show system and hidden extensions in local builds by
-+// default.
-+  pref("devtools.aboutdebugging.showHiddenAddons", true);
-+
-+// Map top-level await expressions in the console
-+pref("devtools.debugger.features.map-await-expression", true);
-+
-+// This relies on javascript.options.asyncstack as well or it has no effect.
-+pref("devtools.debugger.features.async-captured-stacks", true);
-+pref("devtools.debugger.features.async-live-stacks", false);
-+
-+// Disable autohide for DevTools popups and tooltips.
-+// This is currently not exposed by any UI to avoid making
-+// about:devtools-toolbox tabs unusable by mistake.
-+pref("devtools.popup.disable_autohide", false);
-+
-+// Enable overflow debugging in the inspector.
-+pref("devtools.overflow.debugging.enabled", true);
-+// Enable drag to edit properties in the inspector rule view.
-+pref("devtools.inspector.draggable_properties", true);
-diff --git a/suite/components/devtools/components.conf b/suite/components/devtools/components.conf
-new file mode 100644
---- /dev/null
-+++ b/suite/components/devtools/components.conf
-@@ -0,0 +1,15 @@
-+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-+# vim: set filetype=python:
-+# This Source Code Form is subject to the terms of the Mozilla Public
-+# License, v. 2.0. If a copy of the MPL was not distributed with this
-+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-+
-+Classes = [
-+  {
-+    'cid': '{089694e9-106a-4704-abf7-62a88545e194}',
-+    'contract_ids': ['@xulvolution.org/generic/devtools-startup-clh;1'],
-+    'esModule': 'resource:///modules/devtools-loader.sys.mjs',
-+    'constructor': 'DevToolsStartup',
-+    'categories': {'command-line-handler': 'm-aaa-xre-devtools'},
-+  },
-+]
-diff --git a/suite/components/devtools/devtools-loader.sys.mjs b/suite/components/devtools/devtools-loader.sys.mjs
-new file mode 100644
---- /dev/null
-+++ b/suite/components/devtools/devtools-loader.sys.mjs
-@@ -0,0 +1,118 @@
-+/* 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/. */
-+
-+const lazy = {};
-+ChromeUtils.defineESModuleGetters(lazy, {
-+  NetUtil: "resource://gre/modules/NetUtil.sys.mjs",
-+});
-+
-+function resolveURIInternal(aCmdLine, aArgument) {
-+  var uri = aCmdLine.resolveURI(aArgument);
-+
-+  if (!(uri instanceof Ci.nsIFileURL)) {
-+    return uri;
-+  }
-+
-+  try {
-+    if (uri.file.exists()) {
-+      return uri;
-+    }
-+  } catch (e) {
-+    console.error(e);
-+  }
-+
-+  // We have interpreted the argument as a relative file URI, but the file
-+  // doesn't exist. Try URI fixup heuristics: see bug 290782.
-+
-+  try {
-+    uri = Services.uriFixup.getFixupURIInfo(aArgument, 0).preferredURI;
-+  } catch (e) {
-+    console.error(e);
-+  }
-+
-+  return uri;
-+}
-+
-+export function DevToolsStartup() {}
-+
-+DevToolsStartup.prototype = {
-+  QueryInterface: ChromeUtils.generateQI(["nsICommandLineHandler"]),
-+
-+  helpInfo: "",
-+  handle(cmdLine) {
-+    this.initialize();
-+
-+    // We want to overwrite the -devtools flag and open the toolbox instead
-+    const devtoolsFlag = cmdLine.handleFlag("devtools", false);
-+    if (devtoolsFlag) {
-+      this.handleDevToolsFlag(cmdLine);
-+    }
-+
-+    var chromeFlag = cmdLine.handleFlagWithParam("chrome", false);
-+    if (chromeFlag) {
-+      // The parameter specifies the window to open.
-+      this.handleChromeFlag(cmdLine, chromeFlag);
-+    }
-+  },
-+
-+  handleDevToolsFlag(cmdLine) {
-+    const { BrowserToolboxLauncher } = ChromeUtils.importESModule(
-+      "resource://devtools/client/framework/browser-toolbox/Launcher.sys.mjs"
-+    );
-+    BrowserToolboxLauncher.init();
-+
-+    if (cmdLine.state == Ci.nsICommandLine.STATE_REMOTE_AUTO) {
-+      cmdLine.preventDefault = true;
-+    }
-+  },
-+
-+  handleChromeFlag(cmdLine, chromeParam) {
-+    try {
-+      const argstring = Cc["@mozilla.org/supports-string;1"].createInstance(
-+        Ci.nsISupportsString
-+      );
-+
-+      const _uri = resolveURIInternal(cmdLine, chromeParam);
-+
-+      // only load URIs which do not inherit chrome privs
-+      if (!Services.io.URIChainHasFlags(_uri, Ci.nsIProtocolHandler.URI_INHERITS_SECURITY_CONTEXT)) {
-+        Services.ww.openWindow(null, _uri.spec, "_blank", "chrome,dialog=no,all", argstring);
-+        cmdLine.preventDefault = true;
-+      }
-+    } catch (e) { dump(e); }
-+  },
-+
-+  initialize() {
-+    const { loader, require, DevToolsLoader } = ChromeUtils.importESModule(
-+      "resource://devtools/shared/loader/Loader.sys.mjs"
-+    );
-+    const { DevToolsServer } = require("devtools/server/devtools-server");
-+    const { gDevTools } = require("devtools/client/framework/devtools");
-+
-+    // Make sure our root actor is always registered, no matter how devtools are called.
-+    const devtoolsRegisterActors =
-+      DevToolsServer.registerActors.bind(DevToolsServer);
-+    DevToolsServer.registerActors = function (options) {
-+      devtoolsRegisterActors(options);
-+      if (options.root) {
-+        const {
-+          createRootActor,
-+        } = require("resource:///modules/devtools-root-actor.js");
-+        DevToolsServer.setRootActor(createRootActor);
-+      }
-+    };
-+
-+    // Make the loader visible to the debugger by default and for the already
-+    // loaded instance. Thunderbird now also provides the Browser Toolbox for
-+    // chrome debugging, which uses its own separate loader instance.
-+    DevToolsLoader.prototype.invisibleToDebugger = false;
-+    loader.invisibleToDebugger = false;
-+    DevToolsServer.allowChromeProcess = true;
-+
-+    // Initialize and load the toolkit/browser actors. This will also call above function to set the
-+    // Thunderbird root actor
-+    DevToolsServer.init();
-+    DevToolsServer.registerAllActors();
-+  },
-+};
-diff --git a/suite/components/devtools/devtools-root-actor.js b/suite/components/devtools/devtools-root-actor.js
-new file mode 100644
---- /dev/null
-+++ b/suite/components/devtools/devtools-root-actor.js
-@@ -0,0 +1,67 @@
-+/* 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/. */
-+
-+/* globals loader, require, exports */
-+
-+/**
-+ * Actors for Developer Tools.
-+ */
-+
-+var { ActorRegistry } = require("devtools/server/actors/utils/actor-registry");
-+
-+loader.lazyRequireGetter(
-+  this,
-+  "RootActor",
-+  "devtools/server/actors/root",
-+  true
-+);
-+loader.lazyRequireGetter(
-+  this,
-+  "sendShutdownEvent",
-+  "devtools/server/actors/webbrowser",
-+  true
-+);
-+loader.lazyRequireGetter(
-+  this,
-+  "WorkerDescriptorActorList",
-+  "devtools/server/actors/worker/worker-descriptor-actor-list",
-+  true
-+);
-+loader.lazyRequireGetter(
-+  this,
-+  "ServiceWorkerRegistrationActorList",
-+  "devtools/server/actors/worker/service-worker-registration-list",
-+  true
-+);
-+loader.lazyRequireGetter(
-+  this,
-+  "ProcessActorList",
-+  "devtools/server/actors/process",
-+  true
-+);
-+
-+/**
-+ * Create the basic root actor for any XRE Application.
-+ *
-+ * @param aConnection       The debugger connection to create the actor for.
-+ * @returns The actor for the connection.
-+ */
-+exports.createRootActor = function (aConnection) {
-+  const parameters = {
-+    workerList: new WorkerDescriptorActorList(aConnection, {}),
-+    serviceWorkerRegistrationList: new ServiceWorkerRegistrationActorList(
-+      aConnection
-+    ),
-+    processList: new ProcessActorList(),
-+    globalActorFactories: ActorRegistry.globalActorFactories,
-+    onShutdown: sendShutdownEvent,
-+  };
-+
-+  // Create the root actor and set the application type
-+  const rootActor = new RootActor(aConnection, parameters);
-+  rootActor.applicationType = "generic";
-+
-+  return rootActor;
-+};
-+
-diff --git a/suite/components/devtools/moz.build b/suite/components/devtools/moz.build
-new file mode 100644
---- /dev/null
-+++ b/suite/components/devtools/moz.build
-@@ -0,0 +1,15 @@
-+# vim: set filetype=python:
-+# This Source Code Form is subject to the terms of the Mozilla Public
-+# License, v. 2.0. If a copy of the MPL was not distributed with this
-+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-+
-+EXTRA_JS_MODULES += [
-+    "devtools-loader.sys.mjs",
-+    "devtools-root-actor.js",
-+]
-+
-+XPCOM_MANIFESTS += [
-+    "components.conf",
-+]
-+
-+JS_PREFERENCE_FILES += ['all-devtools.js']
-diff --git a/suite/components/moz.build b/suite/components/moz.build
---- a/suite/components/moz.build
-+++ b/suite/components/moz.build
-@@ -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/.
- 
- DIRS += [
-     "autocomplete",
-     "bindings",
-     "console",
-     "dataman",
-+    "devtools",
-     "downloads",
-     "feeds",
-     "helpviewer",
-     "migration",
-     "permissions",
-     "places",
-     "pref",
-     "profile",

+ 0 - 2624
comm-central/patches/TOP-CONTRIB-diagnostic-buoy-component.patch

@@ -1,2624 +0,0 @@
-# HG changeset patch
-# User Matt A. Tobin <email@mattatobin.com>
-# Date 1659988365 0
-No Bug - Create an isolated dianostic component for the suite.
-
-diff --git a/suite/buoy/ATTN-CC-SUITE-PATCHERS.txt b/suite/buoy/ATTN-CC-SUITE-PATCHERS.txt
-new file mode 100644
---- /dev/null
-+++ b/suite/buoy/ATTN-CC-SUITE-PATCHERS.txt
-@@ -0,0 +1,3 @@
-+Please exclude this component from any scripted or manual upgrades to the rest
-+of the suite (unless you are specifically updating this component).
-+It's handling is a special case and should be done seperately.
-\ No newline at end of file
-diff --git a/suite/buoy/ATTN-L10N-TRANSLATORS.txt b/suite/buoy/ATTN-L10N-TRANSLATORS.txt
-new file mode 100644
---- /dev/null
-+++ b/suite/buoy/ATTN-L10N-TRANSLATORS.txt
-@@ -0,0 +1,3 @@
-+This component can be ignored and does not need to be translated. Its only
-+purpose is to faciliate SeaMonkey Reconstruction as well as specific
-+testing cases.
-\ No newline at end of file
-diff --git a/suite/buoy/ZZ-buoy-prefs.js b/suite/buoy/ZZ-buoy-prefs.js
-new file mode 100644
---- /dev/null
-+++ b/suite/buoy/ZZ-buoy-prefs.js
-@@ -0,0 +1,2 @@
-+pref("toolkit.defaultChromeURI", "chrome://buoy/content/buoy.xhtml");
-+pref("prompts.contentPromptSubDialog", false);
-diff --git a/suite/buoy/content/buoy.css b/suite/buoy/content/buoy.css
-new file mode 100644
---- /dev/null
-+++ b/suite/buoy/content/buoy.css
-@@ -0,0 +1,9 @@
-+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-+/* This Source Code Form is subject to the terms of the Mozilla Public
-+ * License, v. 2.0. If a copy of the MPL was not distributed with this
-+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-+
-+html, body {
-+  height: 100%;
-+}
-+
-diff --git a/suite/buoy/content/buoy.js b/suite/buoy/content/buoy.js
-new file mode 100644
---- /dev/null
-+++ b/suite/buoy/content/buoy.js
-@@ -0,0 +1,85 @@
-+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-+/* This Source Code Form is subject to the terms of the Mozilla Public
-+ * License, v. 2.0. If a copy of the MPL was not distributed with this
-+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-+
-+// e10s
-+var { EzE10SUtils } = ChromeUtils.importESModule(
-+  "resource:///modules/EzE10SUtils.sys.mjs"
-+);
-+
-+// Devtools
-+ChromeUtils.defineESModuleGetters(this, {
-+  BrowserToolboxLauncher: "resource://devtools/client/framework/browser-toolbox/Launcher.sys.mjs",
-+});
-+
-+Object.defineProperty(this, "BrowserConsoleManager", {
-+  get() {
-+    let { loader } = ChromeUtils.importESModule("resource://devtools/shared/loader/Loader.sys.mjs");
-+    return loader.require("devtools/client/webconsole/browser-console-manager").BrowserConsoleManager;
-+  },
-+  configurable: true,
-+  enumerable: true,
-+});
-+
-+// Main functions
-+var gBuoy = {
-+  homepage: "about:version",
-+  toContent: function(aURL) {
-+    var browser = document.getElementById("main-browser");
-+    EzE10SUtils.loadURI(browser, aURL);
-+  },
-+  toChrome: function(inType, uri, features, args) {
-+    var topWindow = Services.wm.getMostRecentWindow(inType);
-+
-+    if (topWindow) {
-+      topWindow.focus();
-+    } else if (features) {
-+      Services.ww.openWindow(null, uri, "_blank", features, args);
-+    } else {
-+      Services.ww.openWindow(
-+        null,
-+        uri,
-+        "_blank",
-+        "chrome,all,dialog=no,extrachrome,menubar,resizable,scrollbars," +
-+        "status,location,toolbar,personalbar",
-+        args
-+      );
-+    }
-+  },
-+  navHome: function() {
-+    var browser = document.getElementById("main-browser");
-+    EzE10SUtils.loadURI(browser, this.homepage);
-+  },
-+  navigation: function(aNaviCmd) {
-+    var browser = document.getElementById("main-browser");
-+    switch (aNaviCmd) {
-+      case 'back':
-+        browser.goBack();
-+        break;
-+      case 'forward':
-+        browser.goForward();
-+        break;
-+      case 'reload':
-+        browser.reload();
-+        break;
-+      case 'stop':
-+        browser.stop();
-+        break;
-+      default:
-+        gBuoy.navHome();
-+    }
-+  },
-+  devtools: function() { BrowserToolboxLauncher.init(); },
-+  quitApp: function() { Services.startup.quit(Services.startup.eAttemptQuit); },
-+  startup: function() {
-+    var browser = document.getElementById("main-browser");
-+    EzE10SUtils.loadAboutBlank(browser);
-+    gBuoy.navHome();
-+  },
-+}
-+
-+// Devtools Compat
-+function openWebLinkIn(url, where, params) {
-+  gBuoy.toContent(url);
-+}
-diff --git a/suite/buoy/content/buoy.xhtml b/suite/buoy/content/buoy.xhtml
-new file mode 100644
---- /dev/null
-+++ b/suite/buoy/content/buoy.xhtml
-@@ -0,0 +1,155 @@
-+<?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/. -->
-+
-+<!--  Mozilla DocType Reference:
-+      xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-+      xmlns:xbl="http://www.mozilla.org/xbl"
-+      xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-+      xmlns:html="http://www.w3.org/1999/xhtml"
-+      xmlns:svg="http://www.w3.org/2000/svg"
-+      xmlns:em="http://www.mozilla.org/2004/em-rdf#"
-+-->
-+
-+<!DOCTYPE html>
-+
-+<html id="main-window"
-+      xmlns="http://www.w3.org/1999/xhtml"
-+      xmlns:html="http://www.w3.org/1999/xhtml"
-+      xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-+      windowtype="buoy:main"
-+      screenX="10"
-+      screenY="10"
-+      width="640px"
-+      height="480px"
-+      scrolling="false"
-+      persist="screenX screenY width height sizemode">
-+  <head>
-+    <title>SeaMonkey Diagnostic &amp; Testing Buoy</title>
-+    <link rel="stylesheet" href="chrome://global/skin/global.css" />
-+    <link rel="stylesheet" href="chrome://buoy/content/buoy.css" />
-+    <script defer="defer" src="chrome://global/content/customElements.js" />
-+    <script defer="defer" src="chrome://buoy/content/buoy.js" />
-+    <script>
-+      window.addEventListener("load", gBuoy.startup);
-+    </script>
-+  </head>
-+  <body xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-+
-+    <commandset id="mainCommandSet">
-+      <command id="cmd_Exit"
-+               oncommand="gBuoy.quitApp();"/>
-+      <command id="cmd_DevTools"
-+               oncommand="gBuoy.devtools();"/>
-+
-+      <command id="cmd_Navigator"
-+               oncommand="gBuoy.toChrome('navigator:browser',
-+                                         'chrome://navigator/content/navigator.xhtml');"/>
-+      <command id="cmd_MailNews"
-+               oncommand="gBuoy.toChrome('mail:3pane',
-+                                         'chrome://messenger/content/messenger.xhtml');"/>
-+      <command id="cmd_Composer"
-+               oncommand="gBuoy.toChrome('composer:html',
-+                                         'chrome://editor/content/editor.xhtml');"/>
-+      <command id="cmd_Preferences"
-+               oncommand="gBuoy.toChrome('mozilla:preferences',
-+                                         'chrome://communicator/content/pref/preferences.xhtml');"/>
-+
-+      <command id="cmd_AboutAbout"
-+               oncommand="gBuoy.toContent('about:about');"/>
-+      <command id="cmd_AboutConfig"
-+               oncommand="gBuoy.toContent('about:config');"/>
-+      <command id="cmd_AboutSupport"
-+               oncommand="gBuoy.toContent('about:support');"/>
-+      <command id="cmd_AboutVersion"
-+               oncommand="gBuoy.toContent('about:version');"/>
-+
-+      <command id="cmd_NavHome"
-+               oncommand="gBuoy.navHome();"/>
-+
-+      <command id="cmd_NavBack"
-+               oncommand="gBuoy.navigation('back');"/>
-+      <command id="cmd_NavForward"
-+               oncommand="gBuoy.navigation('forward');"/>
-+      <command id="cmd_NavReload"
-+               oncommand="gBuoy.navigation('reload');"/>
-+      <command id="cmd_NavStop"
-+               oncommand="gBuoy.navigation('stop');"/>
-+
-+      <command id="cmd_SeaMonkeyHomePage"
-+               oncommand="gBuoy.toContent('https://www.seamonkey-project.org/');"/>
-+      <command id="cmd_GetInvolved"
-+               oncommand="gBuoy.toContent('https://www.seamonkey-project.org/dev/get-involved');"/>
-+
-+    </commandset>
-+
-+    <vbox flex="1">    
-+      <toolbox id="main-toolbox" style="border-bottom: 1px solid ThreeDShadow;">
-+        <menubar id="main-menubar">
-+          <menu id="file-menu" label="File">
-+            <menupopup id="file-popup">
-+              <menuitem label="Exit" command="cmd_Exit"/>
-+            </menupopup>
-+          </menu>
-+          <menu id="edit-menu" label="Edit">
-+            <menupopup id="edit-popup">
-+              <menuitem label="Configuration Editor" command="cmd_AboutConfig"/>
-+              <menuitem label="Preferences" command="cmd_Preferences"/>
-+            </menupopup>
-+          </menu>
-+          <menu id="go-menu" label="Go">
-+            <menupopup id="components-popup">
-+              <menuitem label="Back" command="cmd_NavBack"/>
-+              <menuitem label="Forward" command="cmd_NavForward"/>
-+              <menuitem label="Reload" command="cmd_NavReload"/>
-+              <menuitem label="Stop" command="cmd_NavStop"/>
-+              <menuitem label="Home" command="cmd_NavHome"/>
-+            </menupopup>
-+          </menu>
-+          <menu id="components-menu" label="Components">
-+            <menupopup id="components-popup">
-+              <menuitem label="Browser" command="cmd_Navigator"/>
-+              <menuitem label="Messenger" command="cmd_MailNews"/>
-+              <menuitem label="Composer" command="cmd_Composer"/>
-+            </menupopup>
-+          </menu>
-+          <menu id="tools-menu" label="Tools">
-+            <menupopup id="tools-popup">
-+              <menuitem label="About: Pages" command="cmd_AboutAbout"/>
-+              <menuitem label="Developer Tools" command="cmd_DevTools"/>
-+            </menupopup>
-+          </menu>
-+          <menu id="help-menu" label="Help">
-+            <menupopup id="help-popup">
-+              <menuitem label="Get Involved" command="cmd_GetInvolved"/>
-+              <menuitem label="Troubleshooting Information" command="cmd_AboutSupport"/>
-+              <menuitem label="About SeaMonkey" command="cmd_AboutVersion"/>
-+            </menupopup>
-+          </menu>
-+        </menubar>
-+        <toolbar id="navigation-toolbar">
-+          <toolbarbutton id="back-button" label="&lt; Back" command="cmd_NavBack"/>
-+          <toolbarbutton id="forward-button" label="&gt; Forward" command="cmd_NavForward"/>
-+          <toolbarbutton id="reload-button" label="O Reload" command="cmd_NavReload"/>
-+          <toolbarbutton id="stop-button" label="X Stop" command="cmd_NavStop"/>
-+          <html:input id="urlbar" style="flex: 1; margin: 2px; padding: 4px;" placeholder="Enter a URL..." />
-+          <toolbarbutton id="go-button" label="Go -&gt;" oncommand="var urlbar = document.getElementById('urlbar');
-+                                                                    gBuoy.toContent(urlbar.value);
-+                                                                    urlbar.value = '';"/>
-+        </toolbar>
-+        <toolbar id="quick-links-toolbar">
-+          <button label="SeaMonkey Homepage" command="cmd_SeaMonkeyHomePage"/>
-+          <button label="Get Involved" command="cmd_GetInvolved"/>
-+        </toolbar>
-+      </toolbox>
-+      <browser id="main-browser"
-+               flex="1"
-+               type="content"
-+               primary="true"
-+               maychangeremoteness="true"
-+               nodefaultsrc="true" />
-+    </vbox>
-+  </body>
-+</html>
-+
-diff --git a/suite/buoy/jar.mn b/suite/buoy/jar.mn
-new file mode 100644
---- /dev/null
-+++ b/suite/buoy/jar.mn
-@@ -0,0 +1,16 @@
-+# 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/.
-+
-+#filter substitution
-+
-+buoy.jar:
-+% content buoy %content/buoy/ contentaccessible=yes
-+  content/buoy/buoy.css            (content/buoy.css)
-+  content/buoy/buoy.js             (content/buoy.js)
-+  content/buoy/buoy.xhtml          (content/buoy.xhtml)
-+
-+[localization] @AB_CD@.jar:
-+  browser                          (moz-l10n/browser/**/*.ftl)
-+  buoy                             (locale/**/*.ftl)
-+
-diff --git a/suite/buoy/modules/BrowserWindowTracker.sys.mjs b/suite/buoy/modules/BrowserWindowTracker.sys.mjs
-new file mode 100644
---- /dev/null
-+++ b/suite/buoy/modules/BrowserWindowTracker.sys.mjs
-@@ -0,0 +1,6 @@
-+/* This Source Code Form is subject to the terms of the Mozilla Public
-+ * License, v. 2.0. If a copy of the MPL was not distributed with this
-+ * file, you can obtain one at http://mozilla.org/MPL/2.0/. */
-+
-+// This module is deliberately not implemented. It only exists to keep
-+// the automated tests happy. See bug 1782621.
-diff --git a/suite/buoy/modules/CustomizableUI.sys.mjs b/suite/buoy/modules/CustomizableUI.sys.mjs
-new file mode 100644
---- /dev/null
-+++ b/suite/buoy/modules/CustomizableUI.sys.mjs
-@@ -0,0 +1,360 @@
-+/* This Source Code Form is subject to the terms of the Mozilla Public
-+ * License, v. 2.0. If a copy of the MPL was not distributed with this
-+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-+
-+// This file is a copy of a file with the same name in Firefox. Only the
-+// pieces we're using, and a few pieces the devtools rely on such as the
-+// constants, remain.
-+
-+const lazy = {};
-+
-+ChromeUtils.defineESModuleGetters(lazy, {
-+  PanelMultiView: "resource:///modules/PanelMultiView.sys.mjs",
-+});
-+
-+/**
-+ * gPanelsForWindow is a list of known panels in a window which we may need to close
-+ * should command events fire which target them.
-+ */
-+var gPanelsForWindow = new WeakMap();
-+
-+var CustomizableUIInternal = {
-+  addPanelCloseListeners(aPanel) {
-+    Services.els.addSystemEventListener(aPanel, "click", this, false);
-+    Services.els.addSystemEventListener(aPanel, "keypress", this, false);
-+    const win = aPanel.ownerGlobal;
-+    if (!gPanelsForWindow.has(win)) {
-+      gPanelsForWindow.set(win, new Set());
-+    }
-+    gPanelsForWindow.get(win).add(this._getPanelForNode(aPanel));
-+  },
-+
-+  removePanelCloseListeners(aPanel) {
-+    Services.els.removeSystemEventListener(aPanel, "click", this, false);
-+    Services.els.removeSystemEventListener(aPanel, "keypress", this, false);
-+    const win = aPanel.ownerGlobal;
-+    const panels = gPanelsForWindow.get(win);
-+    if (panels) {
-+      panels.delete(this._getPanelForNode(aPanel));
-+    }
-+  },
-+
-+  handleEvent(aEvent) {
-+    switch (aEvent.type) {
-+      case "click":
-+      case "keypress":
-+        this.maybeAutoHidePanel(aEvent);
-+        break;
-+    }
-+  },
-+
-+  _getPanelForNode(aNode) {
-+    return aNode.closest("panel");
-+  },
-+
-+  /*
-+   * If people put things in the panel which need more than single-click interaction,
-+   * we don't want to close it. Right now we check for text inputs and menu buttons.
-+   * We also check for being outside of any toolbaritem/toolbarbutton, ie on a blank
-+   * part of the menu.
-+   */
-+  _isOnInteractiveElement(aEvent) {
-+    function getMenuPopupForDescendant(aNode) {
-+      let lastPopup = null;
-+      while (
-+        aNode &&
-+        aNode.parentNode &&
-+        aNode.parentNode.localName.startsWith("menu")
-+      ) {
-+        lastPopup = aNode.localName == "menupopup" ? aNode : lastPopup;
-+        aNode = aNode.parentNode;
-+      }
-+      return lastPopup;
-+    }
-+
-+    let target = aEvent.target;
-+    const panel = this._getPanelForNode(aEvent.currentTarget);
-+    // This can happen in e.g. customize mode. If there's no panel,
-+    // there's clearly nothing for us to close; pretend we're interactive.
-+    if (!panel) {
-+      return true;
-+    }
-+    // We keep track of:
-+    // whether we're in an input container (text field)
-+    let inInput = false;
-+    // whether we're in a popup/context menu
-+    let inMenu = false;
-+    // whether we're in a toolbarbutton/toolbaritem
-+    let inItem = false;
-+    // whether the current menuitem has a valid closemenu attribute
-+    let menuitemCloseMenu = "auto";
-+
-+    // While keeping track of that, we go from the original target back up,
-+    // to the panel if we have to. We bail as soon as we find an input,
-+    // a toolbarbutton/item, or the panel:
-+    while (target) {
-+      // Skip out of iframes etc:
-+      if (target.nodeType == target.DOCUMENT_NODE) {
-+        if (!target.defaultView) {
-+          // Err, we're done.
-+          break;
-+        }
-+        // Find containing browser or iframe element in the parent doc.
-+        target = target.defaultView.docShell.chromeEventHandler;
-+        if (!target) {
-+          break;
-+        }
-+      }
-+      const tagName = target.localName;
-+      inInput = tagName == "input";
-+      inItem = tagName == "toolbaritem" || tagName == "toolbarbutton";
-+      const isMenuItem = tagName == "menuitem";
-+      inMenu = inMenu || isMenuItem;
-+
-+      if (isMenuItem && target.hasAttribute("closemenu")) {
-+        const closemenuVal = target.getAttribute("closemenu");
-+        menuitemCloseMenu =
-+          closemenuVal == "single" || closemenuVal == "none"
-+            ? closemenuVal
-+            : "auto";
-+      }
-+
-+      // Keep the menu open and break out of the loop if the click happened on
-+      // the ShadowRoot or a disabled menu item.
-+      if (
-+        target.nodeType == target.DOCUMENT_FRAGMENT_NODE ||
-+        target.getAttribute("disabled") == "true"
-+      ) {
-+        return true;
-+      }
-+
-+      // This isn't in the loop condition because we want to break before
-+      // changing |target| if any of these conditions are true
-+      if (inInput || inItem || target == panel) {
-+        break;
-+      }
-+      // We need specific code for popups: the item on which they were invoked
-+      // isn't necessarily in their parentNode chain:
-+      if (isMenuItem) {
-+        const topmostMenuPopup = getMenuPopupForDescendant(target);
-+        target =
-+          (topmostMenuPopup && topmostMenuPopup.triggerNode) ||
-+          target.parentNode;
-+      } else {
-+        target = target.parentNode;
-+      }
-+    }
-+
-+    // If the user clicked a menu item...
-+    if (inMenu) {
-+      // We care if we're in an input also,
-+      // or if the user specified closemenu!="auto":
-+      if (inInput || menuitemCloseMenu != "auto") {
-+        return true;
-+      }
-+      // Otherwise, we're probably fine to close the panel
-+      return false;
-+    }
-+    // If we're not in a menu, and we *are* in a type="menu" toolbarbutton,
-+    // we'll now interact with the menu
-+    if (inItem && target.getAttribute("type") == "menu") {
-+      return true;
-+    }
-+    return inInput || !inItem;
-+  },
-+
-+  hidePanelForNode(aNode) {
-+    const panel = this._getPanelForNode(aNode);
-+    if (panel) {
-+      lazy.PanelMultiView.hidePopup(panel);
-+    }
-+  },
-+
-+  maybeAutoHidePanel(aEvent) {
-+    const eventType = aEvent.type;
-+    if (eventType == "keypress" && aEvent.keyCode != aEvent.DOM_VK_RETURN) {
-+      return;
-+    }
-+
-+    if (eventType == "click" && aEvent.button != 0) {
-+      return;
-+    }
-+
-+    // We don't check preventDefault - it makes sense that this was prevented,
-+    // but we probably still want to close the panel. If consumers don't want
-+    // this to happen, they should specify the closemenu attribute.
-+    if (eventType != "command" && this._isOnInteractiveElement(aEvent)) {
-+      return;
-+    }
-+
-+    // We can't use event.target because we might have passed an anonymous
-+    // content boundary as well, and so target points to the outer element in
-+    // that case. Unfortunately, this means we get anonymous child nodes instead
-+    // of the real ones, so looking for the 'stoooop, don't close me' attributes
-+    // is more involved.
-+    let target = aEvent.originalTarget;
-+    while (target.parentNode && target.localName != "panel") {
-+      if (
-+        target.getAttribute("closemenu") == "none" ||
-+        target.getAttribute("widget-type") == "view" ||
-+        target.getAttribute("widget-type") == "button-and-view"
-+      ) {
-+        return;
-+      }
-+      target = target.parentNode;
-+    }
-+
-+    // If we get here, we can actually hide the popup:
-+    this.hidePanelForNode(aEvent.target);
-+  },
-+};
-+Object.freeze(CustomizableUIInternal);
-+
-+export var CustomizableUI = {
-+  /**
-+   * Constant reference to the ID of the navigation toolbar.
-+   */
-+  AREA_NAVBAR: "nav-bar",
-+  /**
-+   * Constant reference to the ID of the menubar's toolbar.
-+   */
-+  AREA_MENUBAR: "toolbar-menubar",
-+  /**
-+   * Constant reference to the ID of the tabstrip toolbar.
-+   */
-+  AREA_TABSTRIP: "TabsToolbar",
-+  /**
-+   * Constant reference to the ID of the bookmarks toolbar.
-+   */
-+  AREA_BOOKMARKS: "PersonalToolbar",
-+  /**
-+   * Constant reference to the ID of the non-dymanic (fixed) list in the overflow panel.
-+   */
-+  AREA_FIXED_OVERFLOW_PANEL: "widget-overflow-fixed-list",
-+
-+  /**
-+   * Constant indicating the area is a menu panel.
-+   */
-+  TYPE_MENU_PANEL: "menu-panel",
-+  /**
-+   * Constant indicating the area is a toolbar.
-+   */
-+  TYPE_TOOLBAR: "toolbar",
-+
-+  /**
-+   * Constant indicating a XUL-type provider.
-+   */
-+  PROVIDER_XUL: "xul",
-+  /**
-+   * Constant indicating an API-type provider.
-+   */
-+  PROVIDER_API: "api",
-+  /**
-+   * Constant indicating dynamic (special) widgets: spring, spacer, and separator.
-+   */
-+  PROVIDER_SPECIAL: "special",
-+
-+  /**
-+   * Constant indicating the widget is built-in
-+   */
-+  SOURCE_BUILTIN: "builtin",
-+  /**
-+   * Constant indicating the widget is externally provided
-+   * (e.g. by add-ons or other items not part of the builtin widget set).
-+   */
-+  SOURCE_EXTERNAL: "external",
-+
-+  /**
-+   * Constant indicating the reason the event was fired was a window closing
-+   */
-+  REASON_WINDOW_CLOSED: "window-closed",
-+  /**
-+   * Constant indicating the reason the event was fired was an area being
-+   * unregistered separately from window closing mechanics.
-+   */
-+  REASON_AREA_UNREGISTERED: "area-unregistered",
-+
-+  /**
-+   * Add a widget to an area.
-+   * If the area to which you try to add is not known to CustomizableUI,
-+   * this will throw.
-+   * If the area to which you try to add is the same as the area in which
-+   * the widget is currently placed, this will do the same as
-+   * moveWidgetWithinArea.
-+   * If the widget cannot be removed from its original location, this will
-+   * no-op.
-+   *
-+   * This will fire an onWidgetAdded notification,
-+   * and an onWidgetBeforeDOMChange and onWidgetAfterDOMChange notification
-+   * for each window CustomizableUI knows about.
-+   *
-+   * @param aWidgetId the ID of the widget to add
-+   * @param aArea     the ID of the area to add the widget to
-+   * @param aPosition the position at which to add the widget. If you do not
-+   *                  pass a position, the widget will be added to the end
-+   *                  of the area.
-+   */
-+  addWidgetToArea(aWidgetId, aArea, aPosition) {},
-+  /**
-+   * Remove a widget from its area. If the widget cannot be removed from its
-+   * area, or is not in any area, this will no-op. Otherwise, this will fire an
-+   * onWidgetRemoved notification, and an onWidgetBeforeDOMChange and
-+   * onWidgetAfterDOMChange notification for each window CustomizableUI knows
-+   * about.
-+   *
-+   * @param aWidgetId the ID of the widget to remove
-+   */
-+  removeWidgetFromArea(aWidgetId) {},
-+  /**
-+   * Get the placement of a widget. This is by far the best way to obtain
-+   * information about what the state of your widget is. The internals of
-+   * this call are cheap (no DOM necessary) and you will know where the user
-+   * has put your widget.
-+   *
-+   * @param aWidgetId the ID of the widget whose placement you want to know
-+   * @returns
-+   *   {
-+   *     area: "somearea", // The ID of the area where the widget is placed
-+   *     position: 42 // the index in the placements array corresponding to
-+   *                  // your widget.
-+   *   }
-+   *
-+   *   OR
-+   *
-+   *   null // if the widget is not placed anywhere (ie in the palette)
-+   */
-+  getPlacementOfWidget(aWidgetId, aOnlyRegistered = true, aDeadAreas = false) {
-+    return null;
-+  },
-+  /**
-+   * Add listeners to a panel that will close it. For use from the menu panel
-+   * and overflowable toolbar implementations, unlikely to be useful for
-+   * consumers.
-+   *
-+   * @param aPanel the panel to which listeners should be attached.
-+   */
-+  addPanelCloseListeners(aPanel) {
-+    CustomizableUIInternal.addPanelCloseListeners(aPanel);
-+  },
-+  /**
-+   * Remove close listeners that have been added to a panel with
-+   * addPanelCloseListeners. For use from the menu panel and overflowable
-+   * toolbar implementations, unlikely to be useful for consumers.
-+   *
-+   * @param aPanel the panel from which listeners should be removed.
-+   */
-+  removePanelCloseListeners(aPanel) {
-+    CustomizableUIInternal.removePanelCloseListeners(aPanel);
-+  },
-+  /**
-+   * Notify toolbox(es) of a particular event. If you don't pass aWindow,
-+   * all toolboxes will be notified. For use from Customize Mode only,
-+   * do not use otherwise.
-+   *
-+   * @param aEvent the name of the event to send.
-+   * @param aDetails optional, the details of the event.
-+   * @param aWindow optional, the window in which to send the event.
-+   */
-+  dispatchToolboxEvent(aEvent, aDetails = {}, aWindow = null) {},
-+};
-+Object.freeze(CustomizableUI);
-diff --git a/suite/buoy/modules/EzE10SUtils.sys.mjs b/suite/buoy/modules/EzE10SUtils.sys.mjs
-new file mode 100644
---- /dev/null
-+++ b/suite/buoy/modules/EzE10SUtils.sys.mjs
-@@ -0,0 +1,93 @@
-+/* 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 { E10SUtils } from "resource://gre/modules/E10SUtils.sys.mjs";
-+
-+import { ExtensionParent } from "resource://gre/modules/ExtensionParent.sys.mjs";
-+
-+export var EzE10SUtils = {
-+  /**
-+   * Loads about:blank in `browser` without switching remoteness. about:blank
-+   * can load in a local browser or a remote browser, and `loadURI` will make
-+   * it load in a remote browser even if you don't want it to.
-+   *
-+   * @param {nsIBrowser} browser
-+   */
-+  loadAboutBlank(browser) {
-+    if (!browser.currentURI || browser.currentURI.spec == "about:blank") {
-+      return;
-+    }
-+    browser.loadURI(Services.io.newURI("about:blank"), {
-+      triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
-+      remoteTypeOverride: browser.remoteType,
-+    });
-+  },
-+
-+  /**
-+   * Loads `uri` in `browser`, changing to a remote/local browser if necessary.
-+   *
-+   * @see `nsIWebNavigation.loadURI`
-+   *
-+   * @param {nsIBrowser} browser
-+   * @param {string} uri
-+   * @param {object} params
-+   */
-+  loadURI(browser, uri, params = {}) {
-+    const multiProcess = browser.ownerGlobal.docShell.QueryInterface(
-+      Ci.nsILoadContext
-+    ).useRemoteTabs;
-+    const remoteSubframes = browser.ownerGlobal.docShell.QueryInterface(
-+      Ci.nsILoadContext
-+    ).useRemoteSubframes;
-+
-+    const isRemote = browser.getAttribute("remote") == "true";
-+    const remoteType = E10SUtils.getRemoteTypeForURI(
-+      uri,
-+      multiProcess,
-+      remoteSubframes
-+    );
-+    const shouldBeRemote = remoteType !== E10SUtils.NOT_REMOTE;
-+
-+    if (shouldBeRemote != isRemote) {
-+      this.changeRemoteness(browser, remoteType);
-+    }
-+
-+    params.triggeringPrincipal =
-+      params.triggeringPrincipal ||
-+      Services.scriptSecurityManager.getSystemPrincipal();
-+    browser.fixupAndLoadURIString(uri, params);
-+  },
-+
-+  /**
-+   * Force `browser` to be a remote/local browser.
-+   *
-+   * @see E10SUtils.sys.mjs for remote types.
-+   *
-+   * @param {nsIBrowser} browser - the browser to enforce the remoteness of.
-+   * @param {string} remoteType - the remoteness to enforce.
-+   * @returns {boolean} true if any change happened on the browser (which would
-+   *    not be the case if its remoteness is already in the correct state).
-+   */
-+  changeRemoteness(browser, remoteType) {
-+    if (browser.remoteType == remoteType) {
-+      return false;
-+    }
-+
-+    browser.destroy();
-+
-+    if (remoteType) {
-+      browser.setAttribute("remote", "true");
-+      browser.setAttribute("remoteType", remoteType);
-+    } else {
-+      browser.setAttribute("remote", "false");
-+      browser.removeAttribute("remoteType");
-+    }
-+
-+    browser.changeRemoteness({ remoteType });
-+    browser.construct();
-+    ExtensionParent.apiManager.emit("extension-browser-inserted", browser);
-+
-+    return true;
-+  },
-+};
-diff --git a/suite/buoy/modules/PanelMultiView.sys.mjs b/suite/buoy/modules/PanelMultiView.sys.mjs
-new file mode 100644
---- /dev/null
-+++ b/suite/buoy/modules/PanelMultiView.sys.mjs
-@@ -0,0 +1,1700 @@
-+/* 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/. */
-+
-+/**
-+ * Allows a popup panel to host multiple subviews. The main view shown when the
-+ * panel is opened may slide out to display a subview, which in turn may lead to
-+ * other subviews in a cascade menu pattern.
-+ *
-+ * The <panel> element should contain a <panelmultiview> element. Views are
-+ * declared using <panelview> elements that are usually children of the main
-+ * <panelmultiview> element, although they don't need to be, as views can also
-+ * be imported into the panel from other panels or popup sets.
-+ *
-+ * The panel should be opened asynchronously using the openPopup static method
-+ * on the PanelMultiView object. This will display the view specified using the
-+ * mainViewId attribute on the contained <panelmultiview> element.
-+ *
-+ * Specific subviews can slide in using the showSubView method, and backwards
-+ * navigation can be done using the goBack method or through a button in the
-+ * subview headers.
-+ *
-+ * The process of displaying the main view or a new subview requires multiple
-+ * steps to be completed, hence at any given time the <panelview> element may
-+ * be in different states:
-+ *
-+ * -- Open or closed
-+ *
-+ *    All the <panelview> elements start "closed", meaning that they are not
-+ *    associated to a <panelmultiview> element and can be located anywhere in
-+ *    the document. When the openPopup or showSubView methods are called, the
-+ *    relevant view becomes "open" and the <panelview> element may be moved to
-+ *    ensure it is a descendant of the <panelmultiview> element.
-+ *
-+ *    The "ViewShowing" event is fired at this point, when the view is not
-+ *    visible yet. The event is allowed to cancel the operation, in which case
-+ *    the view is closed immediately.
-+ *
-+ *    Closing the view does not move the node back to its original position.
-+ *
-+ * -- Visible or invisible
-+ *
-+ *    This indicates whether the view is visible in the document from a layout
-+ *    perspective, regardless of whether it is currently scrolled into view. In
-+ *    fact, all subviews are already visible before they start sliding in.
-+ *
-+ *    Before scrolling into view, a view may become visible but be placed in a
-+ *    special off-screen area of the document where layout and measurements can
-+ *    take place asynchronously.
-+ *
-+ *    When navigating forward, an open view may become invisible but stay open
-+ *    after sliding out of view. The last known size of these views is still
-+ *    taken into account for determining the overall panel size.
-+ *
-+ *    When navigating backwards, an open subview will first become invisible and
-+ *    then will be closed.
-+ *
-+ * -- Active or inactive
-+ *
-+ *    This indicates whether the view is fully scrolled into the visible area
-+ *    and ready to receive mouse and keyboard events. An active view is always
-+ *    visible, but a visible view may be inactive. For example, during a scroll
-+ *    transition, both views will be inactive.
-+ *
-+ *    When a view becomes active, the ViewShown event is fired synchronously,
-+ *    and the showSubView and goBack methods can be called for navigation.
-+ *
-+ *    For the main view of the panel, the ViewShown event is dispatched during
-+ *    the "popupshown" event, which means that other "popupshown" handlers may
-+ *    be called before the view is active. Thus, code that needs to perform
-+ *    further navigation automatically should either use the ViewShown event or
-+ *    wait for an event loop tick, like BrowserTestUtils.waitForEvent does.
-+ *
-+ * -- Navigating with the keyboard
-+ *
-+ *    An open view may keep state related to keyboard navigation, even if it is
-+ *    invisible. When a view is closed, keyboard navigation state is cleared.
-+ *
-+ * This diagram shows how <panelview> nodes move during navigation:
-+ *
-+ *   In this <panelmultiview>     In other panels    Action
-+ *             ┌───┬───┬───┐        ┌───┬───┐
-+ *             │(A)│ B │ C │        │ D │ E │          Open panel
-+ *             └───┴───┴───┘        └───┴───┘
-+ *         ┌───┬───┬───┐            ┌───┬───┐
-+ *         │{A}│(C)│ B │            │ D │ E │          Show subview C
-+ *         └───┴───┴───┘            └───┴───┘
-+ *     ┌───┬───┬───┬───┐            ┌───┐
-+ *     │{A}│{C}│(D)│ B │            │ E │              Show subview D
-+ *     └───┴───┴───┴───┘            └───┘
-+ *       │ ┌───┬───┬───┬───┐        ┌───┐
-+ *       │ │{A}│(C)│ D │ B │        │ E │              Go back
-+ *       │ └───┴───┴───┴───┘        └───┘
-+ *       │   │   │
-+ *       │   │   └── Currently visible view
-+ *       │   │   │
-+ *       └───┴───┴── Open views
-+ */
-+
-+const lazy = {};
-+
-+ChromeUtils.defineLazyGetter(lazy, "gBundle", function () {
-+  return Services.strings.createBundle(
-+    "chrome://messenger/locale/messenger.properties"
-+  );
-+});
-+
-+/**
-+ * Safety timeout after which asynchronous events will be canceled if any of the
-+ * registered blockers does not return.
-+ */
-+const BLOCKERS_TIMEOUT_MS = 10000;
-+
-+const TRANSITION_PHASES = Object.freeze({
-+  START: 1,
-+  PREPARE: 2,
-+  TRANSITION: 3,
-+});
-+
-+const gNodeToObjectMap = new WeakMap();
-+const gWindowsWithUnloadHandler = new WeakSet();
-+
-+/**
-+ * Allows associating an object to a node lazily using a weak map.
-+ *
-+ * Classes deriving from this one may be easily converted to Custom Elements,
-+ * although they would lose the ability of being associated lazily.
-+ */
-+var AssociatedToNode = class {
-+  constructor(node) {
-+    /**
-+     * Node associated to this object.
-+     */
-+    this.node = node;
-+
-+    /**
-+     * This promise is resolved when the current set of blockers set by event
-+     * handlers have all been processed.
-+     */
-+    this._blockersPromise = Promise.resolve();
-+  }
-+
-+  /**
-+   * Retrieves the instance associated with the given node, constructing a new
-+   * one if necessary. When the last reference to the node is released, the
-+   * object instance will be garbage collected as well.
-+   */
-+  static forNode(node) {
-+    let associatedToNode = gNodeToObjectMap.get(node);
-+    if (!associatedToNode) {
-+      associatedToNode = new this(node);
-+      gNodeToObjectMap.set(node, associatedToNode);
-+    }
-+    return associatedToNode;
-+  }
-+
-+  get document() {
-+    return this.node.ownerDocument;
-+  }
-+
-+  get window() {
-+    return this.node.ownerGlobal;
-+  }
-+
-+  _getBoundsWithoutFlushing(element) {
-+    return this.window.windowUtils.getBoundsWithoutFlushing(element);
-+  }
-+
-+  /**
-+   * Dispatches a custom event on this element.
-+   *
-+   * @param  {string}    eventName Name of the event to dispatch.
-+   * @param  {object}    [detail]  Event detail object. Optional.
-+   * @param  {boolean}   cancelable If the event can be canceled.
-+   * @returns {boolean} `true` if the event was canceled by an event handler, `false`
-+   *                   otherwise.
-+   */
-+  dispatchCustomEvent(eventName, detail, cancelable = false) {
-+    const event = new this.window.CustomEvent(eventName, {
-+      detail,
-+      bubbles: true,
-+      cancelable,
-+    });
-+    this.node.dispatchEvent(event);
-+    return event.defaultPrevented;
-+  }
-+
-+  /**
-+   * Dispatches a custom event on this element and waits for any blocking
-+   * promises registered using the "addBlocker" function on the details object.
-+   * If this function is called again, the event is only dispatched after all
-+   * the previously registered blockers have returned.
-+   *
-+   * The event can be canceled either by resolving any blocking promise to the
-+   * boolean value "false" or by calling preventDefault on the event. Rejections
-+   * and exceptions will be reported and will cancel the event.
-+   *
-+   * Blocking should be used sporadically because it slows down the interface.
-+   * Also, non-reentrancy is not strictly guaranteed because a safety timeout of
-+   * BLOCKERS_TIMEOUT_MS is implemented, after which the event will be canceled.
-+   * This helps to prevent deadlocks if any of the event handlers does not
-+   * resolve a blocker promise.
-+   *
-+   * @note Since there is no use case for dispatching different asynchronous
-+   *       events in parallel for the same element, this function will also wait
-+   *       for previous blockers when the event name is different.
-+   *
-+   * @param eventName
-+   *        Name of the custom event to dispatch.
-+   *
-+   * @resolves True if the event was canceled by a handler, false otherwise.
-+   */
-+  async dispatchAsyncEvent(eventName) {
-+    // Wait for all the previous blockers before dispatching the event.
-+    const blockersPromise = this._blockersPromise.catch(() => {});
-+    return (this._blockersPromise = blockersPromise.then(async () => {
-+      const blockers = new Set();
-+      let cancel = this.dispatchCustomEvent(
-+        eventName,
-+        {
-+          addBlocker(promise) {
-+            // Any exception in the blocker will cancel the operation.
-+            blockers.add(
-+              promise.catch(ex => {
-+                console.error(ex);
-+                return true;
-+              })
-+            );
-+          },
-+        },
-+        true
-+      );
-+      if (blockers.size) {
-+        const timeoutPromise = new Promise((resolve, reject) => {
-+          this.window.setTimeout(reject, BLOCKERS_TIMEOUT_MS);
-+        });
-+        try {
-+          const results = await Promise.race([
-+            Promise.all(blockers),
-+            timeoutPromise,
-+          ]);
-+          cancel = cancel || results.some(result => result === false);
-+        } catch (ex) {
-+          console.error(
-+            new Error(`One of the blockers for ${eventName} timed out.`)
-+          );
-+          return true;
-+        }
-+      }
-+      return cancel;
-+    }));
-+  }
-+};
-+
-+/**
-+ * This is associated to <panelmultiview> elements.
-+ */
-+export class PanelMultiView extends AssociatedToNode {
-+  /**
-+   * Tries to open the specified <panel> and displays the main view specified
-+   * with the "mainViewId" attribute on the <panelmultiview> node it contains.
-+   *
-+   * If the panel does not contain a <panelmultiview>, it is opened directly.
-+   * This allows consumers like page actions to accept different panel types.
-+   *
-+   * @see The non-static openPopup method for details.
-+   */
-+  static async openPopup(panelNode, ...args) {
-+    const panelMultiViewNode = panelNode.querySelector("panelmultiview");
-+    if (panelMultiViewNode) {
-+      return this.forNode(panelMultiViewNode).openPopup(...args);
-+    }
-+    panelNode.openPopup(...args);
-+    return true;
-+  }
-+
-+  /**
-+   * Closes the specified <panel> which contains a <panelmultiview> node.
-+   *
-+   * If the panel does not contain a <panelmultiview>, it is closed directly.
-+   * This allows consumers like page actions to accept different panel types.
-+   *
-+   * @see The non-static hidePopup method for details.
-+   */
-+  static hidePopup(panelNode) {
-+    const panelMultiViewNode = panelNode.querySelector("panelmultiview");
-+    if (panelMultiViewNode) {
-+      this.forNode(panelMultiViewNode).hidePopup();
-+    } else {
-+      panelNode.hidePopup();
-+    }
-+  }
-+
-+  /**
-+   * Removes the specified <panel> from the document, ensuring that any
-+   * <panelmultiview> node it contains is destroyed properly.
-+   *
-+   * If the viewCacheId attribute is present on the <panelmultiview> element,
-+   * imported subviews will be moved out again to the element it specifies, so
-+   * that the panel element can be removed safely.
-+   *
-+   * If the panel does not contain a <panelmultiview>, it is removed directly.
-+   * This allows consumers like page actions to accept different panel types.
-+   */
-+  static removePopup(panelNode) {
-+    try {
-+      const panelMultiViewNode = panelNode.querySelector("panelmultiview");
-+      if (panelMultiViewNode) {
-+        const panelMultiView = this.forNode(panelMultiViewNode);
-+        panelMultiView._moveOutKids();
-+        panelMultiView.disconnect();
-+      }
-+    } finally {
-+      // Make sure to remove the panel element even if disconnecting fails.
-+      panelNode.remove();
-+    }
-+  }
-+
-+  /**
-+   * Ensures that when the specified window is closed all the <panelmultiview>
-+   * node it contains are destroyed properly.
-+   */
-+  static ensureUnloadHandlerRegistered(window) {
-+    if (gWindowsWithUnloadHandler.has(window)) {
-+      return;
-+    }
-+
-+    window.addEventListener(
-+      "unload",
-+      () => {
-+        for (const panelMultiViewNode of window.document.querySelectorAll(
-+          "panelmultiview"
-+        )) {
-+          this.forNode(panelMultiViewNode).disconnect();
-+        }
-+      },
-+      { once: true }
-+    );
-+
-+    gWindowsWithUnloadHandler.add(window);
-+  }
-+
-+  get _panel() {
-+    return this.node.parentNode;
-+  }
-+
-+  set _transitioning(val) {
-+    if (val) {
-+      this.node.setAttribute("transitioning", "true");
-+    } else {
-+      this.node.removeAttribute("transitioning");
-+    }
-+  }
-+
-+  get _screenManager() {
-+    if (this.__screenManager) {
-+      return this.__screenManager;
-+    }
-+    return (this.__screenManager = Cc[
-+      "@mozilla.org/gfx/screenmanager;1"
-+    ].getService(Ci.nsIScreenManager));
-+  }
-+
-+  constructor(node) {
-+    super(node);
-+    this._openPopupPromise = Promise.resolve(false);
-+    this._openPopupCancelCallback = () => {};
-+  }
-+
-+  connect() {
-+    this.connected = true;
-+
-+    PanelMultiView.ensureUnloadHandlerRegistered(this.window);
-+
-+    const viewContainer = (this._viewContainer =
-+      this.document.createXULElement("box"));
-+    viewContainer.classList.add("panel-viewcontainer");
-+
-+    const viewStack = (this._viewStack = this.document.createXULElement("box"));
-+    viewStack.classList.add("panel-viewstack");
-+    viewContainer.append(viewStack);
-+
-+    const offscreenViewContainer = this.document.createXULElement("box");
-+    offscreenViewContainer.classList.add("panel-viewcontainer", "offscreen");
-+
-+    const offscreenViewStack = (this._offscreenViewStack =
-+      this.document.createXULElement("box"));
-+    offscreenViewStack.classList.add("panel-viewstack");
-+    offscreenViewContainer.append(offscreenViewStack);
-+
-+    this.node.prepend(offscreenViewContainer);
-+    this.node.prepend(viewContainer);
-+
-+    this.openViews = [];
-+
-+    this._panel.addEventListener("popupshowing", this);
-+    this._panel.addEventListener("popuppositioned", this);
-+    this._panel.addEventListener("popuphidden", this);
-+    this._panel.addEventListener("popupshown", this);
-+
-+    // Proxy these public properties and methods, as used elsewhere by various
-+    // parts of the browser, to this instance.
-+    ["goBack", "showSubView"].forEach(method => {
-+      Object.defineProperty(this.node, method, {
-+        enumerable: true,
-+        value: (...args) => this[method](...args),
-+      });
-+    });
-+  }
-+
-+  disconnect() {
-+    // Guard against re-entrancy.
-+    if (!this.node || !this.connected) {
-+      return;
-+    }
-+
-+    this._panel.removeEventListener("mousemove", this);
-+    this._panel.removeEventListener("popupshowing", this);
-+    this._panel.removeEventListener("popuppositioned", this);
-+    this._panel.removeEventListener("popupshown", this);
-+    this._panel.removeEventListener("popuphidden", this);
-+    this.window.removeEventListener("keydown", this, true);
-+    this.node =
-+      this._openPopupPromise =
-+      this._openPopupCancelCallback =
-+      this._viewContainer =
-+      this._viewStack =
-+      this._transitionDetails =
-+        null;
-+  }
-+
-+  /**
-+   * Tries to open the panel associated with this PanelMultiView, and displays
-+   * the main view specified with the "mainViewId" attribute.
-+   *
-+   * The hidePopup method can be called while the operation is in progress to
-+   * prevent the panel from being displayed. View events may also cancel the
-+   * operation, so there is no guarantee that the panel will become visible.
-+   *
-+   * The "popuphidden" event will be fired either when the operation is canceled
-+   * or when the popup is closed later. This event can be used for example to
-+   * reset the "open" state of the anchor or tear down temporary panels.
-+   *
-+   * If this method is called again before the panel is shown, the result
-+   * depends on the operation currently in progress. If the operation was not
-+   * canceled, the panel is opened using the arguments from the previous call,
-+   * and this call is ignored. If the operation was canceled, it will be
-+   * retried again using the arguments from this call.
-+   *
-+   * It's not necessary for the <panelmultiview> binding to be connected when
-+   * this method is called, but the containing panel must have its display
-+   * turned on, for example it shouldn't have the "hidden" attribute.
-+   *
-+   * @param anchor
-+   *        The node to anchor the popup to.
-+   * @param options
-+   *        Either options to use or a string position. This is forwarded to
-+   *        the openPopup method of the panel.
-+   * @param args
-+   *        Additional arguments to be forwarded to the openPopup method of the
-+   *        panel.
-+   *
-+   * @resolves With true as soon as the request to display the panel has been
-+   *           sent, or with false if the operation was canceled. The state of
-+   *           the panel at this point is not guaranteed. It may be still
-+   *           showing, completely shown, or completely hidden.
-+   * @rejects If an exception is thrown at any point in the process before the
-+   *          request to display the panel is sent.
-+   */
-+  async openPopup(anchor, options, ...args) {
-+    // Set up the function that allows hidePopup or a second call to showPopup
-+    // to cancel the specific panel opening operation that we're starting below.
-+    // This function must be synchronous, meaning we can't use Promise.race,
-+    // because hidePopup wants to dispatch the "popuphidden" event synchronously
-+    // even if the panel has not been opened yet.
-+    let canCancel = true;
-+    const cancelCallback = (this._openPopupCancelCallback = () => {
-+      // If the cancel callback is called and the panel hasn't been prepared
-+      // yet, cancel showing it. Setting canCancel to false will prevent the
-+      // popup from opening. If the panel has opened by the time the cancel
-+      // callback is called, canCancel will be false already, and we will not
-+      // fire the "popuphidden" event.
-+      if (canCancel && this.node) {
-+        canCancel = false;
-+        this.dispatchCustomEvent("popuphidden");
-+      }
-+    });
-+
-+    // Create a promise that is resolved with the result of the last call to
-+    // this method, where errors indicate that the panel was not opened.
-+    const openPopupPromise = this._openPopupPromise.catch(() => {
-+      return false;
-+    });
-+
-+    // Make the preparation done before showing the panel non-reentrant. The
-+    // promise created here will be resolved only after the panel preparation is
-+    // completed, even if a cancellation request is received in the meantime.
-+    return (this._openPopupPromise = openPopupPromise.then(async wasShown => {
-+      // The panel may have been destroyed in the meantime.
-+      if (!this.node) {
-+        return false;
-+      }
-+      // If the panel has been already opened there is nothing more to do. We
-+      // check the actual state of the panel rather than setting some state in
-+      // our handler of the "popuphidden" event because this has a lower chance
-+      // of locking indefinitely if events aren't raised in the expected order.
-+      if (wasShown && ["open", "showing"].includes(this._panel.state)) {
-+        return true;
-+      }
-+      try {
-+        if (!this.connected) {
-+          this.connect();
-+        }
-+        // Allow any of the ViewShowing handlers to prevent showing the main view.
-+        if (!(await this._showMainView())) {
-+          cancelCallback();
-+        }
-+      } catch (ex) {
-+        cancelCallback();
-+        throw ex;
-+      }
-+      // If a cancellation request was received there is nothing more to do.
-+      if (!canCancel || !this.node) {
-+        return false;
-+      }
-+      // We have to set canCancel to false before opening the popup because the
-+      // hidePopup method of PanelMultiView can be re-entered by event handlers.
-+      // If the openPopup call fails, however, we still have to dispatch the
-+      // "popuphidden" event even if canCancel was set to false.
-+      try {
-+        canCancel = false;
-+        this._panel.openPopup(anchor, options, ...args);
-+
-+        // On Windows, if another popup is hiding while we call openPopup, the
-+        // call won't fail but the popup won't open. In this case, we have to
-+        // dispatch an artificial "popuphidden" event to reset our state.
-+        if (this._panel.state == "closed" && this.openViews.length) {
-+          this.dispatchCustomEvent("popuphidden");
-+          return false;
-+        }
-+
-+        if (
-+          options &&
-+          typeof options == "object" &&
-+          options.triggerEvent &&
-+          options.triggerEvent.type == "keypress" &&
-+          this.openViews.length
-+        ) {
-+          // This was opened via the keyboard, so focus the first item.
-+          this.openViews[0].focusWhenActive = true;
-+        }
-+
-+        return true;
-+      } catch (ex) {
-+        this.dispatchCustomEvent("popuphidden");
-+        throw ex;
-+      }
-+    }));
-+  }
-+
-+  /**
-+   * Closes the panel associated with this PanelMultiView.
-+   *
-+   * If the openPopup method was called but the panel has not been displayed
-+   * yet, the operation is canceled and the panel will not be displayed, but the
-+   * "popuphidden" event is fired synchronously anyways.
-+   *
-+   * This means that by the time this method returns all the operations handled
-+   * by the "popuphidden" event are completed, for example resetting the "open"
-+   * state of the anchor, and the panel is already invisible.
-+   */
-+  hidePopup() {
-+    if (!this.node || !this.connected) {
-+      return;
-+    }
-+
-+    // If we have already reached the _panel.openPopup call in the openPopup
-+    // method, we can call hidePopup. Otherwise, we have to cancel the latest
-+    // request to open the panel, which will have no effect if the request has
-+    // been canceled already.
-+    if (["open", "showing"].includes(this._panel.state)) {
-+      this._panel.hidePopup();
-+    } else {
-+      this._openPopupCancelCallback();
-+    }
-+
-+    // We close all the views synchronously, so that they are ready to be opened
-+    // in other PanelMultiView instances. The "popuphidden" handler may also
-+    // call this function, but the second time openViews will be empty.
-+    this.closeAllViews();
-+  }
-+
-+  /**
-+   * Move any child subviews into the element defined by "viewCacheId" to make
-+   * sure they will not be removed together with the <panelmultiview> element.
-+   */
-+  _moveOutKids() {
-+    const viewCacheId = this.node.getAttribute("viewCacheId");
-+    if (!viewCacheId) {
-+      return;
-+    }
-+
-+    // Node.children and Node.children is live to DOM changes like the
-+    // ones we're about to do, so iterate over a static copy:
-+    const subviews = Array.from(this._viewStack.children);
-+    const viewCache = this.document.getElementById(viewCacheId);
-+    for (const subview of subviews) {
-+      viewCache.appendChild(subview);
-+    }
-+  }
-+
-+  /**
-+   * Slides in the specified view as a subview.
-+   *
-+   * @param viewIdOrNode
-+   *        DOM element or string ID of the <panelview> to display.
-+   * @param anchor
-+   *        DOM element that triggered the subview, which will be highlighted
-+   *        and whose "label" attribute will be used for the title of the
-+   *        subview when a "title" attribute is not specified.
-+   */
-+  showSubView(viewIdOrNode, anchor) {
-+    this._showSubView(viewIdOrNode, anchor).catch(console.error);
-+  }
-+  async _showSubView(viewIdOrNode, anchor) {
-+    const viewNode =
-+      typeof viewIdOrNode == "string"
-+        ? this.document.getElementById(viewIdOrNode)
-+        : viewIdOrNode;
-+    if (!viewNode) {
-+      console.error(new Error(`Subview ${viewIdOrNode} doesn't exist.`));
-+      return;
-+    }
-+
-+    if (!this.openViews.length) {
-+      console.error(new Error(`Cannot show a subview in a closed panel.`));
-+      return;
-+    }
-+
-+    const prevPanelView = this.openViews[this.openViews.length - 1];
-+    const nextPanelView = PanelView.forNode(viewNode);
-+    if (this.openViews.includes(nextPanelView)) {
-+      console.error(new Error(`Subview ${viewNode.id} is already open.`));
-+      return;
-+    }
-+
-+    // Do not re-enter the process if navigation is already in progress. Since
-+    // there is only one active view at any given time, we can do this check
-+    // safely, even considering that during the navigation process the actual
-+    // view to which prevPanelView refers will change.
-+    if (!prevPanelView.active) {
-+      return;
-+    }
-+    // If prevPanelView._doingKeyboardActivation is true, it will be reset to
-+    // false synchronously. Therefore, we must capture it before we use any
-+    // "await" statements.
-+    const doingKeyboardActivation = prevPanelView._doingKeyboardActivation;
-+    // Marking the view that is about to scrolled out of the visible area as
-+    // inactive will prevent re-entrancy and also disable keyboard navigation.
-+    // From this point onwards, "await" statements can be used safely.
-+    prevPanelView.active = false;
-+
-+    // Provide visual feedback while navigation is in progress, starting before
-+    // the transition starts and ending when the previous view is invisible.
-+    if (anchor) {
-+      anchor.setAttribute("open", "true");
-+    }
-+    try {
-+      // If the ViewShowing event cancels the operation we have to re-enable
-+      // keyboard navigation, but this must be avoided if the panel was closed.
-+      if (!(await this._openView(nextPanelView))) {
-+        if (prevPanelView.isOpenIn(this)) {
-+          // We don't raise a ViewShown event because nothing actually changed.
-+          // Technically we should use a different state flag just because there
-+          // is code that could check the "active" property to determine whether
-+          // to wait for a ViewShown event later, but this only happens in
-+          // regression tests and is less likely to be a technique used in
-+          // production code, where use of ViewShown is less common.
-+          prevPanelView.active = true;
-+        }
-+        return;
-+      }
-+
-+      prevPanelView.captureKnownSize();
-+
-+      // The main view of a panel can be a subview in another one. Make sure to
-+      // reset all the properties that may be set on a subview.
-+      nextPanelView.mainview = false;
-+      // The header may change based on how the subview was opened.
-+      nextPanelView.headerText =
-+        viewNode.getAttribute("title") ||
-+        (anchor && anchor.getAttribute("label"));
-+      // The constrained width of subviews may also vary between panels.
-+      nextPanelView.minMaxWidth = prevPanelView.knownWidth;
-+
-+      if (anchor) {
-+        viewNode.classList.add("PanelUI-subView");
-+      }
-+
-+      await this._transitionViews(prevPanelView.node, viewNode, false, anchor);
-+    } finally {
-+      if (anchor) {
-+        anchor.removeAttribute("open");
-+      }
-+    }
-+
-+    nextPanelView.focusWhenActive = doingKeyboardActivation;
-+    this._activateView(nextPanelView);
-+  }
-+
-+  /**
-+   * Navigates backwards by sliding out the most recent subview.
-+   */
-+  goBack() {
-+    this._goBack().catch(console.error);
-+  }
-+  async _goBack() {
-+    if (this.openViews.length < 2) {
-+      // This may be called by keyboard navigation or external code when only
-+      // the main view is open.
-+      return;
-+    }
-+
-+    const prevPanelView = this.openViews[this.openViews.length - 1];
-+    const nextPanelView = this.openViews[this.openViews.length - 2];
-+
-+    // Like in the showSubView method, do not re-enter navigation while it is
-+    // in progress, and make the view inactive immediately. From this point
-+    // onwards, "await" statements can be used safely.
-+    if (!prevPanelView.active) {
-+      return;
-+    }
-+
-+    prevPanelView.active = false;
-+
-+    prevPanelView.captureKnownSize();
-+
-+    await this._transitionViews(prevPanelView.node, nextPanelView.node, true);
-+
-+    this._closeLatestView();
-+
-+    this._activateView(nextPanelView);
-+  }
-+
-+  /**
-+   * Prepares the main view before showing the panel.
-+   */
-+  async _showMainView() {
-+    const nextPanelView = PanelView.forNode(
-+      this.document.getElementById(this.node.getAttribute("mainViewId"))
-+    );
-+
-+    // If the view is already open in another panel, close the panel first.
-+    const oldPanelMultiViewNode = nextPanelView.node.panelMultiView;
-+    if (oldPanelMultiViewNode) {
-+      PanelMultiView.forNode(oldPanelMultiViewNode).hidePopup();
-+      // Wait for a layout flush after hiding the popup, otherwise the view may
-+      // not be displayed correctly for some time after the new panel is opened.
-+      // This is filed as bug 1441015.
-+      await this.window.promiseDocumentFlushed(() => {});
-+    }
-+
-+    if (!(await this._openView(nextPanelView))) {
-+      return false;
-+    }
-+
-+    // The main view of a panel can be a subview in another one. Make sure to
-+    // reset all the properties that may be set on a subview.
-+    nextPanelView.mainview = true;
-+    nextPanelView.headerText = "";
-+    nextPanelView.minMaxWidth = 0;
-+
-+    // Ensure the view will be visible once the panel is opened.
-+    nextPanelView.visible = true;
-+
-+    return true;
-+  }
-+
-+  /**
-+   * Opens the specified PanelView and dispatches the ViewShowing event, which
-+   * can be used to populate the subview or cancel the operation.
-+   *
-+   * This also clears all the attributes and styles that may be left by a
-+   * transition that was interrupted.
-+   *
-+   * @resolves With true if the view was opened, false otherwise.
-+   */
-+  async _openView(panelView) {
-+    if (panelView.node.parentNode != this._viewStack) {
-+      this._viewStack.appendChild(panelView.node);
-+    }
-+
-+    panelView.node.panelMultiView = this.node;
-+    this.openViews.push(panelView);
-+
-+    const canceled = await panelView.dispatchAsyncEvent("ViewShowing");
-+
-+    // The panel can be hidden while we are processing the ViewShowing event.
-+    // This results in all the views being closed synchronously, and at this
-+    // point the ViewHiding event has already been dispatched for all of them.
-+    if (!this.openViews.length) {
-+      return false;
-+    }
-+
-+    // Check if the event requested cancellation but the panel is still open.
-+    if (canceled) {
-+      // Handlers for ViewShowing can't know if a different handler requested
-+      // cancellation, so this will dispatch a ViewHiding event to give a chance
-+      // to clean up.
-+      this._closeLatestView();
-+      return false;
-+    }
-+
-+    // Clean up all the attributes and styles related to transitions. We do this
-+    // here rather than when the view is closed because we are likely to make
-+    // other DOM modifications soon, which isn't the case when closing.
-+    const { style } = panelView.node;
-+    style.removeProperty("outline");
-+    style.removeProperty("width");
-+
-+    return true;
-+  }
-+
-+  /**
-+   * Activates the specified view and raises the ViewShown event, unless the
-+   * view was closed in the meantime.
-+   */
-+  _activateView(panelView) {
-+    if (panelView.isOpenIn(this)) {
-+      panelView.active = true;
-+      if (panelView.focusWhenActive) {
-+        panelView.focusFirstNavigableElement(false, true);
-+        panelView.focusWhenActive = false;
-+      }
-+      panelView.dispatchCustomEvent("ViewShown");
-+    }
-+  }
-+
-+  /**
-+   * Closes the most recent PanelView and raises the ViewHiding event.
-+   *
-+   * @note The ViewHiding event is not cancelable and should probably be renamed
-+   *       to ViewHidden or ViewClosed instead, see bug 1438507.
-+   */
-+  _closeLatestView() {
-+    const panelView = this.openViews.pop();
-+    panelView.clearNavigation();
-+    panelView.dispatchCustomEvent("ViewHiding");
-+    panelView.node.panelMultiView = null;
-+    // Views become invisible synchronously when they are closed, and they won't
-+    // become visible again until they are opened. When this is called at the
-+    // end of backwards navigation, the view is already invisible.
-+    panelView.visible = false;
-+  }
-+
-+  /**
-+   * Closes all the views that are currently open.
-+   */
-+  closeAllViews() {
-+    // Raise ViewHiding events for open views in reverse order.
-+    while (this.openViews.length) {
-+      this._closeLatestView();
-+    }
-+  }
-+
-+  /**
-+   * Apply a transition to 'slide' from the currently active view to the next
-+   * one.
-+   * Sliding the next subview in means that the previous panelview stays where it
-+   * is and the active panelview slides in from the left in LTR mode, right in
-+   * RTL mode.
-+   *
-+   * @param {panelview} previousViewNode Node that is currently displayed, but
-+   *                                     is about to be transitioned away. This
-+   *                                     must be already inactive at this point.
-+   * @param {panelview} viewNode - Node that will becode the active view,
-+   *                                     after the transition has finished.
-+   * @param {boolean}   reverse          Whether we're navigation back to a
-+   *                                     previous view or forward to a next view.
-+   */
-+  async _transitionViews(previousViewNode, viewNode, reverse) {
-+    const { window } = this;
-+
-+    const nextPanelView = PanelView.forNode(viewNode);
-+    const prevPanelView = PanelView.forNode(previousViewNode);
-+
-+    const details = (this._transitionDetails = {
-+      phase: TRANSITION_PHASES.START,
-+    });
-+
-+    // Set the viewContainer dimensions to make sure only the current view is
-+    // visible.
-+    const olderView = reverse ? nextPanelView : prevPanelView;
-+    this._viewContainer.style.minHeight = olderView.knownHeight + "px";
-+    this._viewContainer.style.height = prevPanelView.knownHeight + "px";
-+    this._viewContainer.style.width = prevPanelView.knownWidth + "px";
-+    // Lock the dimensions of the window that hosts the popup panel.
-+    const rect = this._getBoundsWithoutFlushing(this._panel);
-+    this._panel.style.width = rect.width + "px";
-+    this._panel.style.height = rect.height + "px";
-+
-+    let viewRect;
-+    if (reverse) {
-+      // Use the cached size when going back to a previous view, but not when
-+      // reopening a subview, because its contents may have changed.
-+      viewRect = {
-+        width: nextPanelView.knownWidth,
-+        height: nextPanelView.knownHeight,
-+      };
-+      nextPanelView.visible = true;
-+    } else if (viewNode.customRectGetter) {
-+      // We use a customRectGetter for WebExtensions panels, because they need
-+      // to query the size from an embedded browser. The presence of this
-+      // getter also provides an indication that the view node shouldn't be
-+      // moved around, otherwise the state of the browser would get disrupted.
-+      const width = prevPanelView.knownWidth;
-+      const height = prevPanelView.knownHeight;
-+      viewRect = Object.assign({ height, width }, viewNode.customRectGetter());
-+      nextPanelView.visible = true;
-+      // Until the header is visible, it has 0 height.
-+      // Wait for layout before measuring it
-+      const header = viewNode.firstElementChild;
-+      if (header && header.classList.contains("panel-header")) {
-+        viewRect.height += await window.promiseDocumentFlushed(() => {
-+          return this._getBoundsWithoutFlushing(header).height;
-+        });
-+      }
-+    } else {
-+      this._offscreenViewStack.style.minHeight = olderView.knownHeight + "px";
-+      this._offscreenViewStack.appendChild(viewNode);
-+      nextPanelView.visible = true;
-+
-+      viewRect = await window.promiseDocumentFlushed(() => {
-+        return this._getBoundsWithoutFlushing(viewNode);
-+      });
-+      // Bail out if the panel was closed in the meantime.
-+      if (!nextPanelView.isOpenIn(this)) {
-+        return;
-+      }
-+
-+      // Place back the view after all the other views that are already open in
-+      // order for the transition to work as expected.
-+      this._viewStack.appendChild(viewNode);
-+
-+      this._offscreenViewStack.style.removeProperty("min-height");
-+    }
-+
-+    this._transitioning = true;
-+    details.phase = TRANSITION_PHASES.PREPARE;
-+
-+    // The 'magic' part: build up the amount of pixels to move right or left.
-+    const moveToLeft =
-+      (this.window.RTL_UI && !reverse) || (!this.window.RTL_UI && reverse);
-+    const deltaX = prevPanelView.knownWidth;
-+    const deepestNode = reverse ? previousViewNode : viewNode;
-+
-+    // With a transition when navigating backwards - user hits the 'back'
-+    // button - we need to make sure that the views are positioned in a way
-+    // that a translateX() unveils the previous view from the right direction.
-+    if (reverse) {
-+      this._viewStack.style.marginInlineStart = "-" + deltaX + "px";
-+    }
-+
-+    // Set the transition style and listen for its end to clean up and make sure
-+    // the box sizing becomes dynamic again.
-+    // Somehow, putting these properties in PanelUI.css doesn't work for newly
-+    // shown nodes in a XUL parent node.
-+    this._viewStack.style.transition =
-+      "transform var(--animation-easing-function)" +
-+      " var(--panelui-subview-transition-duration)";
-+    this._viewStack.style.willChange = "transform";
-+    // Use an outline instead of a border so that the size is not affected.
-+    deepestNode.style.outline = "1px solid var(--panel-separator-color)";
-+
-+    // Now that all the elements are in place for the start of the transition,
-+    // give the layout code a chance to set the initial values.
-+    await window.promiseDocumentFlushed(() => {});
-+    // Bail out if the panel was closed in the meantime.
-+    if (!nextPanelView.isOpenIn(this)) {
-+      return;
-+    }
-+
-+    // Now set the viewContainer dimensions to that of the new view, which
-+    // kicks of the height animation.
-+    this._viewContainer.style.height = viewRect.height + "px";
-+    this._viewContainer.style.width = viewRect.width + "px";
-+    this._panel.style.removeProperty("width");
-+    this._panel.style.removeProperty("height");
-+
-+    // We're setting the width property to prevent flickering during the
-+    // sliding animation with smaller views.
-+    viewNode.style.width = viewRect.width + "px";
-+
-+    // Kick off the transition!
-+    details.phase = TRANSITION_PHASES.TRANSITION;
-+
-+    // If we're going to show the main view, we can remove the
-+    // min-height property on the view container.
-+    if (viewNode.getAttribute("mainview")) {
-+      this._viewContainer.style.removeProperty("min-height");
-+    }
-+
-+    this._viewStack.style.transform =
-+      "translateX(" + (moveToLeft ? "" : "-") + deltaX + "px)";
-+
-+    await new Promise(resolve => {
-+      details.resolve = resolve;
-+      this._viewContainer.addEventListener(
-+        "transitionend",
-+        (details.listener = ev => {
-+          // It's quite common that `height` on the view container doesn't need
-+          // to transition, so we make sure to do all the work on the transform
-+          // transition-end, because that is guaranteed to happen.
-+          if (ev.target != this._viewStack || ev.propertyName != "transform") {
-+            return;
-+          }
-+          this._viewContainer.removeEventListener(
-+            "transitionend",
-+            details.listener
-+          );
-+          delete details.listener;
-+          resolve();
-+        })
-+      );
-+      this._viewContainer.addEventListener(
-+        "transitioncancel",
-+        (details.cancelListener = ev => {
-+          if (ev.target != this._viewStack) {
-+            return;
-+          }
-+          this._viewContainer.removeEventListener(
-+            "transitioncancel",
-+            details.cancelListener
-+          );
-+          delete details.cancelListener;
-+          resolve();
-+        })
-+      );
-+    });
-+
-+    // Bail out if the panel was closed during the transition.
-+    if (!nextPanelView.isOpenIn(this)) {
-+      return;
-+    }
-+    prevPanelView.visible = false;
-+
-+    // This will complete the operation by removing any transition properties.
-+    nextPanelView.node.style.removeProperty("width");
-+    deepestNode.style.removeProperty("outline");
-+    this._cleanupTransitionPhase();
-+
-+    nextPanelView.focusSelectedElement();
-+  }
-+
-+  /**
-+   * Attempt to clean up the attributes and properties set by `_transitionViews`
-+   * above. Which attributes and properties depends on the phase the transition
-+   * was left from.
-+   */
-+  _cleanupTransitionPhase() {
-+    if (!this._transitionDetails) {
-+      return;
-+    }
-+
-+    const { phase, resolve, listener, cancelListener } =
-+      this._transitionDetails;
-+    this._transitionDetails = null;
-+
-+    if (phase >= TRANSITION_PHASES.START) {
-+      this._panel.style.removeProperty("width");
-+      this._panel.style.removeProperty("height");
-+      this._viewContainer.style.removeProperty("height");
-+      this._viewContainer.style.removeProperty("width");
-+    }
-+    if (phase >= TRANSITION_PHASES.PREPARE) {
-+      this._transitioning = false;
-+      this._viewStack.style.removeProperty("margin-inline-start");
-+      this._viewStack.style.removeProperty("transition");
-+    }
-+    if (phase >= TRANSITION_PHASES.TRANSITION) {
-+      this._viewStack.style.removeProperty("transform");
-+      if (listener) {
-+        this._viewContainer.removeEventListener("transitionend", listener);
-+      }
-+      if (cancelListener) {
-+        this._viewContainer.removeEventListener(
-+          "transitioncancel",
-+          cancelListener
-+        );
-+      }
-+      if (resolve) {
-+        resolve();
-+      }
-+    }
-+  }
-+
-+  _calculateMaxHeight(aEvent) {
-+    // While opening the panel, we have to limit the maximum height of any
-+    // view based on the space that will be available. We cannot just use
-+    // window.screen.availTop and availHeight because these may return an
-+    // incorrect value when the window spans multiple screens.
-+    const anchor = this._panel.anchorNode;
-+    const anchorRect = anchor.getBoundingClientRect();
-+
-+    const screen = this._screenManager.screenForRect(
-+      anchor.screenX,
-+      anchor.screenY,
-+      anchorRect.width,
-+      anchorRect.height
-+    );
-+    const availTop = {},
-+      availHeight = {};
-+    screen.GetAvailRect({}, availTop, {}, availHeight);
-+    const cssAvailTop = availTop.value / screen.defaultCSSScaleFactor;
-+
-+    // The distance from the anchor to the available margin of the screen is
-+    // based on whether the panel will open towards the top or the bottom.
-+    let maxHeight;
-+    if (aEvent.alignmentPosition.startsWith("before_")) {
-+      maxHeight = anchor.screenY - cssAvailTop;
-+    } else {
-+      const anchorScreenBottom = anchor.screenY + anchorRect.height;
-+      const cssAvailHeight = availHeight.value / screen.defaultCSSScaleFactor;
-+      maxHeight = cssAvailTop + cssAvailHeight - anchorScreenBottom;
-+    }
-+
-+    // To go from the maximum height of the panel to the maximum height of
-+    // the view stack, we need to subtract the height of the arrow and the
-+    // height of the opposite margin, but we cannot get their actual values
-+    // because the panel is not visible yet. However, we know that this is
-+    // currently 11px on Mac, 13px on Windows, and 13px on Linux. We also
-+    // want an extra margin, both for visual reasons and to prevent glitches
-+    // due to small rounding errors. So, we just use a value that makes
-+    // sense for all platforms. If the arrow visuals change significantly,
-+    // this value will be easy to adjust.
-+    const EXTRA_MARGIN_PX = 20;
-+    maxHeight -= EXTRA_MARGIN_PX;
-+    return maxHeight;
-+  }
-+
-+  handleEvent(aEvent) {
-+    // Only process actual popup events from the panel or events we generate
-+    // ourselves, but not from menus being shown from within the panel.
-+    if (
-+      aEvent.type.startsWith("popup") &&
-+      aEvent.target != this._panel &&
-+      aEvent.target != this.node
-+    ) {
-+      return;
-+    }
-+    switch (aEvent.type) {
-+      case "keydown":
-+        // Since we start listening for the "keydown" event when the popup is
-+        // already showing and stop listening when the panel is hidden, we
-+        // always have at least one view open.
-+        const currentView = this.openViews[this.openViews.length - 1];
-+        currentView.keyNavigation(aEvent);
-+        break;
-+      case "mousemove":
-+        this.openViews.forEach(panelView => panelView.clearNavigation());
-+        break;
-+      case "popupshowing": {
-+        this._viewContainer.setAttribute("panelopen", "true");
-+        if (!this.node.hasAttribute("disablekeynav")) {
-+          // We add the keydown handler on the window so that it handles key
-+          // presses when a panel appears but doesn't get focus, as happens
-+          // when a button to open a panel is clicked with the mouse.
-+          // However, this means the listener is on an ancestor of the panel,
-+          // which means that handlers such as ToolbarKeyboardNavigator are
-+          // deeper in the tree. Therefore, this must be a capturing listener
-+          // so we get the event first.
-+          this.window.addEventListener("keydown", this, true);
-+          this._panel.addEventListener("mousemove", this);
-+        }
-+        break;
-+      }
-+      case "popuppositioned": {
-+        if (this._panel.state == "showing") {
-+          const maxHeight = this._calculateMaxHeight(aEvent);
-+          this._viewStack.style.maxHeight = maxHeight + "px";
-+          this._offscreenViewStack.style.maxHeight = maxHeight + "px";
-+        }
-+        break;
-+      }
-+      case "popupshown":
-+        // The main view is always open and visible when the panel is first
-+        // shown, so we can check the height of the description elements it
-+        // contains and notify consumers using the ViewShown event. In order to
-+        // minimize flicker we need to allow synchronous reflows, and we still
-+        // make sure the ViewShown event is dispatched synchronously.
-+        const mainPanelView = this.openViews[0];
-+        this._activateView(mainPanelView);
-+        break;
-+      case "popuphidden": {
-+        // WebExtensions consumers can hide the popup from viewshowing, or
-+        // mid-transition, which disrupts our state:
-+        this._transitioning = false;
-+        this._viewContainer.removeAttribute("panelopen");
-+        this._cleanupTransitionPhase();
-+        this.window.removeEventListener("keydown", this, true);
-+        this._panel.removeEventListener("mousemove", this);
-+        this.closeAllViews();
-+
-+        // Clear the main view size caches. The dimensions could be different
-+        // when the popup is opened again, e.g. through touch mode sizing.
-+        this._viewContainer.style.removeProperty("min-height");
-+        this._viewStack.style.removeProperty("max-height");
-+        this._viewContainer.style.removeProperty("width");
-+        this._viewContainer.style.removeProperty("height");
-+
-+        this.dispatchCustomEvent("PanelMultiViewHidden");
-+        break;
-+      }
-+    }
-+  }
-+}
-+
-+/**
-+ * This is associated to <panelview> elements.
-+ */
-+export class PanelView extends AssociatedToNode {
-+  constructor(node) {
-+    super(node);
-+
-+    /**
-+     * Indicates whether the view is active. When this is false, consumers can
-+     * wait for the ViewShown event to know when the view becomes active.
-+     */
-+    this.active = false;
-+
-+    /**
-+     * Specifies whether the view should be focused when active. When this
-+     * is true, the first navigable element in the view will be focused
-+     * when the view becomes active. This should be set to true when the view
-+     * is activated from the keyboard. It will be set to false once the view
-+     * is active.
-+     */
-+    this.focusWhenActive = false;
-+  }
-+
-+  /**
-+   * Indicates whether the view is open in the specified PanelMultiView object.
-+   */
-+  isOpenIn(panelMultiView) {
-+    return this.node.panelMultiView == panelMultiView.node;
-+  }
-+
-+  /**
-+   * The "mainview" attribute is set before the panel is opened when this view
-+   * is displayed as the main view, and is removed before the <panelview> is
-+   * displayed as a subview. The same view element can be displayed as a main
-+   * view and as a subview at different times.
-+   */
-+  set mainview(value) {
-+    if (value) {
-+      this.node.setAttribute("mainview", true);
-+    } else {
-+      this.node.removeAttribute("mainview");
-+    }
-+  }
-+
-+  /**
-+   * Determines whether the view is visible. Setting this to false also resets
-+   * the "active" property.
-+   */
-+  set visible(value) {
-+    if (value) {
-+      this.node.setAttribute("visible", true);
-+    } else {
-+      this.node.removeAttribute("visible");
-+      this.active = false;
-+      this.focusWhenActive = false;
-+    }
-+  }
-+
-+  /**
-+   * Constrains the width of this view using the "min-width" and "max-width"
-+   * styles. Setting this to zero removes the constraints.
-+   */
-+  set minMaxWidth(value) {
-+    const style = this.node.style;
-+    if (value) {
-+      style.minWidth = style.maxWidth = value + "px";
-+    } else {
-+      style.removeProperty("min-width");
-+      style.removeProperty("max-width");
-+    }
-+  }
-+
-+  /**
-+   * Adds a header with the given title, or removes it if the title is empty.
-+   */
-+  set headerText(value) {
-+    // If the header already exists, update or remove it as requested.
-+    let header = this.node.firstElementChild;
-+    if (header && header.classList.contains("panel-header")) {
-+      if (value) {
-+        header.querySelector(".panel-header > h1 > span").textContent = value;
-+      } else {
-+        header.remove();
-+      }
-+      return;
-+    }
-+
-+    // The header doesn't exist, only create it if needed.
-+    if (!value) {
-+      return;
-+    }
-+
-+    header = this.document.createXULElement("box");
-+    header.classList.add("panel-header");
-+
-+    const backButton = this.document.createXULElement("toolbarbutton");
-+    backButton.className =
-+      "subviewbutton subviewbutton-iconic subviewbutton-back";
-+    backButton.setAttribute("closemenu", "none");
-+    backButton.setAttribute("tabindex", "0");
-+
-+    backButton.setAttribute(
-+      "aria-label",
-+      lazy.gBundle.GetStringFromName("panel.back")
-+    );
-+
-+    backButton.addEventListener("command", () => {
-+      // The panelmultiview element may change if the view is reused.
-+      this.node.panelMultiView.goBack();
-+      backButton.blur();
-+    });
-+
-+    const h1 = this.document.createElement("h1");
-+    const span = this.document.createElement("span");
-+    span.textContent = value;
-+    h1.appendChild(span);
-+
-+    header.append(backButton, h1);
-+    this.node.prepend(header);
-+  }
-+
-+  /**
-+   * Populates the "knownWidth" and "knownHeight" properties with the current
-+   * dimensions of the view. These may be zero if the view is invisible.
-+   *
-+   * These values are relevant during transitions and are retained for backwards
-+   * navigation if the view is still open but is invisible.
-+   */
-+  captureKnownSize() {
-+    const rect = this._getBoundsWithoutFlushing(this.node);
-+    this.knownWidth = rect.width;
-+    this.knownHeight = rect.height;
-+  }
-+
-+  /**
-+   * Determine whether an element can only be navigated to with tab/shift+tab,
-+   * not the arrow keys.
-+   */
-+  _isNavigableWithTabOnly(element) {
-+    const tag = element.localName;
-+    return (
-+      tag == "menulist" ||
-+      tag == "input" ||
-+      tag == "textarea" ||
-+      // Allow tab to reach embedded documents in extension panels.
-+      tag == "browser"
-+    );
-+  }
-+
-+  /**
-+   * Make a TreeWalker for keyboard navigation.
-+   *
-+   * @param {boolean} arrowKey If `true`, elements only navigable with tab are
-+   *        excluded.
-+   */
-+  _makeNavigableTreeWalker(arrowKey) {
-+    const filter = node => {
-+      if (node.disabled) {
-+        return NodeFilter.FILTER_REJECT;
-+      }
-+      const bounds = this._getBoundsWithoutFlushing(node);
-+      if (bounds.width == 0 || bounds.height == 0) {
-+        return NodeFilter.FILTER_REJECT;
-+      }
-+      if (
-+        node.tagName == "button" ||
-+        node.tagName == "toolbarbutton" ||
-+        node.classList.contains("text-link") ||
-+        (!arrowKey && this._isNavigableWithTabOnly(node))
-+      ) {
-+        // Set the tabindex attribute to make sure the node is focusable.
-+        if (!node.hasAttribute("tabindex")) {
-+          node.setAttribute("tabindex", "-1");
-+        }
-+        return NodeFilter.FILTER_ACCEPT;
-+      }
-+      return NodeFilter.FILTER_SKIP;
-+    };
-+    return this.document.createTreeWalker(
-+      this.node,
-+      NodeFilter.SHOW_ELEMENT,
-+      filter
-+    );
-+  }
-+
-+  /**
-+   * Get a TreeWalker which finds elements navigable with tab/shift+tab.
-+   */
-+  get _tabNavigableWalker() {
-+    if (!this.__tabNavigableWalker) {
-+      this.__tabNavigableWalker = this._makeNavigableTreeWalker(false);
-+    }
-+    return this.__tabNavigableWalker;
-+  }
-+
-+  /**
-+   * Get a TreeWalker which finds elements navigable with up/down arrow keys.
-+   */
-+  get _arrowNavigableWalker() {
-+    if (!this.__arrowNavigableWalker) {
-+      this.__arrowNavigableWalker = this._makeNavigableTreeWalker(true);
-+    }
-+    return this.__arrowNavigableWalker;
-+  }
-+
-+  /**
-+   * Element that is currently selected with the keyboard, or null if no element
-+   * is selected. Since the reference is held weakly, it can become null or
-+   * undefined at any time.
-+   */
-+  get selectedElement() {
-+    return this._selectedElement && this._selectedElement.get();
-+  }
-+  set selectedElement(value) {
-+    if (!value) {
-+      delete this._selectedElement;
-+    } else {
-+      this._selectedElement = Cu.getWeakReference(value);
-+    }
-+  }
-+
-+  /**
-+   * Focuses and moves keyboard selection to the first navigable element.
-+   * This is a no-op if there are no navigable elements.
-+   *
-+   * @param {boolean} homeKey - `true` if this is for the home key.
-+   * @param {boolean} skipBack - `true` if the Back button should be skipped.
-+   */
-+  focusFirstNavigableElement(homeKey = false, skipBack = false) {
-+    // The home key is conceptually similar to the up/down arrow keys.
-+    const walker = homeKey
-+      ? this._arrowNavigableWalker
-+      : this._tabNavigableWalker;
-+    walker.currentNode = walker.root;
-+    this.selectedElement = walker.firstChild();
-+    if (
-+      skipBack &&
-+      walker.currentNode &&
-+      walker.currentNode.classList.contains("subviewbutton-back") &&
-+      walker.nextNode()
-+    ) {
-+      this.selectedElement = walker.currentNode;
-+    }
-+    this.focusSelectedElement(/* byKey */ true);
-+  }
-+
-+  /**
-+   * Focuses and moves keyboard selection to the last navigable element.
-+   * This is a no-op if there are no navigable elements.
-+   *
-+   * @param {boolean} endKey - `true` if this is for the end key.
-+   */
-+  focusLastNavigableElement(endKey = false) {
-+    // The end key is conceptually similar to the up/down arrow keys.
-+    const walker = endKey
-+      ? this._arrowNavigableWalker
-+      : this._tabNavigableWalker;
-+    walker.currentNode = walker.root;
-+    this.selectedElement = walker.lastChild();
-+    this.focusSelectedElement(/* byKey */ true);
-+  }
-+
-+  /**
-+   * Based on going up or down, select the previous or next focusable element.
-+   *
-+   * @param {boolean} isDown - whether we're going down (true) or up (false).
-+   * @param {boolean} arrowKey - `true` if this is for the up/down arrow keys.
-+   *
-+   * @returns {DOMNode} the element we selected.
-+   */
-+  moveSelection(isDown, arrowKey = false) {
-+    const walker = arrowKey
-+      ? this._arrowNavigableWalker
-+      : this._tabNavigableWalker;
-+    const oldSel = this.selectedElement;
-+    let newSel;
-+    if (oldSel) {
-+      walker.currentNode = oldSel;
-+      newSel = isDown ? walker.nextNode() : walker.previousNode();
-+    }
-+    // If we couldn't find something, select the first or last item:
-+    if (!newSel) {
-+      walker.currentNode = walker.root;
-+      newSel = isDown ? walker.firstChild() : walker.lastChild();
-+    }
-+    this.selectedElement = newSel;
-+    return newSel;
-+  }
-+
-+  /**
-+   * Allow for navigating subview buttons using the arrow keys and the Enter key.
-+   * The Up and Down keys can be used to navigate the list up and down and the
-+   * Enter, Right or Left - depending on the text direction - key can be used to
-+   * simulate a click on the currently selected button.
-+   * The Right or Left key - depending on the text direction - can be used to
-+   * navigate to the previous view, functioning as a shortcut for the view's
-+   * back button.
-+   * Thus, in LTR mode:
-+   *  - The Right key functions the same as the Enter key, simulating a click
-+   *  - The Left key triggers a navigation back to the previous view.
-+   *
-+   * Key navigation is only enabled while the view is active, meaning that this
-+   * method will return early if it is invoked during a sliding transition.
-+   *
-+   * @param {KeyEvent} event
-+   */
-+  /* eslint-disable-next-line complexity */
-+  keyNavigation(event) {
-+    if (!this.active) {
-+      return;
-+    }
-+
-+    let focus = this.document.activeElement;
-+    // Make sure the focus is actually inside the panel. (It might not be if
-+    // the panel was opened with the mouse.) If it isn't, we don't care
-+    // about it for our purposes.
-+    // We use Node.compareDocumentPosition because Node.contains doesn't
-+    // behave as expected for anonymous content; e.g. the input inside a
-+    // textbox.
-+    if (
-+      focus &&
-+      !(
-+        this.node.compareDocumentPosition(focus) &
-+        Node.DOCUMENT_POSITION_CONTAINED_BY
-+      )
-+    ) {
-+      focus = null;
-+    }
-+
-+    // Extension panels contain embedded documents. We can't manage
-+    // keyboard navigation within those.
-+    if (focus && focus.tagName == "browser") {
-+      return;
-+    }
-+
-+    const stop = () => {
-+      event.stopPropagation();
-+      event.preventDefault();
-+    };
-+
-+    // If the focused element is only navigable with tab, it wants the arrow
-+    // keys, etc. We shouldn't handle any keys except tab and shift+tab.
-+    // We make a function for this for performance reasons: we only want to
-+    // check this for keys we potentially care about, not *all* keys.
-+    const tabOnly = () => {
-+      // We use the real focus rather than this.selectedElement because focus
-+      // might have been moved without keyboard navigation (e.g. mouse click)
-+      // and this.selectedElement is only updated for keyboard navigation.
-+      return focus && this._isNavigableWithTabOnly(focus);
-+    };
-+
-+    // If a context menu is open, we must let it handle all keys.
-+    // Normally, this just happens, but because we have a capturing window
-+    // keydown listener, our listener takes precedence.
-+    // Again, we only want to do this check on demand for performance.
-+    const isContextMenuOpen = () => {
-+      if (!focus) {
-+        return false;
-+      }
-+      const contextNode = focus.closest("[context]");
-+      if (!contextNode) {
-+        return false;
-+      }
-+      const context = contextNode.getAttribute("context");
-+      const popup = this.document.getElementById(context);
-+      return popup && popup.state == "open";
-+    };
-+
-+    const keyCode = event.code;
-+    switch (keyCode) {
-+      case "ArrowDown":
-+      case "ArrowUp":
-+        if (tabOnly()) {
-+          break;
-+        }
-+      // Fall-through...
-+      case "Tab": {
-+        if (isContextMenuOpen()) {
-+          break;
-+        }
-+        stop();
-+        const isDown =
-+          keyCode == "ArrowDown" || (keyCode == "Tab" && !event.shiftKey);
-+        const button = this.moveSelection(isDown, keyCode != "Tab");
-+        Services.focus.setFocus(button, Services.focus.FLAG_BYKEY);
-+        break;
-+      }
-+      case "Home":
-+        if (tabOnly() || isContextMenuOpen()) {
-+          break;
-+        }
-+        stop();
-+        this.focusFirstNavigableElement(true);
-+        break;
-+      case "End":
-+        if (tabOnly() || isContextMenuOpen()) {
-+          break;
-+        }
-+        stop();
-+        this.focusLastNavigableElement(true);
-+        break;
-+      case "ArrowLeft":
-+      case "ArrowRight": {
-+        if (tabOnly() || isContextMenuOpen()) {
-+          break;
-+        }
-+        stop();
-+        if (
-+          (!this.window.RTL_UI && keyCode == "ArrowLeft") ||
-+          (this.window.RTL_UI && keyCode == "ArrowRight")
-+        ) {
-+          this.node.panelMultiView.goBack();
-+          break;
-+        }
-+        // If the current button is _not_ one that points to a subview, pressing
-+        // the arrow key shouldn't do anything.
-+        const button = this.selectedElement;
-+        if (!button || !button.classList.contains("subviewbutton-nav")) {
-+          break;
-+        }
-+      }
-+      // Fall-through...
-+      case "Space":
-+      case "NumpadEnter":
-+      case "Enter": {
-+        if (tabOnly() || isContextMenuOpen()) {
-+          break;
-+        }
-+        const button = this.selectedElement;
-+        if (!button) {
-+          break;
-+        }
-+        stop();
-+
-+        this._doingKeyboardActivation = true;
-+        // Unfortunately, 'tabindex' doesn't execute the default action, so
-+        // we explicitly do this here.
-+        // We are sending a command event, a mousedown event and then a click
-+        // event. This is done in order to mimic a "real" mouse click event.
-+        // Normally, the command event executes the action, then the click event
-+        // closes the menu. However, in some cases (e.g. the Library button),
-+        // there is no command event handler and the mousedown event executes the
-+        // action instead.
-+        button.doCommand();
-+        let dispEvent = new event.target.ownerGlobal.MouseEvent("mousedown", {
-+          bubbles: true,
-+        });
-+        button.dispatchEvent(dispEvent);
-+        dispEvent = new event.target.ownerGlobal.MouseEvent("click", {
-+          bubbles: true,
-+        });
-+        button.dispatchEvent(dispEvent);
-+        this._doingKeyboardActivation = false;
-+        break;
-+      }
-+    }
-+  }
-+
-+  /**
-+   * Focus the last selected element in the view, if any.
-+   *
-+   * @param byKey {Boolean} whether focus was moved by the user pressing a key.
-+   *                        Needed to ensure we show focus styles in the right cases.
-+   */
-+  focusSelectedElement(byKey = false) {
-+    const selected = this.selectedElement;
-+    if (selected) {
-+      const flag = byKey ? "FLAG_BYKEY" : "FLAG_BYELEMENTFOCUS";
-+      Services.focus.setFocus(selected, Services.focus[flag]);
-+    }
-+  }
-+
-+  /**
-+   * Clear all traces of keyboard navigation happening right now.
-+   */
-+  clearNavigation() {
-+    const selected = this.selectedElement;
-+    if (selected) {
-+      selected.blur();
-+      this.selectedElement = null;
-+    }
-+  }
-+}
-diff --git a/suite/buoy/modules/SessionStore.sys.mjs b/suite/buoy/modules/SessionStore.sys.mjs
-new file mode 100644
---- /dev/null
-+++ b/suite/buoy/modules/SessionStore.sys.mjs
-@@ -0,0 +1,12 @@
-+/* This Source Code Form is subject to the terms of the Mozilla Public
-+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
-+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
-+
-+/**
-+ * This is a shim for SessionStore in moz-central to prevent bug 1713801. Only
-+ * the methods that appear to be hit by comm-central are implemented.
-+ */
-+export var SessionStore = {
-+  updateSessionStoreFromTablistener(aBrowser, aBrowsingContext, aData) {},
-+  maybeExitCrashedState() {},
-+};
-diff --git a/suite/buoy/moz-l10n/browser/appExtensionFields.ftl b/suite/buoy/moz-l10n/browser/appExtensionFields.ftl
-new file mode 100644
---- /dev/null
-+++ b/suite/buoy/moz-l10n/browser/appExtensionFields.ftl
-@@ -0,0 +1,10 @@
-+# 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/.
-+
-+## Theme names and descriptions used in the Themes panel in about:addons
-+
-+# "Auto" is short for automatic. It can be localized without limitations.
-+extension-default-theme-name-auto=System theme — auto
-+extension-default-theme-description=Follow the operating system setting for buttons, menus, and windows.
-+
-diff --git a/suite/buoy/moz-l10n/browser/branding/brandings.ftl b/suite/buoy/moz-l10n/browser/branding/brandings.ftl
-new file mode 100644
---- /dev/null
-+++ b/suite/buoy/moz-l10n/browser/branding/brandings.ftl
-@@ -0,0 +1,17 @@
-+# This Source Code Form is subject to the terms of the Mozilla Public
-+# License, v. 2.0. If a copy of the MPL was not distributed with this
-+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-+
-+## The following feature names must be treated as a brand.
-+##
-+## They cannot be:
-+## - Transliterated.
-+## - Translated.
-+##
-+## Declension should be avoided where possible, leaving the original
-+## brand unaltered in prominent UI positions.
-+##
-+## For further details, consult:
-+## https://mozilla-l10n.github.io/styleguides/mozilla_general/#brands-copyright-and-trademark
-+
-+-profiler-brand-name = Firefox Profiler
-diff --git a/suite/buoy/moz.build b/suite/buoy/moz.build
-new file mode 100644
---- /dev/null
-+++ b/suite/buoy/moz.build
-@@ -0,0 +1,15 @@
-+EXTRA_JS_MODULES += [
-+    "modules/BrowserWindowTracker.sys.mjs",
-+    "modules/CustomizableUI.sys.mjs",
-+    "modules/EzE10SUtils.sys.mjs",
-+    "modules/PanelMultiView.sys.mjs",
-+]
-+
-+EXTRA_JS_MODULES.sessionstore += [
-+    "modules/SessionStore.sys.mjs",
-+]
-+
-+
-+JS_PREFERENCE_FILES += ["ZZ-buoy-prefs.js"]
-+
-+JAR_MANIFESTS += ["jar.mn"]
-diff --git a/suite/moz.build b/suite/moz.build
---- a/suite/moz.build
-+++ b/suite/moz.build
-@@ -24,16 +24,19 @@ DIRS += [
- if CONFIG["MOZ_THUNDERBIRD_RUST"]:
-     DEFINES["MOZ_THUNDERBIRD_RUST"] = 1
- 
- if CONFIG["MOZ_OVERRIDE_GKRUST"]:
-     DIRS += [
-         "../rust",
-     ]
- 
-+if CONFIG['MOZ_SUITE_BUOY']:
-+    DIRS += ['buoy']
-+
- if CONFIG['MOZ_IRC']:
-     DIRS += ['chatzilla']
- 
- if CONFIG["MAKENSISU"]:
-     DIRS += ["installer/windows"]
- 
- if CONFIG["MOZ_BUNDLED_FONTS"]:
-     DIRS += ["/browser/fonts"]
-diff --git a/suite/moz.configure b/suite/moz.configure
---- a/suite/moz.configure
-+++ b/suite/moz.configure
-@@ -99,16 +99,29 @@ def moz_override_cargo_config(enable_rus
- 
- 
- set_config(
-     "MOZ_OVERRIDE_CARGO_CONFIG",
-     moz_override_cargo_config,
-     when="--enable-thunderbird-rust",
- )
- 
-+# =========================================================
-+# = Diagnostic "Buoy" Component
-+# =========================================================
-+option(
-+    "--enable-buoy", default=False, help="Enable building of the SeaMonkey Diagnostic Component"
-+)
-+
-+@depends_if("--enable-buoy")
-+def buoy(arg):
-+    return True
-+
-+set_config("MOZ_SUITE_BUOY", buoy)
-+
- # Building extensions is disabled by default.
- 
- # =========================================================
- # = ChatZilla extension
- # =========================================================
- option(
-     "--enable-irc", default=False, help="Enable building of the ChatZilla IRC extension"
- )

+ 0 - 28
comm-central/patches/TOP-CONTRIB-null-dll-blocklist-bustage.patch

@@ -1,28 +0,0 @@
-# HG changeset patch
-# User Matt A. Tobin <email@mattatobin.com>
-# Date 1659988365 0
-Opt into MOZ_SANDBOX_NULL_BLOCKLIST_OOP
-
-diff --git a/suite/moz.configure b/suite/moz.configure
---- a/suite/moz.configure
-+++ b/suite/moz.configure
-@@ -9,16 +9,19 @@ set_define("MOZ_SUITE", True)
- 
- imply_option("MOZ_APP_BASENAME", "SeaMonkey")
- imply_option("MOZ_APP_ID", "{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}")
- imply_option("MOZ_APP_VENDOR", "Mozilla")
- # Include the DevTools client, not just the server (which is the default)
- imply_option("MOZ_DEVTOOLS", "all")
- imply_option("NSS_EXTRA_SYMBOLS_FILE", "../comm/mailnews/nss-extra.symbols")
- 
-+set_config("MOZ_SANDBOX_NULL_BLOCKLIST_OOP", True)
-+set_define("MOZ_SANDBOX_NULL_BLOCKLIST_OOP", True)
-+
- imply_option('--enable-default-browser-agent', False)
- 
- @depends(target_is_windows, target_has_linux_kernel)
- def bundled_fonts(is_windows, is_linux):
-     if is_windows or is_linux:
-         return True
- 
- 

+ 0 - 200
comm-central/patches/TOP-CONTRIB-remove-global-dtd-useage.patch

@@ -1,200 +0,0 @@
-# HG changeset patch
-# User Matt A. Tobin <email@mattatobin.com>
-# Date 1659988365 0
-9999999 - Remove usage of global.dtd from about pages
-
-Suite's about:certerror is no longer used in central so it remains unchanged.
-
-diff --git a/suite/base/content/about.xhtml b/suite/base/content/about.xhtml
---- a/suite/base/content/about.xhtml
-+++ b/suite/base/content/about.xhtml
-@@ -1,32 +1,30 @@
- <?xml version="1.0" encoding="UTF-8"?>
- 
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
-   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd" [
- <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" >
- %brandDTD;
--<!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
--%globalDTD;
- <!ENTITY % suiteAboutDTD SYSTEM "chrome://communicator/locale/about.dtd" >
- %suiteAboutDTD;
- ]>
- 
- <!-- This Source Code Form is subject to the terms of the Mozilla Public
-    - License, v. 2.0. If a copy of the MPL was not distributed with this
-    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
- 
- <html xmlns="http://www.w3.org/1999/xhtml">
- <head>
-   <title>About:</title>
--  <link rel="stylesheet" href="chrome://global/skin/about.css" type="text/css"/>
-+  <link rel="stylesheet" href="chrome://communicator/skin/about.css" type="text/css"/>
-   <script src="chrome://communicator/content/about.js"/>
- </head>
- 
--<body dir="&locale.dir;">
-+<body dir="ltr">
-   <div id="aboutLogoContainer">
-     <a id="vendorURL" href="http://www.seamonkey-project.org/">
-       <img src="about:logo" alt="&brandShortName;"/>
-       <p id="version">&about.version; </p>
-     </a>
-   </div>
- 
-   <ul id="aboutPageList">
-diff --git a/suite/base/content/aboutSeaMonkey.xhtml b/suite/base/content/aboutSeaMonkey.xhtml
---- a/suite/base/content/aboutSeaMonkey.xhtml
-+++ b/suite/base/content/aboutSeaMonkey.xhtml
-@@ -1,14 +1,12 @@
- <!DOCTYPE html
- [
-   <!ENTITY % seamonkeyDTD SYSTEM "chrome://communicator/locale/aboutSeaMonkey.dtd" >
-   %seamonkeyDTD;
--  <!ENTITY % directionDTD SYSTEM "chrome://global/locale/global.dtd" >
--  %directionDTD;
- ]>
- 
- <!-- This Source Code Form is subject to the terms of the Mozilla Public
-    - License, v. 2.0. If a copy of the MPL was not distributed with this
-    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
- 
- <html xmlns="http://www.w3.org/1999/xhtml">
-   <head>
-@@ -45,17 +43,17 @@ em {
- 
- a {
-   text-decoration: none;
-   color: white;
- }
- </style>
- </head>
- 
--<body dir="&locale.dir;">
-+<body dir="ltr">
- 
- <section>
-   <p id="moztext">
-   &seamonkey.quote.1.30;
-   </p>
- 
-   <p id="from">
-   &seamonkey.from.1.30;
-diff --git a/suite/base/content/blockedSite.xhtml b/suite/base/content/blockedSite.xhtml
---- a/suite/base/content/blockedSite.xhtml
-+++ b/suite/base/content/blockedSite.xhtml
-@@ -1,15 +1,13 @@
- <?xml version="1.0" encoding="UTF-8"?>
- 
- <!DOCTYPE html [
-   <!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
-   %htmlDTD;
--  <!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
--  %globalDTD;
-   <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" >
-   %brandDTD;
-   <!ENTITY % blockedSiteDTD SYSTEM "chrome://communicator/locale/safeBrowsing.dtd">
-   %blockedSiteDTD;
- ]>
- 
- <!-- 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
-@@ -18,17 +16,17 @@
- <html xmlns="http://www.w3.org/1999/xhtml" class="blacklist">
-   <head>
-     <link rel="stylesheet" href="chrome://communicator/content/certError.css" type="text/css" media="all" />
-     <link rel="stylesheet" href="chrome://global/skin/netError.css" type="text/css" media="all" />
-     <link rel="stylesheet" href="chrome://communicator/skin/blockedSite.css" type="text/css" media="all" />
-     <link rel="icon" type="image/png" id="favicon" href="chrome://global/skin/icons/blacklist_favicon.png"/>
-   </head>
- 
--  <body dir="&locale.dir;">
-+  <body dir="ltr">
-     <div id="errorPageContainer">
- 
-       <!-- Error Title -->
-       <div id="errorTitle">
-         <h1 id="errorTitleText_phishing">&safeb.blocked.phishingPage.title2;</h1>
-         <h1 id="errorTitleText_malware">&safeb.blocked.malwarePage.title;</h1>
-         <h1 id="errorTitleText_unwanted">&safeb.blocked.unwantedPage.title;</h1>
-         <h1 id="errorTitleText_harmful">&safeb.blocked.harmfulPage.title;</h1>
-diff --git a/suite/components/feeds/content/subscribe.xhtml b/suite/components/feeds/content/subscribe.xhtml
---- a/suite/components/feeds/content/subscribe.xhtml
-+++ b/suite/components/feeds/content/subscribe.xhtml
-@@ -4,19 +4,16 @@
-    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
- 
- 
- <!DOCTYPE html [
-   <!ENTITY % htmlDTD
-     PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
-     "DTD/xhtml1-strict.dtd">
-   %htmlDTD;
--  <!ENTITY % globalDTD
--    SYSTEM "chrome://global/locale/global.dtd">
--  %globalDTD;
-   <!ENTITY % feedDTD
-     SYSTEM "chrome://communicator/locale/feeds/subscribe.dtd">
-   %feedDTD;
- ]>
- 
- <?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
- 
- <html id="feedHandler"
-@@ -29,17 +26,17 @@
-           media="all"/>
-     <link rel="stylesheet"
-           href="chrome://communicator/skin/feed-subscribe.css"
-           type="text/css"
-           media="all"/>
-   </head>
-   <body>
-     <div id="feedHeaderContainer">
--      <div id="feedHeader" dir="&locale.dir;">
-+      <div id="feedHeader" dir="ltr">
-         <div id="feedIntroText">
-           <p id="feedSubscriptionInfo1" />
-           <p id="feedSubscriptionInfo2" />
-         </div>
-         <div id="feedSubscribeLine" />
-       </div>
-     </div>
- 
-diff --git a/suite/components/sessionstore/content/aboutSessionRestore.xhtml b/suite/components/sessionstore/content/aboutSessionRestore.xhtml
---- a/suite/components/sessionstore/content/aboutSessionRestore.xhtml
-+++ b/suite/components/sessionstore/content/aboutSessionRestore.xhtml
-@@ -6,33 +6,31 @@
- -->
- <!DOCTYPE html [
- <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" >
-   %brandDTD;
-   <!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
-   %htmlDTD;
-   <!ENTITY % netErrorDTD SYSTEM "chrome://global/locale/netError.dtd">
-   %netErrorDTD;
--  <!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
--  %globalDTD;
-   <!ENTITY % restorepageDTD SYSTEM "chrome://communicator/locale/aboutSessionRestore.dtd">
-   %restorepageDTD;
- ]>
- 
- <html xmlns="http://www.w3.org/1999/xhtml">
-   <head>
-     <title>&restorepage.tabtitle;</title>
-     <link rel="stylesheet" href="chrome://global/skin/netError.css" type="text/css" media="all"/>
-     <link rel="stylesheet" href="chrome://communicator/skin/aboutSessionRestore.css" type="text/css" media="all"/>
-     <link rel="icon" type="image/png" href="chrome://global/skin/icons/question-16.png"/>
- 
-     <script src="chrome://communicator/content/aboutSessionRestore.js"/>
-   </head>
- 
--  <body dir="&locale.dir;">
-+  <body dir="ltr">
- 
-     <!-- PAGE CONTAINER (for styling purposes only) -->
-     <div id="errorPageContainer">
- 
-       <!-- Error Title -->
-       <div id="errorTitle">
-         <h1 id="errorTitleText">&restorepage.pagetitle;</h1>
-       </div>

+ 0 - 477
comm-central/patches/binoc/almost-bypass-package-manifest.patch

@@ -1,477 +0,0 @@
-# HG changeset patch
-# User Matt A. Tobin <email@mattatobin.com>
-# Date 1659988365 0
-imported patch X-Y-almost-bypass-package-manifest.patch
-
-diff --git a/suite/installer/package-manifest.in b/suite/installer/package-manifest.in
---- a/suite/installer/package-manifest.in
-+++ b/suite/installer/package-manifest.in
-@@ -37,466 +37,9 @@
- #ifdef XP_MACOSX
- ; Mac bundle stuff
- @APPNAME@/Contents/Info.plist
- @APPNAME@/Contents/PkgInfo
- @RESPATH@/seamonkey.icns
- @RESPATH@/@LPROJ_ROOT@.lproj/*
- #endif
- 
--[@AB_CD@]
--@RESPATH@/defaults/messenger/mailViews.dat
--@RESPATH@/defaults/profile/bookmarks.html
--@RESPATH@/defaults/profile/chrome/*
--@RESPATH@/defaults/profile/mimeTypes.rdf
--@RESPATH@/defaults/profile/panels.rdf
--@RESPATH@/dictionaries/*
--@RESPATH@/hyphenation/*
--#ifdef MOZ_BUNDLED_FONTS
--@RESPATH@/fonts/*
--#endif
--@RESPATH@/@PREF_DIR@/suite-l10n.js
--#ifdef HAVE_MAKENSISU
--@BINPATH@/uninstall/helper.exe
--#endif
--#ifdef MOZ_UPDATER
--@RESPATH@/update.locale
--@RESPATH@/updater.ini
--#endif
--
--#ifdef PKG_LOCALE_MANIFEST
--#include @PKG_LOCALE_MANIFEST@
--#endif
--
--[xpcom]
--@RESPATH@/dependentlibs.list
--#ifdef MOZ_SHARED_MOZGLUE
--@BINPATH@/@DLL_PREFIX@mozglue@DLL_SUFFIX@
--#endif
--#ifndef MOZ_STATIC_JS
--@BINPATH@/@DLL_PREFIX@mozjs@DLL_SUFFIX@
--#endif
--#ifndef MOZ_SYSTEM_NSPR
--#ifndef MOZ_FOLD_LIBS
--@BINPATH@/@DLL_PREFIX@nspr4@DLL_SUFFIX@
--@BINPATH@/@DLL_PREFIX@plc4@DLL_SUFFIX@
--@BINPATH@/@DLL_PREFIX@plds4@DLL_SUFFIX@
--#endif
--#endif
--#ifdef XP_MACOSX
--@BINPATH@/XUL
--#else
--@BINPATH@/@DLL_PREFIX@xul@DLL_SUFFIX@
--#endif
--#ifdef XP_MACOSX
--@BINPATH@/@MOZ_CHILD_PROCESS_NAME@.app/
--#else
--@BINPATH@/@MOZ_CHILD_PROCESS_NAME@
--#endif
--; ANGLE GLES-on-D3D rendering library
--#ifdef MOZ_ANGLE_RENDERER
--@BINPATH@/libEGL.dll
--@BINPATH@/libGLESv2.dll
--#ifdef MOZ_D3DCOMPILER_VISTA_DLL
--@BINPATH@/@MOZ_D3DCOMPILER_VISTA_DLL@
--#endif
--#endif # MOZ_ANGLE_RENDERER
--
--#ifdef XP_WIN
--#if MOZ_PACKAGE_MSVC_DLLS
--@BINPATH@/@MSVC_C_RUNTIME_DLL@
--@BINPATH@/@MSVC_CXX_RUNTIME_DLL@
--@BINPATH@/api-ms-win-*.dll
--@BINPATH@/ucrtbase.dll
--#endif
--#endif
--
--[browser]
--; [Base Browser Files]
--#ifdef XP_WIN
--@BINPATH@/@MOZ_APP_NAME@.exe
--#else
--@BINPATH@/@MOZ_APP_NAME@-bin
--@BINPATH@/@MOZ_APP_NAME@
--#endif
--@RESPATH@/application.ini
--@RESPATH@/platform.ini
--#ifdef MOZ_UPDATER
--# update-settings.ini has been removed on macOS.
--#ifndef XP_MACOSX
--@RESPATH@/update-settings.ini
--#endif
--#endif
--#ifndef MOZ_FOLD_LIBS
--@BINPATH@/@DLL_PREFIX@mozsqlite3@DLL_SUFFIX@
--#endif
--@BINPATH@/@DLL_PREFIX@lgpllibs@DLL_SUFFIX@
--@BINPATH@/@DLL_PREFIX@gkcodecs@DLL_SUFFIX@
--#ifdef MOZ_FFVPX
--@BINPATH@/@DLL_PREFIX@mozavutil@DLL_SUFFIX@
--@BINPATH@/@DLL_PREFIX@mozavcodec@DLL_SUFFIX@
--#endif
--#ifdef MOZ_GTK
--@BINPATH@/glxtest
--@BINPATH@/@DLL_PREFIX@mozgtk@DLL_SUFFIX@
--#ifdef MOZ_WAYLAND
--@BINPATH@/vaapitest
--@BINPATH@/@DLL_PREFIX@mozwayland@DLL_SUFFIX@
--#endif
--#endif
--@RESPATH@/license.txt
--@RESPATH@/blocklist.xml
--
--; [Components]
--#ifdef ACCESSIBILITY
--#ifdef XP_WIN
--@BINPATH@/AccessibleMarshal.dll
--#endif
--#endif
--@RESPATH@/components/extensions.manifest
--@RESPATH@/components/SuiteBrowser.manifest
--@RESPATH@/components/SuiteComponents.manifest
--@RESPATH@/components/SuiteFeeds.manifest
--@RESPATH@/components/SuiteSidebar.manifest
--; JavaScript components
--@RESPATH@/components/cryptoComponents.manifest
--@RESPATH@/components/FeedConverter.js
--@RESPATH@/components/FeedWriter.js
--@RESPATH@/components/jsconsole-clhandler.js
--@RESPATH@/components/jsconsole-clhandler.manifest
--@RESPATH@/components/nsBrowserContentHandler.js
--@RESPATH@/components/nsComposerCmdLineHandler.js
--@RESPATH@/components/nsComposerCmdLineHandler.manifest
--@RESPATH@/components/nsGopherProtocolStubHandler.js
--@RESPATH@/components/nsPlacesAutoComplete.js
--@RESPATH@/components/nsPlacesAutoComplete.manifest
--@RESPATH@/components/nsSessionStartup.js
--@RESPATH@/components/nsSessionStartup.manifest
--@RESPATH@/components/nsSessionStore.js
--@RESPATH@/components/nsSidebar.js
--@RESPATH@/components/nsSuiteGlue.js
--@RESPATH@/components/nsSetDefault.js
--@RESPATH@/components/nsSetDefault.manifest
--@RESPATH@/components/nsTypeAheadFind.js
--#ifdef MOZ_UPDATER
--@RESPATH@/components/nsUpdateService.manifest
--#endif
--@RESPATH@/components/ProcessSingleton.manifest
--@RESPATH@/components/Push.manifest
--@RESPATH@/components/servicesComponents.manifest
--@RESPATH@/components/servicesSettings.manifest
--@RESPATH@/components/SuiteProfileMigrator.js
--@RESPATH@/components/SuiteProfileMigrator.manifest
--#if defined(ENABLE_TESTS) && defined(MOZ_DEBUG)
--@RESPATH@/components/TestInterfaceJS.js
--@RESPATH@/components/TestInterfaceJS.manifest
--@RESPATH@/components/TestInterfaceJSMaplike.js
--#endif
--@RESPATH@/components/WebContentConverter.js
--
--; Modules
--@RESPATH@/modules/*
--
--; [Extensions]
--@RESPATH@/components/extensions-toolkit.manifest
--
--; [Browser Chrome Files]
--; Browser: Hack to get built_in_addons.json packaged
--@RESPATH@/chrome/browser@JAREXT@
--@RESPATH@/chrome/browser.manifest
--@RESPATH@/chrome/comm@JAREXT@
--@RESPATH@/chrome/comm.manifest
--@RESPATH@/chrome/toolkit@JAREXT@
--@RESPATH@/chrome/toolkit.manifest
--
--; [DevTools Startup Files]
--@RESPATH@/chrome/devtools-startup@JAREXT@
--@RESPATH@/chrome/devtools-startup.manifest
--
--; DevTools
--@RESPATH@/chrome/devtools@JAREXT@
--@RESPATH@/chrome/devtools.manifest
--@RESPATH@/@PREF_DIR@/debugger.js
--
--; classic theme
--@RESPATH@/chrome/classic@JAREXT@
--@RESPATH@/chrome/classic.manifest
--@RESPATH@/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}.xpi
--
--; modern theme
--@RESPATH@/extensions/modern@themes.mozilla.org.xpi
--
--; shell icons
--#ifdef MOZ_GTK
--@RESPATH@/chrome/icons/default/bookmarkproperties.png
--@RESPATH@/chrome/icons/default/bookmarkproperties16.png
--@RESPATH@/chrome/icons/default/bookmarkproperties48.png
--@RESPATH@/chrome/icons/default/chatzilla-window.png
--@RESPATH@/chrome/icons/default/chatzilla-window16.png
--@RESPATH@/chrome/icons/default/chatzilla-window48.png
--@RESPATH@/chrome/icons/default/default16.png
--@RESPATH@/chrome/icons/default/default22.png
--@RESPATH@/chrome/icons/default/default24.png
--@RESPATH@/chrome/icons/default/default32.png
--@RESPATH@/chrome/icons/default/default48.png
--@RESPATH@/chrome/icons/default/default64.png
--@RESPATH@/chrome/icons/default/default128.png
--@RESPATH@/chrome/icons/default/default256.png
--@RESPATH@/chrome/icons/default/downloadManager.png
--@RESPATH@/chrome/icons/default/downloadManager16.png
--@RESPATH@/chrome/icons/default/downloadManager48.png
--@RESPATH@/chrome/icons/default/editorWindow.png
--@RESPATH@/chrome/icons/default/editorWindow16.png
--@RESPATH@/chrome/icons/default/editorWindow48.png
--@RESPATH@/chrome/icons/default/findBookmarkWindow.png
--@RESPATH@/chrome/icons/default/findBookmarkWindow16.png
--@RESPATH@/chrome/icons/default/findBookmarkWindow48.png
--@RESPATH@/chrome/icons/default/findHistoryWindow.png
--@RESPATH@/chrome/icons/default/findHistoryWindow16.png
--@RESPATH@/chrome/icons/default/findHistoryWindow48.png
--@RESPATH@/chrome/icons/default/history-window.png
--@RESPATH@/chrome/icons/default/history-window16.png
--@RESPATH@/chrome/icons/default/history-window48.png
--@RESPATH@/chrome/icons/default/JSConsoleWindow.png
--@RESPATH@/chrome/icons/default/JSConsoleWindow16.png
--@RESPATH@/chrome/icons/default/JSConsoleWindow48.png
--@RESPATH@/chrome/icons/default/places.png
--@RESPATH@/chrome/icons/default/places16.png
--@RESPATH@/chrome/icons/default/places48.png
--#ifdef MOZ_UPDATER
--@RESPATH@/icons/updater.png
--#endif
--#elifdef XP_WIN
--@RESPATH@/chrome/icons/default/bookmarkproperties.ico
--@RESPATH@/chrome/icons/default/chatzilla-window.ico
--@RESPATH@/chrome/icons/default/downloadManager.ico
--@RESPATH@/chrome/icons/default/editorWindow.ico
--@RESPATH@/chrome/icons/default/findBookmarkWindow.ico
--@RESPATH@/chrome/icons/default/findHistoryWindow.ico
--@RESPATH@/chrome/icons/default/gif-file.ico
--@RESPATH@/chrome/icons/default/history-window.ico
--@RESPATH@/chrome/icons/default/html-file.ico
--@RESPATH@/chrome/icons/default/image-file.ico
--@RESPATH@/chrome/icons/default/jpeg-file.ico
--@RESPATH@/chrome/icons/default/JSConsoleWindow.ico
--@RESPATH@/chrome/icons/default/main-window.ico
--@RESPATH@/chrome/icons/default/places.ico
--@RESPATH@/chrome/icons/default/script-file.ico
--@RESPATH@/chrome/icons/default/xml-file.ico
--@RESPATH@/chrome/icons/default/xul-file.ico
--#endif
--
--; [Default Preferences]
--; All the browser/general pref files must be part of base to prevent migration bugs
--@RESPATH@/@PREF_DIR@/suite-prefs.js
--@RESPATH@/@PREF_DIR@/composer.js
--@RESPATH@/greprefs.js
--@RESPATH@/defaults/autoconfig/prefcalls.js
--@RESPATH@/defaults/permissions
--@RESPATH@/defaults/settings/blocklists
--@RESPATH@/defaults/settings/main
--; Warning: changing the path to channel-prefs.js can cause bugs. (Bug 756325)
--@RESPATH@/defaults/pref/channel-prefs.js
--
--; [Layout Engine Resources]
--; Layout debug extension.
--#ifdef ENABLE_TESTS
--#ifdef MOZ_DEBUG
--@RESPATH@/chrome/layoutdebug@JAREXT@
--@RESPATH@/chrome/layoutdebug.manifest
--#endif
--#endif
--; Style Sheets, Graphics and other Resources used by the layout engine.
--@RESPATH@/res/contenteditable.css
--@RESPATH@/res/designmode.css
--@RESPATH@/res/EditorOverride.css
--@RESPATH@/res/grabber.gif
--@RESPATH@/res/language.properties
--@RESPATH@/res/svg.css
--@RESPATH@/res/table-add-column-after-active.gif
--@RESPATH@/res/table-add-column-after-hover.gif
--@RESPATH@/res/table-add-column-after.gif
--@RESPATH@/res/table-add-column-before-active.gif
--@RESPATH@/res/table-add-column-before-hover.gif
--@RESPATH@/res/table-add-column-before.gif
--@RESPATH@/res/table-add-row-after-active.gif
--@RESPATH@/res/table-add-row-after-hover.gif
--@RESPATH@/res/table-add-row-after.gif
--@RESPATH@/res/table-add-row-before-active.gif
--@RESPATH@/res/table-add-row-before-hover.gif
--@RESPATH@/res/table-add-row-before.gif
--@RESPATH@/res/table-remove-column-active.gif
--@RESPATH@/res/table-remove-column-hover.gif
--@RESPATH@/res/table-remove-column.gif
--@RESPATH@/res/table-remove-row-active.gif
--@RESPATH@/res/table-remove-row-hover.gif
--@RESPATH@/res/table-remove-row.gif
--#ifdef XP_MACOSX
--@RESPATH@/res/cursors/*
--#endif
--@RESPATH@/res/fonts/*
--@RESPATH@/res/dtd/*
--#ifdef XP_MACOSX
--@RESPATH@/res/MainMenu.nib/
--#endif
--
--; Content-accessible resources.
--@RESPATH@/contentaccessible/*
--
--; [Personal Security Manager]
--;
--; NSS libraries are signed in the staging directory,
--; meaning their .chk files are created there directly.
--;
--#ifndef MOZ_SYSTEM_NSS
--#if defined(XP_LINUX) && !defined(ANDROID)
--@BINPATH@/@DLL_PREFIX@freeblpriv3@DLL_SUFFIX@
--#else
--@BINPATH@/@DLL_PREFIX@freebl3@DLL_SUFFIX@
--#endif
--@BINPATH@/@DLL_PREFIX@nss3@DLL_SUFFIX@
--@BINPATH@/@DLL_PREFIX@nssckbi@DLL_SUFFIX@
--#ifndef MOZ_FOLD_LIBS
--@BINPATH@/@DLL_PREFIX@nssutil3@DLL_SUFFIX@
--@BINPATH@/@DLL_PREFIX@smime3@DLL_SUFFIX@
--@BINPATH@/@DLL_PREFIX@ssl3@DLL_SUFFIX@
--#endif
--@BINPATH@/@DLL_PREFIX@softokn3@DLL_SUFFIX@
--#endif
--@RESPATH@/chrome/pippki@JAREXT@
--@RESPATH@/chrome/pippki.manifest
--
--; For process sandboxing
--#if defined(MOZ_SANDBOX)
--#if defined(XP_LINUX)
--@BINPATH@/@DLL_PREFIX@mozsandbox@DLL_SUFFIX@
--#endif
--#endif
--
--; for Solaris SPARC
--#ifdef SOLARIS
--bin/libfreebl_32fpu_3.so
--bin/libfreebl_32int_3.so
--bin/libfreebl_32int64_3.so
--#endif
--
--; [MAN pages]
--#ifdef UNIX_BUT_NOT_MAC
--man/*
--#endif
--
--; [Updater]
--;
--#ifdef MOZ_UPDATER
--#ifdef XP_MACOSX
--@BINPATH@/updater.app/
--#else
--@BINPATH@/updater@BIN_SUFFIX@
--#endif
--#endif
--
--; [Crash Reporter]
--;
--#ifdef MOZ_CRASHREPORTER
--#ifdef XP_MACOSX
--@BINPATH@/crashreporter.app/
--#else
--@BINPATH@/crashreporter@BIN_SUFFIX@
--#endif
--#ifdef MOZ_CRASHREPORTER_INJECTOR
--@BINPATH@/breakpadinjector.dll
--#endif
--#endif
--
--; [ minidump-analyzer ]
--;
--#ifdef MOZ_CRASHREPORTER
--@BINPATH@/minidump-analyzer@BIN_SUFFIX@
--#endif
--
--; [ Ping Sender ]
--;
--@BINPATH@/pingsender@BIN_SUFFIX@
--
--[mail]
--; MailNews components
--
--; MailNews JS components
--
--; MailNews chrome
--@RESPATH@/chrome/messenger@JAREXT@
--@RESPATH@/chrome/messenger.manifest
--@RESPATH@/chrome/newsblog@JAREXT@
--@RESPATH@/chrome/newsblog.manifest
--#ifdef MOZ_GTK
--@RESPATH@/chrome/icons/default/abcardWindow.png
--@RESPATH@/chrome/icons/default/abcardWindow16.png
--@RESPATH@/chrome/icons/default/abcardWindow48.png
--@RESPATH@/chrome/icons/default/ablistWindow.png
--@RESPATH@/chrome/icons/default/ablistWindow16.png
--@RESPATH@/chrome/icons/default/ablistWindow48.png
--@RESPATH@/chrome/icons/default/addressbookWindow.png
--@RESPATH@/chrome/icons/default/addressbookWindow16.png
--@RESPATH@/chrome/icons/default/addressbookWindow48.png
--@RESPATH@/chrome/icons/default/messengerWindow.png
--@RESPATH@/chrome/icons/default/messengerWindow16.png
--@RESPATH@/chrome/icons/default/messengerWindow48.png
--@RESPATH@/chrome/icons/default/msgcomposeWindow.png
--@RESPATH@/chrome/icons/default/msgcomposeWindow16.png
--@RESPATH@/chrome/icons/default/msgcomposeWindow48.png
--#elifdef XP_WIN
--@RESPATH@/chrome/icons/default/abcardWindow.ico
--@RESPATH@/chrome/icons/default/ablistWindow.ico
--@RESPATH@/chrome/icons/default/addressbookWindow.ico
--@RESPATH@/chrome/icons/default/messengerWindow.ico
--@RESPATH@/chrome/icons/default/msgcomposeWindow.ico
--@RESPATH@/chrome/icons/default/calendar-alarm-dialog.ico
--@RESPATH@/chrome/icons/default/calendar-event-dialog.ico
--@RESPATH@/chrome/icons/default/calendar-event-summary-dialog.ico
--@RESPATH@/chrome/icons/default/calendar-task-dialog.ico
--@RESPATH@/chrome/icons/default/calendar-task-summary-dialog.ico
--#endif
--
--; [MailNews Default Preferences]
--@RESPATH@/@PREF_DIR@/mailnews.js
--@RESPATH@/@PREF_DIR@/mdn.js
--; @RESPATH@/@PREF_DIR@/e2e-prefs.js
--
--#ifdef MOZ_MAPI_SUPPORT
--@BINPATH@/MapiProxy.dll
--@BINPATH@/mozMapi32.dll
--#endif
--
--@RESPATH@/isp/*
--
--; Gloda
--@RESPATH@/chrome/gloda@JAREXT@
--@RESPATH@/chrome/gloda.manifest
--
--; Address Sanitizer
--#ifdef LLVM_SYMBOLIZER
--@BINPATH@/@LLVM_SYMBOLIZER@
--#endif
--
--#ifdef MOZ_CLANG_RT_ASAN_LIB
--@BINPATH@/@MOZ_CLANG_RT_ASAN_LIB@
--#endif
--
--[chatzilla]
--#ifdef MOZ_IRC
--@RESPATH@/chrome/chatzilla@JAREXT@
--@RESPATH@/chrome/chatzilla.manifest
--@RESPATH@/components/chatzilla-service.js
--@RESPATH@/components/chatzilla-service.manifest
--#endif
--
--[debugqa]
--#ifdef MOZ_PACKAGE_DEBUGQA
--@RESPATH@/extensions/debugQA@mozilla.org.xpi
--#endif
--
--[calendar]
--@RESPATH@/chrome/calendar@JAREXT@
--@RESPATH@/chrome/calendar.manifest
--
--@RESPATH@/@PREF_DIR@/calendar.js
--
--# Files added to components directory via `FINAL_TARGET_FILES.components`.
-+@RESPATH@/*
-\ No newline at end of file

+ 0 - 8
comm-central/patches/series

@@ -16,11 +16,3 @@ WIP-9999999-port1712633-suite-90a1.patch
 WIP-1650630-2-port-1603712-suite.patch
 WIP-1783623-port1524687-suite.patch
 WIP-9999999-port1770994-suite.patch
-TOP-CONTRIB-null-dll-blocklist-bustage.patch
-TOP-CONTRIB-devtools-with-chrome-clh.patch
-TOP-CONTRIB-add-brand-ftl.patch
-TOP-CONTRIB-remove-global-dtd-useage.patch
-TOP-CONTRIB-about-redirector-jscomp2esmodule.patch
-TOP-CONTRIB-diagnostic-buoy-component.patch
-ZZZZZZZ-MQSTOP-BINOC-MODIFICATIONS.patch
-./binoc/almost-bypass-package-manifest.patch