Merge mozilla-central to mozilla-inbound. a=merge
authorDaniel Varga <dvarga@mozilla.com>
Tue, 23 Apr 2019 12:57:35 +0300
changeset 470538 7a1707c388c7c5cd787d8b0747aed226dbea773e
parent 470537 24537856cc886a8beccb2089ee679d55d448ce00 (current diff)
parent 470434 831918f009f63596fde1e532cc0f026d2e53cf78 (diff)
child 470539 5e18acc4a42b127d90ef83658aa132bb139d7483
push id35907
push useraciure@mozilla.com
push dateTue, 23 Apr 2019 22:16:10 +0000
treeherdermozilla-central@4b0811d7b8e1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to mozilla-inbound. a=merge
browser/components/newtab/content-src/components/DiscoveryStreamComponents/DSImage/cache.js
browser/components/newtab/content-src/lib/asroutercontent.js
browser/components/newtab/content-src/lib/snippets.js
browser/components/newtab/docs/v2-system-addon/snippets.md
browser/components/newtab/lib/SnippetsFeed.jsm
browser/components/newtab/test/unit/activity-stream.test.jsx
browser/components/newtab/test/unit/common/ImgCache.test.js
browser/components/newtab/test/unit/content-src/lib/snippets.test.js
browser/components/newtab/test/unit/lib/SnippetsFeed.test.js
devtools/client/debugger/flow-typed/npm/devtools-reps_vx.x.x.js
devtools/client/debugger/src/actions/pause/setPopupObjectProperties.js
dom/xbl/nsXBLPrototypeResources.cpp
dom/xbl/nsXBLPrototypeResources.h
dom/xbl/nsXBLResourceLoader.cpp
dom/xbl/nsXBLResourceLoader.h
layout/style/test/test_media_queries_dynamic_xbl.html
--- a/browser/components/enterprisepolicies/Policies.jsm
+++ b/browser/components/enterprisepolicies/Policies.jsm
@@ -790,26 +790,66 @@ var Policies = {
       } else {
         Services.locale.requestedLocales = param.split(",");
       }
     },
   },
 
   "SanitizeOnShutdown": {
     onBeforeUIStartup(manager, param) {
-      setAndLockPref("privacy.sanitize.sanitizeOnShutdown", param);
-      if (param) {
-        setAndLockPref("privacy.clearOnShutdown.cache", true);
-        setAndLockPref("privacy.clearOnShutdown.cookies", true);
-        setAndLockPref("privacy.clearOnShutdown.downloads", true);
-        setAndLockPref("privacy.clearOnShutdown.formdata", true);
-        setAndLockPref("privacy.clearOnShutdown.history", true);
-        setAndLockPref("privacy.clearOnShutdown.sessions", true);
-        setAndLockPref("privacy.clearOnShutdown.siteSettings", true);
-        setAndLockPref("privacy.clearOnShutdown.offlineApps", true);
+      if (typeof param === "boolean") {
+        setAndLockPref("privacy.sanitize.sanitizeOnShutdown", param);
+        if (param) {
+          setAndLockPref("privacy.clearOnShutdown.cache", true);
+          setAndLockPref("privacy.clearOnShutdown.cookies", true);
+          setAndLockPref("privacy.clearOnShutdown.downloads", true);
+          setAndLockPref("privacy.clearOnShutdown.formdata", true);
+          setAndLockPref("privacy.clearOnShutdown.history", true);
+          setAndLockPref("privacy.clearOnShutdown.sessions", true);
+          setAndLockPref("privacy.clearOnShutdown.siteSettings", true);
+          setAndLockPref("privacy.clearOnShutdown.offlineApps", true);
+        }
+      } else {
+        setAndLockPref("privacy.sanitize.sanitizeOnShutdown", true);
+        if ("Cache" in param) {
+          setAndLockPref("privacy.clearOnShutdown.cache", param.Cache);
+        } else {
+          setAndLockPref("privacy.clearOnShutdown.cache", false);
+        }
+        if ("Cookies" in param) {
+          setAndLockPref("privacy.clearOnShutdown.cookies", param.Cookies);
+        } else {
+          setAndLockPref("privacy.clearOnShutdown.cookies", false);
+        }
+        if ("Downloads" in param) {
+          setAndLockPref("privacy.clearOnShutdown.downloads", param.Downloads);
+        } else {
+          setAndLockPref("privacy.clearOnShutdown.downloads", false);
+        }
+        if ("FormData" in param) {
+          setAndLockPref("privacy.clearOnShutdown.formdata", param.FormData);
+        } else {
+          setAndLockPref("privacy.clearOnShutdown.formdata", false);
+        }
+        if ("History" in param) {
+          setAndLockPref("privacy.clearOnShutdown.history", param.History);
+        } else {
+          setAndLockPref("privacy.clearOnShutdown.history", false);
+        }
+        if ("Sessions" in param) {
+          setAndLockPref("privacy.clearOnShutdown.sessions", param.Sessions);
+        } else {
+          setAndLockPref("privacy.clearOnShutdown.sessions", false);
+        }
+        if ("SiteSettings" in param) {
+          setAndLockPref("privacy.clearOnShutdown.siteSettings", param.SiteSettings);
+        }
+        if ("OfflineApps" in param) {
+          setAndLockPref("privacy.clearOnShutdown.offlineApps", param.OfflineApps);
+        }
       }
     },
   },
 
   "SearchBar": {
     onAllWindowsRestored(manager, param) {
       // This policy is meant to change the default behavior, not to force it.
       // If this policy was already applied and the user chose move the search
--- a/browser/components/enterprisepolicies/content/aboutPolicies.js
+++ b/browser/components/enterprisepolicies/content/aboutPolicies.js
@@ -225,16 +225,17 @@ function generateDocumentation() {
   let new_cont = document.getElementById("documentationContent");
   new_cont.setAttribute("id", "documentationContent");
 
   // map specific policies to a different string ID, to allow updates to
   // existing descriptions
   let string_mapping = {
     "DisableSetDesktopBackground": "DisableSetAsDesktopBackground",
     "Certificates": "CertificatesDescription",
+    "SanitizeOnShutdown": "SanitizeOnShutdown2",
   };
 
   for (let policyName in schema.properties) {
     let main_tbody = document.createElement("tbody");
     main_tbody.classList.add("collapsible");
     main_tbody.addEventListener("click", function() {
       let content = this.nextElementSibling;
       content.classList.toggle("content");
--- a/browser/components/enterprisepolicies/schemas/policies-schema.json
+++ b/browser/components/enterprisepolicies/schemas/policies-schema.json
@@ -651,17 +651,43 @@
     "RequestedLocales": {
       "type": ["string", "array"],
       "items": {
         "type": "string"
       }
     },
 
     "SanitizeOnShutdown": {
-      "type": "boolean"
+      "type": ["boolean", "object"],
+      "properties": {
+        "Cache": {
+          "type": "boolean"
+        },
+        "Cookies": {
+          "type": "boolean"
+        },
+        "Downloads": {
+          "type": "boolean"
+        },
+        "FormData": {
+          "type": "boolean"
+        },
+        "History": {
+          "type": "boolean"
+        },
+        "Sessions": {
+          "type": "boolean"
+        },
+        "SiteSettings": {
+          "type": "boolean"
+        },
+        "OfflineApps": {
+          "type": "boolean"
+        }
+      }
     },
 
     "SearchBar": {
       "type": "string",
       "enum": ["unified", "separate"]
     },
 
     "SearchEngines": {
--- a/browser/components/enterprisepolicies/tests/browser/browser_policies_simple_pref_policies.js
+++ b/browser/components/enterprisepolicies/tests/browser/browser_policies_simple_pref_policies.js
@@ -1,8 +1,9 @@
+
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 /*
  * Use this file to add tests to policies that are
  * simple pref flips.
@@ -169,16 +170,154 @@ const POLICIES_TESTS = [
       "privacy.clearOnShutdown.formdata": true,
       "privacy.clearOnShutdown.history": true,
       "privacy.clearOnShutdown.sessions": true,
       "privacy.clearOnShutdown.siteSettings": true,
       "privacy.clearOnShutdown.offlineApps": true,
     },
   },
 
+  {
+    policies: {
+      "SanitizeOnShutdown": {
+        "Cache": true,
+      },
+    },
+    lockedPrefs: {
+      "privacy.sanitize.sanitizeOnShutdown": true,
+      "privacy.clearOnShutdown.cache": true,
+      "privacy.clearOnShutdown.cookies": false,
+      "privacy.clearOnShutdown.downloads": false,
+      "privacy.clearOnShutdown.formdata": false,
+      "privacy.clearOnShutdown.history": false,
+      "privacy.clearOnShutdown.sessions": false,
+    },
+  },
+
+  {
+    policies: {
+      "SanitizeOnShutdown": {
+        "Cookies": true,
+      },
+    },
+    lockedPrefs: {
+      "privacy.sanitize.sanitizeOnShutdown": true,
+      "privacy.clearOnShutdown.cache": false,
+      "privacy.clearOnShutdown.cookies": true,
+      "privacy.clearOnShutdown.downloads": false,
+      "privacy.clearOnShutdown.formdata": false,
+      "privacy.clearOnShutdown.history": false,
+      "privacy.clearOnShutdown.sessions": false,
+    },
+  },
+
+  {
+    policies: {
+      "SanitizeOnShutdown": {
+        "Downloads": true,
+      },
+    },
+    lockedPrefs: {
+      "privacy.sanitize.sanitizeOnShutdown": true,
+      "privacy.clearOnShutdown.cache": false,
+      "privacy.clearOnShutdown.cookies": false,
+      "privacy.clearOnShutdown.downloads": true,
+      "privacy.clearOnShutdown.formdata": false,
+      "privacy.clearOnShutdown.history": false,
+      "privacy.clearOnShutdown.sessions": false,
+    },
+  },
+
+  {
+    policies: {
+      "SanitizeOnShutdown": {
+        "FormData": true,
+      },
+    },
+    lockedPrefs: {
+      "privacy.sanitize.sanitizeOnShutdown": true,
+      "privacy.clearOnShutdown.cache": false,
+      "privacy.clearOnShutdown.cookies": false,
+      "privacy.clearOnShutdown.downloads": false,
+      "privacy.clearOnShutdown.formdata": true,
+      "privacy.clearOnShutdown.history": false,
+      "privacy.clearOnShutdown.sessions": false,
+    },
+  },
+
+  {
+    policies: {
+      "SanitizeOnShutdown": {
+        "History": true,
+      },
+    },
+    lockedPrefs: {
+      "privacy.sanitize.sanitizeOnShutdown": true,
+      "privacy.clearOnShutdown.cache": false,
+      "privacy.clearOnShutdown.cookies": false,
+      "privacy.clearOnShutdown.downloads": false,
+      "privacy.clearOnShutdown.formdata": false,
+      "privacy.clearOnShutdown.history": true,
+      "privacy.clearOnShutdown.sessions": false,
+    },
+  },
+
+  {
+    policies: {
+      "SanitizeOnShutdown": {
+        "Sessions": true,
+      },
+    },
+    lockedPrefs: {
+      "privacy.sanitize.sanitizeOnShutdown": true,
+      "privacy.clearOnShutdown.cache": false,
+      "privacy.clearOnShutdown.cookies": false,
+      "privacy.clearOnShutdown.downloads": false,
+      "privacy.clearOnShutdown.formdata": false,
+      "privacy.clearOnShutdown.history": false,
+      "privacy.clearOnShutdown.sessions": true,
+    },
+  },
+
+  {
+    policies: {
+      "SanitizeOnShutdown": {
+        "SiteSettings": true,
+      },
+    },
+    lockedPrefs: {
+      "privacy.sanitize.sanitizeOnShutdown": true,
+      "privacy.clearOnShutdown.cache": false,
+      "privacy.clearOnShutdown.cookies": false,
+      "privacy.clearOnShutdown.downloads": false,
+      "privacy.clearOnShutdown.formdata": false,
+      "privacy.clearOnShutdown.history": false,
+      "privacy.clearOnShutdown.sessions": false,
+      "privacy.clearOnShutdown.siteSettings": true,
+    },
+  },
+
+  {
+    policies: {
+      "SanitizeOnShutdown": {
+        "OfflineApps": true,
+      },
+    },
+    lockedPrefs: {
+      "privacy.sanitize.sanitizeOnShutdown": true,
+      "privacy.clearOnShutdown.cache": false,
+      "privacy.clearOnShutdown.cookies": false,
+      "privacy.clearOnShutdown.downloads": false,
+      "privacy.clearOnShutdown.formdata": false,
+      "privacy.clearOnShutdown.history": false,
+      "privacy.clearOnShutdown.sessions": false,
+      "privacy.clearOnShutdown.offlineApps": true,
+    },
+  },
+
   // POLICY: DNSOverHTTPS Locked
   {
     policies: {
       "DNSOverHTTPS": {
         "Enabled": true,
         "ProviderURL": "http://example.com/provider",
         "Locked": true,
       },
@@ -285,17 +424,17 @@ const POLICIES_TESTS = [
       "SearchSuggestEnabled": false,
     },
     lockedPrefs: {
       "browser.urlbar.suggest.searches": false,
     },
   },
 ];
 
-add_task(async function test_policy_remember_passwords() {
+add_task(async function test_policy_simple_prefs() {
   for (let test of POLICIES_TESTS) {
     await setupPolicyEngineWithJson({
       "policies": test.policies,
     });
 
     info("Checking policy: " + Object.keys(test.policies)[0]);
 
     for (let [prefName, prefValue] of Object.entries(test.lockedPrefs || {})) {
--- a/browser/components/extensions/test/browser/browser_ext_menus_activeTab.js
+++ b/browser/components/extensions/test/browser/browser_ext_menus_activeTab.js
@@ -34,16 +34,20 @@ async function openTwoTabsAndOpenTabMenu
       "permissions": ["menus", "activeTab"],
     },
     background: `(${background})(${onTabMenuClicked})`,
   });
 
   await extension.startup();
   await extension.awaitMessage("ready");
 
+  // Focus a selected tab to to make tabbrowser.js to load localization files,
+  // and thereby initialize document.l10n property.
+  gBrowser.selectedTab.focus();
+
   // The .tabbrowser-tab selector matches the first tab (tab1).
   let menu = await openChromeContextMenu("tabContextMenu", ".tabbrowser-tab", window);
   let menuItem = menu.getElementsByAttribute("label", "menu item on tab")[0];
   await closeTabContextMenu(menuItem);
   await extension.awaitMessage("onCommand_on_tab_click");
 
   await extension.unload();
 
--- a/browser/components/newtab/common/Reducers.jsm
+++ b/browser/components/newtab/common/Reducers.jsm
@@ -504,17 +504,17 @@ function DiscoveryStream(prevState = INI
           loaded: true,
         },
       };
     case at.DISCOVERY_STREAM_SPOCS_CAPS:
       return {
         ...prevState,
         spocs: {
           ...prevState.spocs,
-          frequency_caps: action.data,
+          frequency_caps: [...prevState.spocs.frequency_caps, ...action.data],
         },
       };
     case at.DISCOVERY_STREAM_SPOCS_ENDPOINT:
       return {
         ...prevState,
         spocs: {
           ...INITIAL_STATE.DiscoveryStream.spocs,
           spocs_endpoint: action.data || INITIAL_STATE.DiscoveryStream.spocs.spocs_endpoint,
--- a/browser/components/newtab/content-src/activity-stream.jsx
+++ b/browser/components/newtab/content-src/activity-stream.jsx
@@ -1,34 +1,27 @@
 import {actionCreators as ac, actionTypes as at} from "common/Actions.jsm";
-import {addSnippetsSubscriber} from "content-src/lib/snippets";
-import {ASRouterContent} from "content-src/asrouter/asrouter-content";
 import {Base} from "content-src/components/Base/Base";
 import {DetectUserSessionStart} from "content-src/lib/detect-user-session-start";
-import {enableASRouterContent} from "content-src/lib/asroutercontent";
 import {initStore} from "content-src/lib/init-store";
 import {Provider} from "react-redux";
 import React from "react";
 import ReactDOM from "react-dom";
 import {reducers} from "common/Reducers.jsm";
 
 const store = initStore(reducers, global.gActivityStreamPrerenderedState);
-const asrouterContent = new ASRouterContent();
 
 new DetectUserSessionStart(store).sendEventOrAddListener();
 
 // If we are starting in a prerendered state, we must wait until the first render
 // to request state rehydration (see Base.jsx). If we are NOT in a prerendered state,
 // we can request it immedately.
 if (!global.gActivityStreamPrerenderedState) {
   store.dispatch(ac.AlsoToMain({type: at.NEW_TAB_STATE_REQUEST}));
 }
-enableASRouterContent(store, asrouterContent);
 
 ReactDOM.hydrate(<Provider store={store}>
   <Base
     isFirstrun={global.document.location.href === "about:welcome"}
     isPrerendered={!!global.gActivityStreamPrerenderedState}
     locale={global.document.documentElement.lang}
     strings={global.gActivityStreamStrings} />
 </Provider>, document.getElementById("root"));
-
-addSnippetsSubscriber(store);
--- a/browser/components/newtab/content-src/asrouter/asrouter-content.jsx
+++ b/browser/components/newtab/content-src/asrouter/asrouter-content.jsx
@@ -2,34 +2,38 @@ import {addLocaleData, IntlProvider} fro
 import {actionCreators as ac} from "common/Actions.jsm";
 import {OUTGOING_MESSAGE_NAME as AS_GENERAL_OUTGOING_MESSAGE_NAME} from "content-src/lib/init-store";
 import {generateMessages} from "./rich-text-strings";
 import {ImpressionsWrapper} from "./components/ImpressionsWrapper/ImpressionsWrapper";
 import {LocalizationProvider} from "fluent-react";
 import {NEWTAB_DARK_THEME} from "content-src/lib/constants";
 import {OnboardingMessage} from "./templates/OnboardingMessage/OnboardingMessage";
 import React from "react";
-import ReactDOM from "react-dom";
 import {ReturnToAMO} from "./templates/ReturnToAMO/ReturnToAMO";
 import {SnippetsTemplates} from "./templates/template-manifest";
 import {StartupOverlay} from "./templates/StartupOverlay/StartupOverlay";
 
 const INCOMING_MESSAGE_NAME = "ASRouter:parent-to-child";
 const OUTGOING_MESSAGE_NAME = "ASRouter:child-to-parent";
-const ASR_CONTAINER_ID = "asr-newtab-container";
 
 export const ASRouterUtils = {
   addListener(listener) {
-    global.RPMAddMessageListener(INCOMING_MESSAGE_NAME, listener);
+    if (global.RPMAddMessageListener) {
+      global.RPMAddMessageListener(INCOMING_MESSAGE_NAME, listener);
+    }
   },
   removeListener(listener) {
-    global.RPMRemoveMessageListener(INCOMING_MESSAGE_NAME, listener);
+    if (global.RPMRemoveMessageListener) {
+      global.RPMRemoveMessageListener(INCOMING_MESSAGE_NAME, listener);
+    }
   },
   sendMessage(action) {
-    global.RPMSendAsyncMessage(OUTGOING_MESSAGE_NAME, action);
+    if (global.RPMSendAsyncMessage) {
+      global.RPMSendAsyncMessage(OUTGOING_MESSAGE_NAME, action);
+    }
   },
   blockById(id, options) {
     ASRouterUtils.sendMessage({type: "BLOCK_MESSAGE_BY_ID", data: {id, ...options}});
   },
   dismissById(id) {
     ASRouterUtils.sendMessage({type: "DISMISS_MESSAGE_BY_ID", data: {id}});
   },
   dismissBundle(bundle) {
@@ -46,36 +50,38 @@ export const ASRouterUtils = {
   },
   unblockBundle(bundle) {
     ASRouterUtils.sendMessage({type: "UNBLOCK_BUNDLE", data: {bundle}});
   },
   overrideMessage(id) {
     ASRouterUtils.sendMessage({type: "OVERRIDE_MESSAGE", data: {id}});
   },
   sendTelemetry(ping) {
-    const payload = ac.ASRouterUserEvent(ping);
-    global.RPMSendAsyncMessage(AS_GENERAL_OUTGOING_MESSAGE_NAME, payload);
+    if (global.RPMSendAsyncMessage) {
+      const payload = ac.ASRouterUserEvent(ping);
+      global.RPMSendAsyncMessage(AS_GENERAL_OUTGOING_MESSAGE_NAME, payload);
+    }
   },
   getPreviewEndpoint() {
-    if (window.location.href.includes("endpoint")) {
-      const params = new URLSearchParams(window.location.href.slice(window.location.href.indexOf("endpoint")));
+    if (global.location && global.location.href.includes("endpoint")) {
+      const params = new URLSearchParams(global.location.href.slice(global.location.href.indexOf("endpoint")));
       try {
         const endpoint = new URL(params.get("endpoint"));
         return {
           url: endpoint.href,
           snippetId: params.get("snippetId"),
           theme: this.getPreviewTheme(),
         };
       } catch (e) {}
     }
 
     return null;
   },
   getPreviewTheme() {
-    return new URLSearchParams(window.location.href.slice(window.location.href.indexOf("theme"))).get("theme");
+    return new URLSearchParams(global.location.href.slice(global.location.href.indexOf("theme"))).get("theme");
   },
 };
 
 // Note: nextProps/prevProps refer to props passed to <ImpressionsWrapper />, not <ASRouterUISurface />
 function shouldSendImpressionOnUpdate(nextProps, prevProps) {
   return (nextProps.message.id && (!prevProps.message || prevProps.message.id !== nextProps.message.id));
 }
 
@@ -179,27 +185,29 @@ export class ASRouterUISurface extends R
         }
         break;
       case "CLEAR_ALL":
         this.setState({message: {}, bundle: {}});
     }
   }
 
   componentWillMount() {
-    // Add locale data for StartupOverlay because it uses react-intl
-    addLocaleData(global.document.documentElement.lang);
+    if (global.document) {
+      // Add locale data for StartupOverlay because it uses react-intl
+      addLocaleData(global.document.documentElement.lang);
+    }
 
     const endpoint = ASRouterUtils.getPreviewEndpoint();
     if (endpoint && endpoint.theme === "dark") {
       global.window.dispatchEvent(new CustomEvent("LightweightTheme:Set", {detail: {data: NEWTAB_DARK_THEME}}));
     }
     ASRouterUtils.addListener(this.onMessageFromParent);
 
     // If we are loading about:welcome we want to trigger the onboarding messages
-    if (this.props.document.location.href === "about:welcome") {
+    if (this.props.document && this.props.document.location.href === "about:welcome") {
       ASRouterUtils.sendMessage({type: "TRIGGER", data: {trigger: {id: "firstRun"}}});
     } else {
       ASRouterUtils.sendMessage({type: "SNIPPETS_REQUEST", data: {endpoint}});
     }
   }
 
   componentWillUnmount() {
     ASRouterUtils.removeListener(this.onMessageFromParent);
@@ -252,18 +260,17 @@ export class ASRouterUISurface extends R
     const {message} = this.state;
     if (message.template === "fxa_overlay") {
       global.document.body.classList.add("fxa");
       return (
         <IntlProvider locale={global.document.documentElement.lang} messages={global.gActivityStreamStrings}>
           <StartupOverlay
             onReady={this.triggerOnboarding}
             onBlock={this.onDismissById(message.id)}
-            dispatch={this.props.activityStreamStore.dispatch}
-            store={this.props.activityStreamStore} />
+            dispatch={this.props.dispatch} />
         </IntlProvider>
       );
     } else if (message.template === "return_to_amo_overlay") {
       global.document.body.classList.add("amo");
       return (
         <LocalizationProvider messages={generateMessages({"amo_html": message.content.text})}>
           <ReturnToAMO
             {...message}
@@ -299,44 +306,8 @@ export class ASRouterUISurface extends R
         {this.renderOnboarding()}
         {this.renderSnippets()}
       </React.Fragment>
     );
   }
 }
 
 ASRouterUISurface.defaultProps = {document: global.document};
-
-export class ASRouterContent {
-  constructor() {
-    this.initialized = false;
-    this.containerElement = null;
-  }
-
-  _mount() {
-    this.containerElement = global.document.getElementById(ASR_CONTAINER_ID);
-    if (!this.containerElement) {
-      this.containerElement = global.document.createElement("div");
-      this.containerElement.id = ASR_CONTAINER_ID;
-      this.containerElement.style.zIndex = 1;
-      global.document.body.appendChild(this.containerElement);
-    }
-
-    ReactDOM.render(<ASRouterUISurface activityStreamStore={this._activityStreamStore} />, this.containerElement);
-  }
-
-  _unmount() {
-    ReactDOM.unmountComponentAtNode(this.containerElement);
-  }
-
-  init(store) {
-    this._activityStreamStore = store;
-    this._mount();
-    this.initialized = true;
-  }
-
-  uninit() {
-    if (this.initialized) {
-      this._unmount();
-      this.initialized = false;
-    }
-  }
-}
--- a/browser/components/newtab/content-src/asrouter/components/SnippetBase/_SnippetBase.scss
+++ b/browser/components/newtab/content-src/asrouter/components/SnippetBase/_SnippetBase.scss
@@ -1,12 +1,10 @@
 .SnippetBaseContainer {
   position: fixed;
-  // Make sure ASR snippets show on top of legacy snippets
-  // This can happen when ASR preview is used with legacy snippets
   z-index: 2;
   bottom: 0;
   left: 0;
   right: 0;
   background-color: var(--newtab-snippets-background-color);
   color: var(--newtab-text-primary-color);
   font-size: 14px;
   line-height: 20px;
--- a/browser/components/newtab/content-src/asrouter/docs/debugging-docs.md
+++ b/browser/components/newtab/content-src/asrouter/docs/debugging-docs.md
@@ -32,35 +32,21 @@ To test telemetry pings, complete the th
 - Open the Browser Toolbox devtools (Tools > Developer > Browser Toolbox) and switch to the console tab. Add a filter for for `activity-stream-router` to only display relevant pings:
 
 ![Devtools telemetry pong](./telemetry-screenshot.png)
 
 You should now see pings show up as you view/interact with ASR messages/templates.
 
 ## Snippets debugging
 
-### How to test legacy snippets
-
-To make sure the legacy snippets system is still running properly, do the following:
-
-- Load test data for legacy snippets. In about:config, set `browser.aboutHomeSnippets.updateUrl` to `https://snippets.allizom.org/%STARTPAGE_VERSION%/%NAME%/%VERSION%/%APPBUILDID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/`
-- Disable ASR snippets
-  - set up your ASR devtools (see steps above)
-  - visit `about:newtab#asrouter`
-  - Uncheck the checkbox next to snippets
-- Check `about:newtab` to make sure legacy snippets are loading
-  - visit `about:newtab`
-  - Type gSnippetsMap.clear() into the devtools console and refresh the page
-  - Open the devtools again
-  - Ensure you see the message “Legacy snippets: Successfully added snippets.”
-  - Ensure you visually see snippets on the page
-
 ### How to view preview URLs
 
-Follow these steps to view preview URLs (e.g. `about:newtab?endpoint=https://gist.githubusercontent.com/piatra/d193ca7e0f513cc19fc6a1d396c214f7/raw/8bcaf9548212e4c613577e839198cc14e7317630/newsletter_snippet.json`)
+Follow these steps to view preview URLs (e.g. `about:newtab?endpoint=https://gist.githubusercontent.com/piatra/d193ca7e0f513cc19fc6a1d396c214f7/raw/8bcaf9548212e4c613577e839198cc14e7317630/newsletter_snippet.json&theme=dark`)
+
+You can preview in the two different themes (light and dark) by adding `&theme=dark` or `&theme=light` at the end of the url.
 
 #### IMPORTANT NOTES
 - Links to URLs starting with `about:newtab` cannot be clicked on directly. They must be copy and pasted into the address bar.
 - Previews should only be tested in `Firefox 64` and later.
 - The endpoint must be HTTPS, the host must be whitelisted (see testing instructions below)
 - Errors are surfaced in the `Console` tab of the `Browser Toolbox`
 
 #### Testing instructions
--- a/browser/components/newtab/content-src/components/ASRouterAdmin/ASRouterAdmin.jsx
+++ b/browser/components/newtab/content-src/components/ASRouterAdmin/ASRouterAdmin.jsx
@@ -708,17 +708,17 @@ export class ASRouterAdminInner extends 
           {this.renderMessageFilter()}
           {this.renderMessages()}
           {this.renderPasteModal()}
         </React.Fragment>);
     }
   }
 
   render() {
-    return (<div className="asrouter-admin">
+    return (<div className={`asrouter-admin ${this.props.collapsed ? "collapsed" : "expanded"}`}>
       <aside className="sidebar">
         <ul>
           <li><a href="#devtools">General</a></li>
           <li><a href="#devtools-targeting">Targeting</a></li>
           <li><a href="#devtools-pocket">Pocket</a></li>
           <li><a href="#devtools-ds">Discovery Stream</a></li>
           <li><a href="#devtools-errors">Errors</a></li>
         </ul>
@@ -735,10 +735,59 @@ export class ASRouterAdminInner extends 
       </p>
 
       {this.getSection()}
       </main>
     </div>);
   }
 }
 
-export const _ASRouterAdmin = props => (<SimpleHashRouter><ASRouterAdminInner {...props} /></SimpleHashRouter>);
+export class CollapseToggle extends React.PureComponent {
+  constructor(props) {
+    super(props);
+    this.onCollapseToggle = this.onCollapseToggle.bind(this);
+    this.state = {collapsed: false};
+  }
+
+  get renderAdmin() {
+    const {props} = this;
+    return props.location.hash && (props.location.hash.startsWith("#asrouter") || props.location.hash.startsWith("#devtools"));
+  }
+
+  onCollapseToggle(e) {
+    e.preventDefault();
+    this.setState(state => ({collapsed: !state.collapsed}));
+  }
+
+  setBodyClass() {
+    if (this.renderAdmin && !this.state.collapsed) {
+      global.document.body.classList.add("no-scroll");
+    } else {
+      global.document.body.classList.remove("no-scroll");
+    }
+  }
+
+  componentDidMount() {
+    this.setBodyClass();
+  }
+
+  componentDidUpdate() {
+    this.setBodyClass();
+  }
+
+  componentWillUnmount() {
+    global.document.body.classList.remove("no-scroll");
+  }
+
+  render() {
+    const {props} = this;
+    const {renderAdmin} = this;
+    const action = (this.state.collapsed || !renderAdmin) ? "Expand" : "Collapse";
+    return (<React.Fragment>
+      <a href="#devtools" className="asrouter-toggle" onClick={this.renderAdmin ? this.onCollapseToggle : null}>{action} Devtools</a>
+      {renderAdmin ? <ASRouterAdminInner {...props} collapsed={this.state.collapsed} /> : null}
+    </React.Fragment>);
+  }
+}
+
+const _ASRouterAdmin = props => <SimpleHashRouter><CollapseToggle {...props} /></SimpleHashRouter>;
+
 export const ASRouterAdmin = connect(state => ({Sections: state.Sections, DiscoveryStream: state.DiscoveryStream, Prefs: state.Prefs}))(_ASRouterAdmin);
--- a/browser/components/newtab/content-src/components/ASRouterAdmin/ASRouterAdmin.scss
+++ b/browser/components/newtab/content-src/components/ASRouterAdmin/ASRouterAdmin.scss
@@ -1,19 +1,42 @@
+
+.asrouter-toggle {
+  background: $yellow-50;
+  color: $black;
+  position: fixed;
+  top: 0;
+  left: 43px;
+  padding: 5px 10px;
+  border-radius: 0 0 3px 3px;
+  border: 1px solid $black-10;
+  border-top: 0;
+  z-index: 3000;
+}
 
 .asrouter-admin {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  background: var(--newtab-background-color);
+  height: 100%;
+  overflow-y: scroll;
   $border-color: var(--newtab-border-secondary-color);
   $monospace: 'SF Mono', 'Monaco', 'Inconsolata', 'Fira Mono', 'Droid Sans Mono', 'Source Code Pro', monospace;
   $sidebar-width: 240px;
   margin: 0 auto;
   font-size: 14px;
   padding-left: $sidebar-width;
-  display: flex;
   color: var(--newtab-text-primary-color);
 
+  &.collapsed {
+    display: none;
+  }
+
   .sidebar {
     inset-inline-start: 0;
     position: fixed;
     width: $sidebar-width;
     padding: 30px 20px;
 
     ul {
       margin: 0;
@@ -145,19 +168,18 @@
 
   .errorState {
     border: 1px solid $red-60;
   }
 
   .helpLink {
     padding: 10px;
     display: flex;
-    background: $yellow-50;
+    background: $black-10;
     border-radius: 3px;
-    color: $grey-90;
 
     a {
       text-decoration: underline;
     }
   }
 
   .dsEnabled {
     padding: 10px;
--- a/browser/components/newtab/content-src/components/ASRouterAdmin/SimpleHashRouter.jsx
+++ b/browser/components/newtab/content-src/components/ASRouterAdmin/SimpleHashRouter.jsx
@@ -15,17 +15,17 @@ export class SimpleHashRouter extends Re
     global.addEventListener("hashchange", this.onHashChange);
   }
 
   componentWillUnmount() {
     global.removeEventListener("hashchange", this.onHashChange);
   }
 
   render() {
-    const [, ...routes] = this.state.hash.replace("#asrouter", "").split("-");
+    const [, ...routes] = this.state.hash.split("-");
     return React.cloneElement(this.props.children, {
       location: {
         hash: this.state.hash,
         routes,
       },
     });
   }
 }
--- a/browser/components/newtab/content-src/components/Base/Base.jsx
+++ b/browser/components/newtab/content-src/components/Base/Base.jsx
@@ -1,23 +1,22 @@
 import {actionCreators as ac, actionTypes as at} from "common/Actions.jsm";
 import {addLocaleData, injectIntl, IntlProvider} from "react-intl";
 import {ASRouterAdmin} from "content-src/components/ASRouterAdmin/ASRouterAdmin";
+import {ASRouterUISurface} from "../../asrouter/asrouter-content";
 import {ConfirmDialog} from "content-src/components/ConfirmDialog/ConfirmDialog";
 import {connect} from "react-redux";
 import {DiscoveryStreamBase} from "content-src/components/DiscoveryStreamBase/DiscoveryStreamBase";
 import {ErrorBoundary} from "content-src/components/ErrorBoundary/ErrorBoundary";
 import {ManualMigration} from "content-src/components/ManualMigration/ManualMigration";
 import {PrerenderData} from "common/PrerenderData.jsm";
 import React from "react";
 import {Search} from "content-src/components/Search/Search";
 import {Sections} from "content-src/components/Sections/Sections";
 
-let didLogDevtoolsHelpText = false;
-
 const PrefsButton = injectIntl(props => (
   <div className="prefs-button">
     <button className="icon icon-settings" onClick={props.onClick} title={props.intl.formatMessage({id: "settings_pane_button_label"})} />
   </div>
 ));
 
 // Add the locale data for pluralization and relative-time formatting for now,
 // this just uses english locale data. We can make this more sophisticated if
@@ -77,37 +76,30 @@ export class _Base extends React.PureCom
     ].filter(v => v).join(" ");
     global.document.body.className = bodyClassName;
   }
 
   render() {
     const {props} = this;
     const {App, locale, strings} = props;
     const {initialized} = App;
-
-    const prefs = props.Prefs.values;
-    if (prefs["asrouter.devtoolsEnabled"]) {
-      if (window.location.hash.startsWith("#asrouter") ||
-          window.location.hash.startsWith("#devtools")) {
-        return (<ASRouterAdmin />);
-      } else if (!didLogDevtoolsHelpText) {
-        console.log("Activity Stream devtools enabled. To access visit %cabout:newtab#devtools", "font-weight: bold"); // eslint-disable-line no-console
-        didLogDevtoolsHelpText = true;
-      }
-    }
+    const isDevtoolsEnabled = props.Prefs.values["asrouter.devtoolsEnabled"];
 
     if (!props.isPrerendered && !initialized) {
       return null;
     }
 
     return (<IntlProvider locale={locale} messages={strings}>
-        <ErrorBoundary className="base-content-fallback">
+      <ErrorBoundary className="base-content-fallback">
+        <React.Fragment>
           <BaseContent {...this.props} />
-        </ErrorBoundary>
-      </IntlProvider>);
+          {isDevtoolsEnabled ? <ASRouterAdmin /> : null}
+        </React.Fragment>
+      </ErrorBoundary>
+    </IntlProvider>);
   }
 }
 
 export class BaseContent extends React.PureComponent {
   constructor(props) {
     super(props);
     this.openPreferences = this.openPreferences.bind(this);
     this.onWindowScroll = debounce(this.onWindowScroll.bind(this), 5);
@@ -177,16 +169,17 @@ export class BaseContent extends React.P
                 <ErrorBoundary className="borderless-error">
                   <DiscoveryStreamBase />
                 </ErrorBoundary>) : <Sections />}
               <PrefsButton onClick={this.openPreferences} />
             </div>
             <ConfirmDialog />
           </main>
         </div>
+        <ASRouterUISurface dispatch={this.props.dispatch} />
       </div>);
   }
 }
 
 export const Base = connect(state => ({
   App: state.App,
   Prefs: state.Prefs,
   Sections: state.Sections,
--- a/browser/components/newtab/content-src/components/DiscoveryStreamComponents/CardGrid/_CardGrid.scss
+++ b/browser/components/newtab/content-src/components/DiscoveryStreamComponents/CardGrid/_CardGrid.scss
@@ -29,17 +29,17 @@
           box-shadow: 0 0 0 5px $grey-60;
         }
 
         box-shadow: 0 0 0 5px $grey-30;
         transition: box-shadow 150ms;
         outline: none;
       }
 
-      .img-wrapper .img {
+      .img-wrapper .img img {
         border-radius: 4px 4px 0 0;
       }
     }
   }
 
   &.ds-card-grid-no-border {
     .ds-card {
       background: none;
--- a/browser/components/newtab/content-src/components/DiscoveryStreamComponents/DSImage/DSImage.jsx
+++ b/browser/components/newtab/content-src/components/DiscoveryStreamComponents/DSImage/DSImage.jsx
@@ -1,9 +1,8 @@
-import {cache} from "./cache";
 import React from "react";
 import ReactDOM from "react-dom";
 
 export class DSImage extends React.PureComponent {
   constructor(props) {
     super(props);
 
     this.onOptimizedImageError = this.onOptimizedImageError.bind(this);
@@ -15,34 +14,35 @@ export class DSImage extends React.PureC
   }
 
   onSeen(entries) {
     if (this.state) {
       if (entries.some(entry => entry.isIntersecting)) {
         if (this.props.optimize) {
           this.setState({
             containerWidth: ReactDOM.findDOMNode(this).clientWidth,
+            containerHeight: ReactDOM.findDOMNode(this).clientHeight,
           });
         }
 
         this.setState({
           isSeen: true,
         });
 
         // Stop observing since element has been seen
         this.observer.unobserve(ReactDOM.findDOMNode(this));
       }
     }
   }
 
-  reformatImageURL(url, width) {
+  reformatImageURL(url, width, height) {
     // Change the image URL to request a size tailored for the parent container width
     // Also: force JPEG, quality 60, no upscaling, no EXIF data
     // Uses Thumbor: https://thumbor.readthedocs.io/en/latest/usage.html
-    return `https://img-getpocket.cdn.mozilla.net/${width}x0/filters:format(jpeg):quality(60):no_upscale():strip_exif()/${encodeURIComponent(url)}`;
+    return `https://img-getpocket.cdn.mozilla.net/${width}x${height}/filters:format(jpeg):quality(60):no_upscale():strip_exif()/${encodeURIComponent(url)}`;
   }
 
   componentDidMount() {
     this.observer = new IntersectionObserver(this.onSeen.bind(this));
     this.observer.observe(ReactDOM.findDOMNode(this));
   }
 
   componentWillUnmount() {
@@ -62,22 +62,24 @@ export class DSImage extends React.PureC
         let source;
         let source2x;
 
         if (this.state && this.state.containerWidth) {
           let baseSource = this.props.rawSource;
 
           source = this.reformatImageURL(
             baseSource,
-            cache.query(baseSource, this.state.containerWidth, `1x`)
+            this.state.containerWidth,
+            this.state.containerHeight
           );
 
           source2x = this.reformatImageURL(
             baseSource,
-            cache.query(baseSource, this.state.containerWidth * 2, `2x`)
+            this.state.containerWidth * 2,
+            this.state.containerHeight * 2
           );
 
           img = (<img onError={this.onOptimizedImageError} src={source} srcSet={`${source2x} 2x`} />);
         }
       } else {
         img = (<img src={this.props.source} />);
       }
     }
deleted file mode 100644
--- a/browser/components/newtab/content-src/components/DiscoveryStreamComponents/DSImage/cache.js
+++ /dev/null
@@ -1,28 +0,0 @@
-// This cache is for tracking queued image source requests from DSImage instances and leveraging
-//  larger sizes of images to scale down in the browser instead of making additional
-//  requests for smaller sizes from the server.
-
-let cache = {
-  query(url, size, set) {
-    // Create an empty set if none exists
-    // Need multiple cache sets because the browser decides what set to use based on pixel density
-    if (this.queuedImages[set] === undefined) {
-      this.queuedImages[set] = {};
-    }
-
-    let sizeToRequest; // The px width to request from Thumbor via query value
-
-    if (!this.queuedImages[set][url] || this.queuedImages[set][url] < size) {
-      this.queuedImages[set][url] = size;
-      sizeToRequest = size;
-    } else {
-      // Use the larger size already queued for download (and allow browser to scale down)
-      sizeToRequest = this.queuedImages[set][url];
-    }
-
-    return sizeToRequest;
-  },
-  queuedImages: {},
-};
-
-export {cache};
--- a/browser/components/newtab/content-src/components/DiscoveryStreamComponents/Hero/Hero.jsx
+++ b/browser/components/newtab/content-src/components/DiscoveryStreamComponents/Hero/Hero.jsx
@@ -37,16 +37,17 @@ export class Hero extends React.PureComp
     const cards = [];
     for (let index = 0; index < this.props.items - 1; index++) {
       const rec = otherRecs[index];
       cards.push(rec ? (
         <DSCard
         campaignId={rec.campaign_id}
         key={`dscard-${index}`}
         image_src={rec.image_src}
+        raw_image_src={rec.raw_image_src}
         title={rec.title}
         url={rec.url}
         id={rec.id}
         pos={rec.pos}
         type={this.props.type}
         dispatch={this.props.dispatch}
         context={rec.context}
         source={rec.domain}
--- a/browser/components/newtab/content-src/components/ManualMigration/_ManualMigration.scss
+++ b/browser/components/newtab/content-src/components/ManualMigration/_ManualMigration.scss
@@ -21,16 +21,17 @@
   }
 
   .icon {
     display: none;
     @media (min-width: $break-point-medium) {
       align-self: center;
       display: block;
       fill: var(--newtab-icon-secondary-color);
+      flex-shrink: 0;
       margin-inline-end: 6px;
     }
   }
 }
 
 .manual-migration-actions {
   border: 0;
   display: block;
deleted file mode 100644
--- a/browser/components/newtab/content-src/lib/asroutercontent.js
+++ /dev/null
@@ -1,15 +0,0 @@
-export function enableASRouterContent(store, asrouterContent) {
-  // Enable asrouter content
-  store.subscribe(() => {
-    const state = store.getState();
-    if (!state.ASRouter.initialized) {
-      return;
-    }
-
-    if (!asrouterContent.initialized) {
-      asrouterContent.init(store);
-    }
-  });
-  // Return this for testing purposes
-  return {asrouterContent};
-}
deleted file mode 100644
--- a/browser/components/newtab/content-src/lib/snippets.js
+++ /dev/null
@@ -1,433 +0,0 @@
-const DATABASE_NAME = "snippets_db";
-const DATABASE_VERSION = 1;
-const SNIPPETS_OBJECTSTORE_NAME = "snippets";
-export const SNIPPETS_UPDATE_INTERVAL_MS = 14400000; // 4 hours.
-
-const SNIPPETS_ENABLED_EVENT = "Snippets:Enabled";
-const SNIPPETS_DISABLED_EVENT = "Snippets:Disabled";
-
-import {actionCreators as ac, actionTypes as at} from "common/Actions.jsm";
-
-/**
- * SnippetsMap - A utility for cacheing values related to the snippet. It has
- *               the same interface as a Map, but is optionally backed by
- *               indexedDB for persistent storage.
- *               Call .connect() to open a database connection and restore any
- *               previously cached data, if necessary.
- *
- */
-export class SnippetsMap extends Map {
-  constructor(dispatch) {
-    super();
-    this._db = null;
-    this._dispatch = dispatch;
-  }
-
-  set(key, value) {
-    super.set(key, value);
-    return this._dbTransaction(db => db.put(value, key));
-  }
-
-  delete(key) {
-    super.delete(key);
-    return this._dbTransaction(db => db.delete(key));
-  }
-
-  clear() {
-    super.clear();
-    this._dispatch(ac.OnlyToMain({type: at.SNIPPETS_BLOCKLIST_CLEARED}));
-    return this._dbTransaction(db => db.clear());
-  }
-
-  get blockList() {
-    return this.get("blockList") || [];
-  }
-
-  /**
-   * blockSnippetById - Blocks a snippet given an id
-   *
-   * @param  {str|int} id   The id of the snippet
-   * @return {Promise}      Resolves when the id has been written to indexedDB,
-   *                        or immediately if the snippetMap is not connected
-   */
-  async blockSnippetById(id) {
-    if (!id) {
-      return;
-    }
-    const {blockList} = this;
-    if (!blockList.includes(id)) {
-      blockList.push(id);
-      this._dispatch(ac.AlsoToMain({type: at.SNIPPETS_BLOCKLIST_UPDATED, data: id}));
-      await this.set("blockList", blockList);
-    }
-  }
-
-  disableOnboarding() {}
-
-  showFirefoxAccounts() {
-    this._dispatch(ac.AlsoToMain({type: at.SHOW_FIREFOX_ACCOUNTS}));
-  }
-
-  getTotalBookmarksCount() {
-    return new Promise(resolve => {
-      this._dispatch(ac.OnlyToMain({type: at.TOTAL_BOOKMARKS_REQUEST}));
-      global.RPMAddMessageListener("ActivityStream:MainToContent", function onMessage({data: action}) {
-        if (action.type === at.TOTAL_BOOKMARKS_RESPONSE) {
-          resolve(action.data);
-          global.RPMRemoveMessageListener("ActivityStream:MainToContent", onMessage);
-        }
-      });
-    });
-  }
-
-  getAddonsInfo() {
-    return new Promise(resolve => {
-      this._dispatch(ac.OnlyToMain({type: at.ADDONS_INFO_REQUEST}));
-      global.RPMAddMessageListener("ActivityStream:MainToContent", function onMessage({data: action}) {
-        if (action.type === at.ADDONS_INFO_RESPONSE) {
-          resolve(action.data);
-          global.RPMRemoveMessageListener("ActivityStream:MainToContent", onMessage);
-        }
-      });
-    });
-  }
-
-  /**
-   * connect - Attaches an indexedDB back-end to the Map so that any set values
-   *           are also cached in a store. It also restores any existing values
-   *           that are already stored in the indexedDB store.
-   *
-   * @return {type}  description
-   */
-  async connect() {
-    // Open the connection
-    const db = await this._openDB();
-
-    // Restore any existing values
-    await this._restoreFromDb(db);
-
-    // Attach a reference to the db
-    this._db = db;
-  }
-
-  /**
-   * _dbTransaction - Returns a db transaction wrapped with the given modifier
-   *                  function as a Promise. If the db has not been connected,
-   *                  it resolves immediately.
-   *
-   * @param  {func} modifier A function to call with the transaction
-   * @return {obj}           A Promise that resolves when the transaction has
-   *                         completed or errored
-   */
-  _dbTransaction(modifier) {
-    if (!this._db) {
-      return Promise.resolve();
-    }
-    return new Promise((resolve, reject) => {
-      const transaction = modifier(
-        this._db
-          .transaction(SNIPPETS_OBJECTSTORE_NAME, "readwrite")
-          .objectStore(SNIPPETS_OBJECTSTORE_NAME)
-      );
-      transaction.onsuccess = event => resolve();
-
-      /* istanbul ignore next */
-      transaction.onerror = event => reject(transaction.error);
-    });
-  }
-
-  _openDB() {
-    return new Promise((resolve, reject) => {
-      const openRequest = indexedDB.open(DATABASE_NAME, DATABASE_VERSION);
-
-      /* istanbul ignore next */
-      openRequest.onerror = event => {
-        // Try to delete the old database so that we can start this process over
-        // next time.
-        indexedDB.deleteDatabase(DATABASE_NAME);
-        reject(event);
-      };
-
-      openRequest.onupgradeneeded = event => {
-        const db = event.target.result;
-        if (!db.objectStoreNames.contains(SNIPPETS_OBJECTSTORE_NAME)) {
-          db.createObjectStore(SNIPPETS_OBJECTSTORE_NAME);
-        }
-      };
-
-      openRequest.onsuccess = event => {
-        let db = event.target.result;
-
-        /* istanbul ignore next */
-        db.onerror = err => console.error(err); // eslint-disable-line no-console
-        /* istanbul ignore next */
-        db.onversionchange = versionChangeEvent => versionChangeEvent.target.close();
-
-        resolve(db);
-      };
-    });
-  }
-
-  _restoreFromDb(db) {
-    return new Promise((resolve, reject) => {
-      let cursorRequest;
-      try {
-        cursorRequest = db.transaction(SNIPPETS_OBJECTSTORE_NAME)
-          .objectStore(SNIPPETS_OBJECTSTORE_NAME).openCursor();
-      } catch (err) {
-        // istanbul ignore next
-        reject(err);
-        // istanbul ignore next
-        return;
-      }
-
-      /* istanbul ignore next */
-      cursorRequest.onerror = event => reject(event);
-
-      cursorRequest.onsuccess = event => {
-        let cursor = event.target.result;
-        // Populate the cache from the persistent storage.
-        if (cursor) {
-          if (cursor.value !== "blockList") {
-            this.set(cursor.key, cursor.value);
-          }
-          cursor.continue();
-        } else {
-          // We are done.
-          resolve();
-        }
-      };
-    });
-  }
-}
-
-/**
- * SnippetsProvider - Initializes a SnippetsMap and loads snippets from a
- *                    remote location, or else default snippets if the remote
- *                    snippets cannot be retrieved.
- */
-export class SnippetsProvider {
-  constructor(dispatch) {
-    // Initialize the Snippets Map and attaches it to a global so that
-    // the snippet payload can interact with it.
-    global.gSnippetsMap = new SnippetsMap(dispatch);
-    this._onAction = this._onAction.bind(this);
-  }
-
-  get snippetsMap() {
-    return global.gSnippetsMap;
-  }
-
-  async _refreshSnippets() {
-    // Check if the cached version of of the snippets in snippetsMap. If it's too
-    // old, blow away the entire snippetsMap.
-    const cachedVersion = this.snippetsMap.get("snippets-cached-version");
-
-    if (cachedVersion !== this.appData.version) {
-      this.snippetsMap.clear();
-    }
-
-    // Has enough time passed for us to require an update?
-    const lastUpdate = this.snippetsMap.get("snippets-last-update");
-    const needsUpdate = !(lastUpdate >= 0) || Date.now() - lastUpdate > SNIPPETS_UPDATE_INTERVAL_MS;
-
-    if (needsUpdate && this.appData.snippetsURL) {
-      this.snippetsMap.set("snippets-last-update", Date.now());
-      try {
-        const response = await fetch(this.appData.snippetsURL);
-        if (response.status === 200) {
-          const payload = await response.text();
-
-          this.snippetsMap.set("snippets", payload);
-          this.snippetsMap.set("snippets-cached-version", this.appData.version);
-        }
-      } catch (e) {
-        console.error(e); // eslint-disable-line no-console
-      }
-    }
-  }
-
-  _showRemoteSnippets() {
-    const snippetsEl = document.getElementById(this.elementId);
-    const payload = this.snippetsMap.get("snippets");
-
-    if (!snippetsEl) {
-      throw new Error(`No element was found with id '${this.elementId}'.`);
-    }
-
-    // This could happen if fetching failed
-    if (!payload) {
-      throw new Error("No remote snippets were found in gSnippetsMap.");
-    }
-
-    if (typeof payload !== "string") {
-      throw new Error("Snippet payload was incorrectly formatted");
-    }
-
-    // Note that injecting snippets can throw if they're invalid XML.
-    // eslint-disable-next-line no-unsanitized/property
-    snippetsEl.innerHTML = payload;
-
-    this._logIfDevtools("Successfully added snippets.");
-
-    // Scripts injected by innerHTML are inactive, so we have to relocate them
-    // through DOM manipulation to activate their contents.
-    for (const scriptEl of snippetsEl.getElementsByTagName("script")) {
-      const relocatedScript = document.createElement("script");
-      relocatedScript.text = scriptEl.text;
-      scriptEl.parentNode.replaceChild(relocatedScript, scriptEl);
-    }
-  }
-
-  _onAction(msg) {
-    if (msg.data.type === at.SNIPPET_BLOCKED) {
-      if (!this.snippetsMap.blockList.includes(msg.data.data)) {
-        this.snippetsMap.set("blockList", this.snippetsMap.blockList.concat(msg.data.data));
-        document.getElementById("snippets-container").style.display = "none";
-      }
-    }
-  }
-
-  // istanbul ignore next
-  _logIfDevtools(text) {
-    if (this.devtoolsEnabled) {
-      console.log("Legacy snippets:", text); // eslint-disable-line no-console
-    }
-  }
-
-  /**
-   * init - Fetch the snippet payload and show snippets
-   *
-   * @param  {obj} options
-   * @param  {str} options.appData.snippetsURL  The URL from which we fetch snippets
-   * @param  {int} options.appData.version  The current snippets version
-   * @param  {str} options.elementId  The id of the element in which to inject snippets
-   * @param  {bool} options.connect  Should gSnippetsMap connect to indexedDB?
-   */
-  async init(options) {
-    Object.assign(this, {
-      appData: {},
-      elementId: "snippets",
-      connect: true,
-      devtoolsEnabled: false,
-    }, options);
-
-    this._logIfDevtools("Initializing...");
-
-    // Add listener so we know when snippets are blocked on other pages
-    if (global.RPMAddMessageListener) {
-      global.RPMAddMessageListener("ActivityStream:MainToContent", this._onAction);
-    }
-
-    // TODO: Requires enabling indexedDB on newtab
-    // Restore the snippets map from indexedDB
-    if (this.connect) {
-      try {
-        await this.snippetsMap.connect();
-      } catch (e) {
-        console.error(e); // eslint-disable-line no-console
-      }
-    }
-
-    // Cache app data values so they can be accessible from gSnippetsMap
-    for (const key of Object.keys(this.appData)) {
-      if (key === "blockList") {
-        this.snippetsMap.set("blockList", this.appData[key]);
-      } else {
-        this.snippetsMap.set(`appData.${key}`, this.appData[key]);
-      }
-    }
-
-    // Refresh snippets, if enough time has passed.
-    await this._refreshSnippets();
-
-    // Try showing remote snippets, falling back to defaults if necessary.
-    try {
-      this._showRemoteSnippets();
-    } catch (e) {
-      this._logIfDevtools("Problem inserting remote snippets!");
-      console.error(e); // eslint-disable-line no-console
-    }
-
-    window.dispatchEvent(new Event(SNIPPETS_ENABLED_EVENT));
-
-    this.initialized = true;
-    this._logIfDevtools("Finished initializing.");
-  }
-
-  uninit() {
-    window.dispatchEvent(new Event(SNIPPETS_DISABLED_EVENT));
-    if (global.RPMRemoveMessageListener) {
-      global.RPMRemoveMessageListener("ActivityStream:MainToContent", this._onAction);
-    }
-    this.initialized = false;
-  }
-}
-
-/**
- * addSnippetsSubscriber - Creates a SnippetsProvider that Initializes
- *                         when the store has received the appropriate
- *                         Snippet data.
- *
- * @param  {obj} store   The redux store
- * @return {obj}         Returns the snippets instance, asrouterContent instance and unsubscribe function
- */
-export function addSnippetsSubscriber(store) {
-  const snippets = new SnippetsProvider(store.dispatch);
-
-  let initializing = false;
-
-  store.subscribe(async () => {
-    const state = store.getState();
-
-    /**
-     * Sorry this code is so complicated. It will be removed soon.
-     * This is what the different values actually mean:
-     *
-     * ASRouter.initialized                   Is ASRouter.jsm initialised?
-     * ASRouter.allowLegacySnippets           Are ASRouter snippets turned OFF (i.e. legacy snippets are allowed)
-     * state.Prefs.values["feeds.snippets"]   User preference for snippets
-     * state.Snippets.initialized             Is SnippetsFeed.jsm initialised?
-     * snippets.initialized                   Is in-content snippets currently initialised?
-     * state.Prefs.values.disableSnippets     This pref is used to disable legacy snippets in an emergency
-     *                                        in a way that is not user-editable (true = disabled)
-     */
-
-    /** If we should initialize snippets... */
-    if (
-      state.Prefs.values["feeds.snippets"] &&
-      state.ASRouter.initialized &&
-      state.ASRouter.allowLegacySnippets &&
-      !state.Prefs.values.disableSnippets &&
-      state.Snippets.initialized &&
-      !snippets.initialized &&
-      // Don't call init multiple times
-      !initializing &&
-      location.href !== "about:welcome" &&
-      location.hash !== "#asrouter"
-    ) {
-      initializing = true;
-      await snippets.init({appData: state.Snippets, devtoolsEnabled: state.Prefs.values["asrouter.devtoolsEnabled"]});
-      initializing = false;
-
-    /** If we should remove snippets... */
-    } else if (
-      (
-        state.Prefs.values["feeds.snippets"] === false ||
-        state.Prefs.values.disableSnippets === true ||
-        (state.ASRouter.initialized && !state.ASRouter.allowLegacySnippets)
-      ) &&
-      snippets.initialized
-    ) {
-      // Remove snippets
-      snippets.uninit();
-      // istanbul ignore if
-      if (state.Prefs.values["asrouter.devtoolsEnabled"]) {
-        console.log("Legacy snippets removed"); // eslint-disable-line no-console
-      }
-    }
-  });
-
-  // Returned for testing purposes
-  return {snippets};
-}
--- a/browser/components/newtab/content-src/styles/_activity-stream.scss
+++ b/browser/components/newtab/content-src/styles/_activity-stream.scss
@@ -15,16 +15,20 @@ body,
 
 body {
   background-color: var(--newtab-background-color);
   font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Ubuntu', 'Helvetica Neue', sans-serif;
   font-size: 16px;
   overflow-y: scroll;
 }
 
+.no-scroll {
+  overflow: hidden;
+}
+
 h1,
 h2 {
   font-weight: normal;
 }
 
 a {
   text-decoration: none;
 }
--- a/browser/components/newtab/css/activity-stream-linux.css
+++ b/browser/components/newtab/css/activity-stream-linux.css
@@ -237,16 +237,19 @@ body,
   min-height: 100vh; }
 
 body {
   background-color: var(--newtab-background-color);
   font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Ubuntu', 'Helvetica Neue', sans-serif;
   font-size: 16px;
   overflow-y: scroll; }
 
+.no-scroll {
+  overflow: hidden; }
+
 h1,
 h2 {
   font-weight: normal; }
 
 a {
   text-decoration: none; }
 
 .sr-only {
@@ -1532,16 +1535,17 @@ main {
         justify-content: space-between; } }
   .manual-migration-container .icon {
     display: none; }
     @media (min-width: 610px) {
       .manual-migration-container .icon {
         align-self: center;
         display: block;
         fill: var(--newtab-icon-secondary-color);
+        flex-shrink: 0;
         margin-inline-end: 6px; } }
 
 .manual-migration-actions {
   border: 0;
   display: block;
   flex-wrap: nowrap; }
   @media (min-width: 610px) {
     .manual-migration-actions {
@@ -1639,22 +1643,42 @@ main {
     transition: max-height 0.5s cubic-bezier(0.07, 0.95, 0, 1); }
   .collapsible-section.collapsed .section-body {
     max-height: 0;
     overflow: hidden; }
   @media (min-width: 610px) and (max-width: 865px) {
     .collapsible-section[data-section-id='topstories'] .card-outer:first-child {
       display: none; } }
 
+.asrouter-toggle {
+  background: #FFE900;
+  color: #000;
+  position: fixed;
+  top: 0;
+  left: 43px;
+  padding: 5px 10px;
+  border-radius: 0 0 3px 3px;
+  border: 1px solid rgba(0, 0, 0, 0.1);
+  border-top: 0;
+  z-index: 3000; }
+
 .asrouter-admin {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  background: var(--newtab-background-color);
+  height: 100%;
+  overflow-y: scroll;
   margin: 0 auto;
   font-size: 14px;
   padding-left: 240px;
-  display: flex;
   color: var(--newtab-text-primary-color); }
+  .asrouter-admin.collapsed {
+    display: none; }
   .asrouter-admin .sidebar {
     inset-inline-start: 0;
     position: fixed;
     width: 240px;
     padding: 30px 20px; }
     .asrouter-admin .sidebar ul {
       margin: 0;
       padding: 0;
@@ -1725,19 +1749,18 @@ main {
     max-width: 750px;
     overflow: auto;
     font-family: "SF Mono", "Monaco", "Inconsolata", "Fira Mono", "Droid Sans Mono", "Source Code Pro", monospace; }
   .asrouter-admin .errorState {
     border: 1px solid #D70022; }
   .asrouter-admin .helpLink {
     padding: 10px;
     display: flex;
-    background: #FFE900;
-    border-radius: 3px;
-    color: #0C0C0D; }
+    background: rgba(0, 0, 0, 0.1);
+    border-radius: 3px; }
     .asrouter-admin .helpLink a {
       text-decoration: underline; }
   .asrouter-admin .dsEnabled {
     padding: 10px;
     font-size: 16px;
     margin-bottom: 20px;
     border: 1px solid var(--newtab-border-secondary-color); }
   .asrouter-admin .ds-component {
@@ -1884,17 +1907,17 @@ main {
       box-shadow: 0 1px 4px rgba(12, 12, 13, 0.1);
       background: #38383D; }
     .ds-card-grid.ds-card-grid-border .ds-card:not(.placeholder):hover {
       box-shadow: 0 0 0 5px #D7D7DB;
       transition: box-shadow 150ms;
       outline: none; }
       [lwt-newtab-brighttext] .ds-card-grid.ds-card-grid-border .ds-card:not(.placeholder):hover {
         box-shadow: 0 0 0 5px #4A4A4F; }
-    .ds-card-grid.ds-card-grid-border .ds-card:not(.placeholder) .img-wrapper .img {
+    .ds-card-grid.ds-card-grid-border .ds-card:not(.placeholder) .img-wrapper .img img {
       border-radius: 4px 4px 0 0; }
   .ds-card-grid.ds-card-grid-no-border .ds-card {
     background: none; }
     .ds-card-grid.ds-card-grid-no-border .ds-card .meta {
       padding: 16px 0; }
   .ds-column-5 .ds-card-grid,
   .ds-column-6 .ds-card-grid,
   .ds-column-7 .ds-card-grid,
--- a/browser/components/newtab/css/activity-stream-mac.css
+++ b/browser/components/newtab/css/activity-stream-mac.css
@@ -240,16 +240,19 @@ body,
   min-height: 100vh; }
 
 body {
   background-color: var(--newtab-background-color);
   font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Ubuntu', 'Helvetica Neue', sans-serif;
   font-size: 16px;
   overflow-y: scroll; }
 
+.no-scroll {
+  overflow: hidden; }
+
 h1,
 h2 {
   font-weight: normal; }
 
 a {
   text-decoration: none; }
 
 .sr-only {
@@ -1535,16 +1538,17 @@ main {
         justify-content: space-between; } }
   .manual-migration-container .icon {
     display: none; }
     @media (min-width: 610px) {
       .manual-migration-container .icon {
         align-self: center;
         display: block;
         fill: var(--newtab-icon-secondary-color);
+        flex-shrink: 0;
         margin-inline-end: 6px; } }
 
 .manual-migration-actions {
   border: 0;
   display: block;
   flex-wrap: nowrap; }
   @media (min-width: 610px) {
     .manual-migration-actions {
@@ -1642,22 +1646,42 @@ main {
     transition: max-height 0.5s cubic-bezier(0.07, 0.95, 0, 1); }
   .collapsible-section.collapsed .section-body {
     max-height: 0;
     overflow: hidden; }
   @media (min-width: 610px) and (max-width: 865px) {
     .collapsible-section[data-section-id='topstories'] .card-outer:first-child {
       display: none; } }
 
+.asrouter-toggle {
+  background: #FFE900;
+  color: #000;
+  position: fixed;
+  top: 0;
+  left: 43px;
+  padding: 5px 10px;
+  border-radius: 0 0 3px 3px;
+  border: 1px solid rgba(0, 0, 0, 0.1);
+  border-top: 0;
+  z-index: 3000; }
+
 .asrouter-admin {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  background: var(--newtab-background-color);
+  height: 100%;
+  overflow-y: scroll;
   margin: 0 auto;
   font-size: 14px;
   padding-left: 240px;
-  display: flex;
   color: var(--newtab-text-primary-color); }
+  .asrouter-admin.collapsed {
+    display: none; }
   .asrouter-admin .sidebar {
     inset-inline-start: 0;
     position: fixed;
     width: 240px;
     padding: 30px 20px; }
     .asrouter-admin .sidebar ul {
       margin: 0;
       padding: 0;
@@ -1728,19 +1752,18 @@ main {
     max-width: 750px;
     overflow: auto;
     font-family: "SF Mono", "Monaco", "Inconsolata", "Fira Mono", "Droid Sans Mono", "Source Code Pro", monospace; }
   .asrouter-admin .errorState {
     border: 1px solid #D70022; }
   .asrouter-admin .helpLink {
     padding: 10px;
     display: flex;
-    background: #FFE900;
-    border-radius: 3px;
-    color: #0C0C0D; }
+    background: rgba(0, 0, 0, 0.1);
+    border-radius: 3px; }
     .asrouter-admin .helpLink a {
       text-decoration: underline; }
   .asrouter-admin .dsEnabled {
     padding: 10px;
     font-size: 16px;
     margin-bottom: 20px;
     border: 1px solid var(--newtab-border-secondary-color); }
   .asrouter-admin .ds-component {
@@ -1887,17 +1910,17 @@ main {
       box-shadow: 0 1px 4px rgba(12, 12, 13, 0.1);
       background: #38383D; }
     .ds-card-grid.ds-card-grid-border .ds-card:not(.placeholder):hover {
       box-shadow: 0 0 0 5px #D7D7DB;
       transition: box-shadow 150ms;
       outline: none; }
       [lwt-newtab-brighttext] .ds-card-grid.ds-card-grid-border .ds-card:not(.placeholder):hover {
         box-shadow: 0 0 0 5px #4A4A4F; }
-    .ds-card-grid.ds-card-grid-border .ds-card:not(.placeholder) .img-wrapper .img {
+    .ds-card-grid.ds-card-grid-border .ds-card:not(.placeholder) .img-wrapper .img img {
       border-radius: 4px 4px 0 0; }
   .ds-card-grid.ds-card-grid-no-border .ds-card {
     background: none; }
     .ds-card-grid.ds-card-grid-no-border .ds-card .meta {
       padding: 16px 0; }
   .ds-column-5 .ds-card-grid,
   .ds-column-6 .ds-card-grid,
   .ds-column-7 .ds-card-grid,
--- a/browser/components/newtab/css/activity-stream-windows.css
+++ b/browser/components/newtab/css/activity-stream-windows.css
@@ -237,16 +237,19 @@ body,
   min-height: 100vh; }
 
 body {
   background-color: var(--newtab-background-color);
   font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Ubuntu', 'Helvetica Neue', sans-serif;
   font-size: 16px;
   overflow-y: scroll; }
 
+.no-scroll {
+  overflow: hidden; }
+
 h1,
 h2 {
   font-weight: normal; }
 
 a {
   text-decoration: none; }
 
 .sr-only {
@@ -1532,16 +1535,17 @@ main {
         justify-content: space-between; } }
   .manual-migration-container .icon {
     display: none; }
     @media (min-width: 610px) {
       .manual-migration-container .icon {
         align-self: center;
         display: block;
         fill: var(--newtab-icon-secondary-color);
+        flex-shrink: 0;
         margin-inline-end: 6px; } }
 
 .manual-migration-actions {
   border: 0;
   display: block;
   flex-wrap: nowrap; }
   @media (min-width: 610px) {
     .manual-migration-actions {
@@ -1639,22 +1643,42 @@ main {
     transition: max-height 0.5s cubic-bezier(0.07, 0.95, 0, 1); }
   .collapsible-section.collapsed .section-body {
     max-height: 0;
     overflow: hidden; }
   @media (min-width: 610px) and (max-width: 865px) {
     .collapsible-section[data-section-id='topstories'] .card-outer:first-child {
       display: none; } }
 
+.asrouter-toggle {
+  background: #FFE900;
+  color: #000;
+  position: fixed;
+  top: 0;
+  left: 43px;
+  padding: 5px 10px;
+  border-radius: 0 0 3px 3px;
+  border: 1px solid rgba(0, 0, 0, 0.1);
+  border-top: 0;
+  z-index: 3000; }
+
 .asrouter-admin {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  background: var(--newtab-background-color);
+  height: 100%;
+  overflow-y: scroll;
   margin: 0 auto;
   font-size: 14px;
   padding-left: 240px;
-  display: flex;
   color: var(--newtab-text-primary-color); }
+  .asrouter-admin.collapsed {
+    display: none; }
   .asrouter-admin .sidebar {
     inset-inline-start: 0;
     position: fixed;
     width: 240px;
     padding: 30px 20px; }
     .asrouter-admin .sidebar ul {
       margin: 0;
       padding: 0;
@@ -1725,19 +1749,18 @@ main {
     max-width: 750px;
     overflow: auto;
     font-family: "SF Mono", "Monaco", "Inconsolata", "Fira Mono", "Droid Sans Mono", "Source Code Pro", monospace; }
   .asrouter-admin .errorState {
     border: 1px solid #D70022; }
   .asrouter-admin .helpLink {
     padding: 10px;
     display: flex;
-    background: #FFE900;
-    border-radius: 3px;
-    color: #0C0C0D; }
+    background: rgba(0, 0, 0, 0.1);
+    border-radius: 3px; }
     .asrouter-admin .helpLink a {
       text-decoration: underline; }
   .asrouter-admin .dsEnabled {
     padding: 10px;
     font-size: 16px;
     margin-bottom: 20px;
     border: 1px solid var(--newtab-border-secondary-color); }
   .asrouter-admin .ds-component {
@@ -1884,17 +1907,17 @@ main {
       box-shadow: 0 1px 4px rgba(12, 12, 13, 0.1);
       background: #38383D; }
     .ds-card-grid.ds-card-grid-border .ds-card:not(.placeholder):hover {
       box-shadow: 0 0 0 5px #D7D7DB;
       transition: box-shadow 150ms;
       outline: none; }
       [lwt-newtab-brighttext] .ds-card-grid.ds-card-grid-border .ds-card:not(.placeholder):hover {
         box-shadow: 0 0 0 5px #4A4A4F; }
-    .ds-card-grid.ds-card-grid-border .ds-card:not(.placeholder) .img-wrapper .img {
+    .ds-card-grid.ds-card-grid-border .ds-card:not(.placeholder) .img-wrapper .img img {
       border-radius: 4px 4px 0 0; }
   .ds-card-grid.ds-card-grid-no-border .ds-card {
     background: none; }
     .ds-card-grid.ds-card-grid-no-border .ds-card .meta {
       padding: 16px 0; }
   .ds-column-5 .ds-card-grid,
   .ds-column-6 .ds-card-grid,
   .ds-column-7 .ds-card-grid,
--- a/browser/components/newtab/data/content/activity-stream.bundle.js
+++ b/browser/components/newtab/data/content/activity-stream.bundle.js
@@ -86,62 +86,53 @@
 /************************************************************************/
 /******/ ([
 /* 0 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* WEBPACK VAR INJECTION */(function(global) {/* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
-/* harmony import */ var content_src_lib_snippets__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);
-/* harmony import */ var content_src_asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(4);
-/* harmony import */ var content_src_components_Base_Base__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(26);
-/* harmony import */ var content_src_lib_detect_user_session_start__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(52);
-/* harmony import */ var content_src_lib_asroutercontent__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(53);
-/* harmony import */ var content_src_lib_init_store__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(6);
-/* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(25);
-/* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_7___default = /*#__PURE__*/__webpack_require__.n(react_redux__WEBPACK_IMPORTED_MODULE_7__);
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(10);
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_8___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_8__);
-/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(15);
-/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_9___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_9__);
-/* harmony import */ var common_Reducers_jsm__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(58);
-
-
-
-
-
-
-
-
-
-
-
-const store = Object(content_src_lib_init_store__WEBPACK_IMPORTED_MODULE_6__["initStore"])(common_Reducers_jsm__WEBPACK_IMPORTED_MODULE_10__["reducers"], global.gActivityStreamPrerenderedState);
-const asrouterContent = new content_src_asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_2__["ASRouterContent"]();
-new content_src_lib_detect_user_session_start__WEBPACK_IMPORTED_MODULE_4__["DetectUserSessionStart"](store).sendEventOrAddListener(); // If we are starting in a prerendered state, we must wait until the first render
+/* harmony import */ var content_src_components_Base_Base__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);
+/* harmony import */ var content_src_lib_detect_user_session_start__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(51);
+/* harmony import */ var content_src_lib_init_store__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(7);
+/* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(25);
+/* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(react_redux__WEBPACK_IMPORTED_MODULE_4__);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(11);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_5__);
+/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(28);
+/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_6__);
+/* harmony import */ var common_Reducers_jsm__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(56);
+
+
+
+
+
+
+
+
+const store = Object(content_src_lib_init_store__WEBPACK_IMPORTED_MODULE_3__["initStore"])(common_Reducers_jsm__WEBPACK_IMPORTED_MODULE_7__["reducers"], global.gActivityStreamPrerenderedState);
+new content_src_lib_detect_user_session_start__WEBPACK_IMPORTED_MODULE_2__["DetectUserSessionStart"](store).sendEventOrAddListener(); // If we are starting in a prerendered state, we must wait until the first render
 // to request state rehydration (see Base.jsx). If we are NOT in a prerendered state,
 // we can request it immedately.
 
 if (!global.gActivityStreamPrerenderedState) {
   store.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({
     type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].NEW_TAB_STATE_REQUEST
   }));
 }
 
-Object(content_src_lib_asroutercontent__WEBPACK_IMPORTED_MODULE_5__["enableASRouterContent"])(store, asrouterContent);
-react_dom__WEBPACK_IMPORTED_MODULE_9___default.a.hydrate(react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(react_redux__WEBPACK_IMPORTED_MODULE_7__["Provider"], {
+react_dom__WEBPACK_IMPORTED_MODULE_6___default.a.hydrate(react__WEBPACK_IMPORTED_MODULE_5___default.a.createElement(react_redux__WEBPACK_IMPORTED_MODULE_4__["Provider"], {
   store: store
-}, react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(content_src_components_Base_Base__WEBPACK_IMPORTED_MODULE_3__["Base"], {
+}, react__WEBPACK_IMPORTED_MODULE_5___default.a.createElement(content_src_components_Base_Base__WEBPACK_IMPORTED_MODULE_1__["Base"], {
   isFirstrun: global.document.location.href === "about:welcome",
   isPrerendered: !!global.gActivityStreamPrerenderedState,
   locale: global.document.documentElement.lang,
   strings: global.gActivityStreamStrings
 })), document.getElementById("root"));
-Object(content_src_lib_snippets__WEBPACK_IMPORTED_MODULE_1__["addSnippetsSubscriber"])(store);
 /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
 
 /***/ }),
 /* 1 */
 /***/ (function(module, exports) {
 
 var g;
 
@@ -546,1982 +537,53 @@ var actionUtils = {
 };
 
 /***/ }),
 /* 3 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
-/* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SNIPPETS_UPDATE_INTERVAL_MS", function() { return SNIPPETS_UPDATE_INTERVAL_MS; });
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SnippetsMap", function() { return SnippetsMap; });
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SnippetsProvider", function() { return SnippetsProvider; });
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "addSnippetsSubscriber", function() { return addSnippetsSubscriber; });
-/* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
-const DATABASE_NAME = "snippets_db";
-const DATABASE_VERSION = 1;
-const SNIPPETS_OBJECTSTORE_NAME = "snippets";
-const SNIPPETS_UPDATE_INTERVAL_MS = 14400000; // 4 hours.
-
-const SNIPPETS_ENABLED_EVENT = "Snippets:Enabled";
-const SNIPPETS_DISABLED_EVENT = "Snippets:Disabled";
-
-/**
- * SnippetsMap - A utility for cacheing values related to the snippet. It has
- *               the same interface as a Map, but is optionally backed by
- *               indexedDB for persistent storage.
- *               Call .connect() to open a database connection and restore any
- *               previously cached data, if necessary.
- *
- */
-
-class SnippetsMap extends Map {
-  constructor(dispatch) {
-    super();
-    this._db = null;
-    this._dispatch = dispatch;
-  }
-
-  set(key, value) {
-    super.set(key, value);
-    return this._dbTransaction(db => db.put(value, key));
-  }
-
-  delete(key) {
-    super.delete(key);
-    return this._dbTransaction(db => db.delete(key));
-  }
-
-  clear() {
-    super.clear();
-
-    this._dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
-      type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].SNIPPETS_BLOCKLIST_CLEARED
-    }));
-
-    return this._dbTransaction(db => db.clear());
-  }
-
-  get blockList() {
-    return this.get("blockList") || [];
-  }
-  /**
-   * blockSnippetById - Blocks a snippet given an id
-   *
-   * @param  {str|int} id   The id of the snippet
-   * @return {Promise}      Resolves when the id has been written to indexedDB,
-   *                        or immediately if the snippetMap is not connected
-   */
-
-
-  async blockSnippetById(id) {
-    if (!id) {
-      return;
-    }
-
-    const {
-      blockList
-    } = this;
-
-    if (!blockList.includes(id)) {
-      blockList.push(id);
-
-      this._dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({
-        type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].SNIPPETS_BLOCKLIST_UPDATED,
-        data: id
-      }));
-
-      await this.set("blockList", blockList);
-    }
-  }
-
-  disableOnboarding() {}
-
-  showFirefoxAccounts() {
-    this._dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({
-      type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].SHOW_FIREFOX_ACCOUNTS
-    }));
-  }
-
-  getTotalBookmarksCount() {
-    return new Promise(resolve => {
-      this._dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
-        type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].TOTAL_BOOKMARKS_REQUEST
-      }));
-
-      global.RPMAddMessageListener("ActivityStream:MainToContent", function onMessage({
-        data: action
-      }) {
-        if (action.type === common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].TOTAL_BOOKMARKS_RESPONSE) {
-          resolve(action.data);
-          global.RPMRemoveMessageListener("ActivityStream:MainToContent", onMessage);
-        }
-      });
-    });
-  }
-
-  getAddonsInfo() {
-    return new Promise(resolve => {
-      this._dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
-        type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].ADDONS_INFO_REQUEST
-      }));
-
-      global.RPMAddMessageListener("ActivityStream:MainToContent", function onMessage({
-        data: action
-      }) {
-        if (action.type === common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].ADDONS_INFO_RESPONSE) {
-          resolve(action.data);
-          global.RPMRemoveMessageListener("ActivityStream:MainToContent", onMessage);
-        }
-      });
-    });
-  }
-  /**
-   * connect - Attaches an indexedDB back-end to the Map so that any set values
-   *           are also cached in a store. It also restores any existing values
-   *           that are already stored in the indexedDB store.
-   *
-   * @return {type}  description
-   */
-
-
-  async connect() {
-    // Open the connection
-    const db = await this._openDB(); // Restore any existing values
-
-    await this._restoreFromDb(db); // Attach a reference to the db
-
-    this._db = db;
-  }
-  /**
-   * _dbTransaction - Returns a db transaction wrapped with the given modifier
-   *                  function as a Promise. If the db has not been connected,
-   *                  it resolves immediately.
-   *
-   * @param  {func} modifier A function to call with the transaction
-   * @return {obj}           A Promise that resolves when the transaction has
-   *                         completed or errored
-   */
-
-
-  _dbTransaction(modifier) {
-    if (!this._db) {
-      return Promise.resolve();
-    }
-
-    return new Promise((resolve, reject) => {
-      const transaction = modifier(this._db.transaction(SNIPPETS_OBJECTSTORE_NAME, "readwrite").objectStore(SNIPPETS_OBJECTSTORE_NAME));
-
-      transaction.onsuccess = event => resolve();
-      /* istanbul ignore next */
-
-
-      transaction.onerror = event => reject(transaction.error);
-    });
-  }
-
-  _openDB() {
-    return new Promise((resolve, reject) => {
-      const openRequest = indexedDB.open(DATABASE_NAME, DATABASE_VERSION);
-      /* istanbul ignore next */
-
-      openRequest.onerror = event => {
-        // Try to delete the old database so that we can start this process over
-        // next time.
-        indexedDB.deleteDatabase(DATABASE_NAME);
-        reject(event);
-      };
-
-      openRequest.onupgradeneeded = event => {
-        const db = event.target.result;
-
-        if (!db.objectStoreNames.contains(SNIPPETS_OBJECTSTORE_NAME)) {
-          db.createObjectStore(SNIPPETS_OBJECTSTORE_NAME);
-        }
-      };
-
-      openRequest.onsuccess = event => {
-        let db = event.target.result;
-        /* istanbul ignore next */
-
-        db.onerror = err => console.error(err); // eslint-disable-line no-console
-
-        /* istanbul ignore next */
-
-
-        db.onversionchange = versionChangeEvent => versionChangeEvent.target.close();
-
-        resolve(db);
-      };
-    });
-  }
-
-  _restoreFromDb(db) {
-    return new Promise((resolve, reject) => {
-      let cursorRequest;
-
-      try {
-        cursorRequest = db.transaction(SNIPPETS_OBJECTSTORE_NAME).objectStore(SNIPPETS_OBJECTSTORE_NAME).openCursor();
-      } catch (err) {
-        // istanbul ignore next
-        reject(err); // istanbul ignore next
-
-        return;
-      }
-      /* istanbul ignore next */
-
-
-      cursorRequest.onerror = event => reject(event);
-
-      cursorRequest.onsuccess = event => {
-        let cursor = event.target.result; // Populate the cache from the persistent storage.
-
-        if (cursor) {
-          if (cursor.value !== "blockList") {
-            this.set(cursor.key, cursor.value);
-          }
-
-          cursor.continue();
-        } else {
-          // We are done.
-          resolve();
-        }
-      };
-    });
-  }
-
-}
-/**
- * SnippetsProvider - Initializes a SnippetsMap and loads snippets from a
- *                    remote location, or else default snippets if the remote
- *                    snippets cannot be retrieved.
- */
-
-class SnippetsProvider {
-  constructor(dispatch) {
-    // Initialize the Snippets Map and attaches it to a global so that
-    // the snippet payload can interact with it.
-    global.gSnippetsMap = new SnippetsMap(dispatch);
-    this._onAction = this._onAction.bind(this);
-  }
-
-  get snippetsMap() {
-    return global.gSnippetsMap;
-  }
-
-  async _refreshSnippets() {
-    // Check if the cached version of of the snippets in snippetsMap. If it's too
-    // old, blow away the entire snippetsMap.
-    const cachedVersion = this.snippetsMap.get("snippets-cached-version");
-
-    if (cachedVersion !== this.appData.version) {
-      this.snippetsMap.clear();
-    } // Has enough time passed for us to require an update?
-
-
-    const lastUpdate = this.snippetsMap.get("snippets-last-update");
-    const needsUpdate = !(lastUpdate >= 0) || Date.now() - lastUpdate > SNIPPETS_UPDATE_INTERVAL_MS;
-
-    if (needsUpdate && this.appData.snippetsURL) {
-      this.snippetsMap.set("snippets-last-update", Date.now());
-
-      try {
-        const response = await fetch(this.appData.snippetsURL);
-
-        if (response.status === 200) {
-          const payload = await response.text();
-          this.snippetsMap.set("snippets", payload);
-          this.snippetsMap.set("snippets-cached-version", this.appData.version);
-        }
-      } catch (e) {
-        console.error(e); // eslint-disable-line no-console
-      }
-    }
-  }
-
-  _showRemoteSnippets() {
-    const snippetsEl = document.getElementById(this.elementId);
-    const payload = this.snippetsMap.get("snippets");
-
-    if (!snippetsEl) {
-      throw new Error(`No element was found with id '${this.elementId}'.`);
-    } // This could happen if fetching failed
-
-
-    if (!payload) {
-      throw new Error("No remote snippets were found in gSnippetsMap.");
-    }
-
-    if (typeof payload !== "string") {
-      throw new Error("Snippet payload was incorrectly formatted");
-    } // Note that injecting snippets can throw if they're invalid XML.
-    // eslint-disable-next-line no-unsanitized/property
-
-
-    snippetsEl.innerHTML = payload;
-
-    this._logIfDevtools("Successfully added snippets."); // Scripts injected by innerHTML are inactive, so we have to relocate them
-    // through DOM manipulation to activate their contents.
-
-
-    for (const scriptEl of snippetsEl.getElementsByTagName("script")) {
-      const relocatedScript = document.createElement("script");
-      relocatedScript.text = scriptEl.text;
-      scriptEl.parentNode.replaceChild(relocatedScript, scriptEl);
-    }
-  }
-
-  _onAction(msg) {
-    if (msg.data.type === common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].SNIPPET_BLOCKED) {
-      if (!this.snippetsMap.blockList.includes(msg.data.data)) {
-        this.snippetsMap.set("blockList", this.snippetsMap.blockList.concat(msg.data.data));
-        document.getElementById("snippets-container").style.display = "none";
-      }
-    }
-  } // istanbul ignore next
-
-
-  _logIfDevtools(text) {
-    if (this.devtoolsEnabled) {
-      console.log("Legacy snippets:", text); // eslint-disable-line no-console
-    }
-  }
-  /**
-   * init - Fetch the snippet payload and show snippets
-   *
-   * @param  {obj} options
-   * @param  {str} options.appData.snippetsURL  The URL from which we fetch snippets
-   * @param  {int} options.appData.version  The current snippets version
-   * @param  {str} options.elementId  The id of the element in which to inject snippets
-   * @param  {bool} options.connect  Should gSnippetsMap connect to indexedDB?
-   */
-
-
-  async init(options) {
-    Object.assign(this, {
-      appData: {},
-      elementId: "snippets",
-      connect: true,
-      devtoolsEnabled: false
-    }, options);
-
-    this._logIfDevtools("Initializing..."); // Add listener so we know when snippets are blocked on other pages
-
-
-    if (global.RPMAddMessageListener) {
-      global.RPMAddMessageListener("ActivityStream:MainToContent", this._onAction);
-    } // TODO: Requires enabling indexedDB on newtab
-    // Restore the snippets map from indexedDB
-
-
-    if (this.connect) {
-      try {
-        await this.snippetsMap.connect();
-      } catch (e) {
-        console.error(e); // eslint-disable-line no-console
-      }
-    } // Cache app data values so they can be accessible from gSnippetsMap
-
-
-    for (const key of Object.keys(this.appData)) {
-      if (key === "blockList") {
-        this.snippetsMap.set("blockList", this.appData[key]);
-      } else {
-        this.snippetsMap.set(`appData.${key}`, this.appData[key]);
-      }
-    } // Refresh snippets, if enough time has passed.
-
-
-    await this._refreshSnippets(); // Try showing remote snippets, falling back to defaults if necessary.
-
-    try {
-      this._showRemoteSnippets();
-    } catch (e) {
-      this._logIfDevtools("Problem inserting remote snippets!");
-
-      console.error(e); // eslint-disable-line no-console
-    }
-
-    window.dispatchEvent(new Event(SNIPPETS_ENABLED_EVENT));
-    this.initialized = true;
-
-    this._logIfDevtools("Finished initializing.");
-  }
-
-  uninit() {
-    window.dispatchEvent(new Event(SNIPPETS_DISABLED_EVENT));
-
-    if (global.RPMRemoveMessageListener) {
-      global.RPMRemoveMessageListener("ActivityStream:MainToContent", this._onAction);
-    }
-
-    this.initialized = false;
-  }
-
-}
-/**
- * addSnippetsSubscriber - Creates a SnippetsProvider that Initializes
- *                         when the store has received the appropriate
- *                         Snippet data.
- *
- * @param  {obj} store   The redux store
- * @return {obj}         Returns the snippets instance, asrouterContent instance and unsubscribe function
- */
-
-function addSnippetsSubscriber(store) {
-  const snippets = new SnippetsProvider(store.dispatch);
-  let initializing = false;
-  store.subscribe(async () => {
-    const state = store.getState();
-    /**
-     * Sorry this code is so complicated. It will be removed soon.
-     * This is what the different values actually mean:
-     *
-     * ASRouter.initialized                   Is ASRouter.jsm initialised?
-     * ASRouter.allowLegacySnippets           Are ASRouter snippets turned OFF (i.e. legacy snippets are allowed)
-     * state.Prefs.values["feeds.snippets"]   User preference for snippets
-     * state.Snippets.initialized             Is SnippetsFeed.jsm initialised?
-     * snippets.initialized                   Is in-content snippets currently initialised?
-     * state.Prefs.values.disableSnippets     This pref is used to disable legacy snippets in an emergency
-     *                                        in a way that is not user-editable (true = disabled)
-     */
-
-    /** If we should initialize snippets... */
-
-    if (state.Prefs.values["feeds.snippets"] && state.ASRouter.initialized && state.ASRouter.allowLegacySnippets && !state.Prefs.values.disableSnippets && state.Snippets.initialized && !snippets.initialized && // Don't call init multiple times
-    !initializing && location.href !== "about:welcome" && location.hash !== "#asrouter") {
-      initializing = true;
-      await snippets.init({
-        appData: state.Snippets,
-        devtoolsEnabled: state.Prefs.values["asrouter.devtoolsEnabled"]
-      });
-      initializing = false;
-      /** If we should remove snippets... */
-    } else if ((state.Prefs.values["feeds.snippets"] === false || state.Prefs.values.disableSnippets === true || state.ASRouter.initialized && !state.ASRouter.allowLegacySnippets) && snippets.initialized) {
-      // Remove snippets
-      snippets.uninit(); // istanbul ignore if
-
-      if (state.Prefs.values["asrouter.devtoolsEnabled"]) {
-        console.log("Legacy snippets removed"); // eslint-disable-line no-console
-      }
-    }
-  }); // Returned for testing purposes
-
-  return {
-    snippets
-  };
-}
-/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
-
-/***/ }),
-/* 4 */
-/***/ (function(module, __webpack_exports__, __webpack_require__) {
-
-"use strict";
-__webpack_require__.r(__webpack_exports__);
-/* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ASRouterUtils", function() { return ASRouterUtils; });
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ASRouterUISurface", function() { return ASRouterUISurface; });
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ASRouterContent", function() { return ASRouterContent; });
-/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5);
-/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_0__);
-/* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
-/* harmony import */ var content_src_lib_init_store__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6);
-/* harmony import */ var _rich_text_strings__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(8);
-/* harmony import */ var _components_ImpressionsWrapper_ImpressionsWrapper__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(9);
-/* harmony import */ var fluent_react__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(57);
-/* harmony import */ var content_src_lib_constants__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(12);
-/* harmony import */ var _templates_OnboardingMessage_OnboardingMessage__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(13);
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(10);
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_8___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_8__);
-/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(15);
-/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_9___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_9__);
-/* harmony import */ var _templates_ReturnToAMO_ReturnToAMO__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(16);
-/* harmony import */ var _templates_template_manifest__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(55);
-/* harmony import */ var _templates_StartupOverlay_StartupOverlay__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(24);
-function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-const INCOMING_MESSAGE_NAME = "ASRouter:parent-to-child";
-const OUTGOING_MESSAGE_NAME = "ASRouter:child-to-parent";
-const ASR_CONTAINER_ID = "asr-newtab-container";
-const ASRouterUtils = {
-  addListener(listener) {
-    global.RPMAddMessageListener(INCOMING_MESSAGE_NAME, listener);
-  },
-
-  removeListener(listener) {
-    global.RPMRemoveMessageListener(INCOMING_MESSAGE_NAME, listener);
-  },
-
-  sendMessage(action) {
-    global.RPMSendAsyncMessage(OUTGOING_MESSAGE_NAME, action);
-  },
-
-  blockById(id, options) {
-    ASRouterUtils.sendMessage({
-      type: "BLOCK_MESSAGE_BY_ID",
-      data: {
-        id,
-        ...options
-      }
-    });
-  },
-
-  dismissById(id) {
-    ASRouterUtils.sendMessage({
-      type: "DISMISS_MESSAGE_BY_ID",
-      data: {
-        id
-      }
-    });
-  },
-
-  dismissBundle(bundle) {
-    ASRouterUtils.sendMessage({
-      type: "DISMISS_BUNDLE",
-      data: {
-        bundle
-      }
-    });
-  },
-
-  executeAction(button_action) {
-    ASRouterUtils.sendMessage({
-      type: "USER_ACTION",
-      data: button_action
-    });
-  },
-
-  unblockById(id) {
-    ASRouterUtils.sendMessage({
-      type: "UNBLOCK_MESSAGE_BY_ID",
-      data: {
-        id
-      }
-    });
-  },
-
-  unblockBundle(bundle) {
-    ASRouterUtils.sendMessage({
-      type: "UNBLOCK_BUNDLE",
-      data: {
-        bundle
-      }
-    });
-  },
-
-  overrideMessage(id) {
-    ASRouterUtils.sendMessage({
-      type: "OVERRIDE_MESSAGE",
-      data: {
-        id
-      }
-    });
-  },
-
-  sendTelemetry(ping) {
-    const payload = common_Actions_jsm__WEBPACK_IMPORTED_MODULE_1__["actionCreators"].ASRouterUserEvent(ping);
-    global.RPMSendAsyncMessage(content_src_lib_init_store__WEBPACK_IMPORTED_MODULE_2__["OUTGOING_MESSAGE_NAME"], payload);
-  },
-
-  getPreviewEndpoint() {
-    if (window.location.href.includes("endpoint")) {
-      const params = new URLSearchParams(window.location.href.slice(window.location.href.indexOf("endpoint")));
-
-      try {
-        const endpoint = new URL(params.get("endpoint"));
-        return {
-          url: endpoint.href,
-          snippetId: params.get("snippetId"),
-          theme: this.getPreviewTheme()
-        };
-      } catch (e) {}
-    }
-
-    return null;
-  },
-
-  getPreviewTheme() {
-    return new URLSearchParams(window.location.href.slice(window.location.href.indexOf("theme"))).get("theme");
-  }
-
-}; // Note: nextProps/prevProps refer to props passed to <ImpressionsWrapper />, not <ASRouterUISurface />
-
-function shouldSendImpressionOnUpdate(nextProps, prevProps) {
-  return nextProps.message.id && (!prevProps.message || prevProps.message.id !== nextProps.message.id);
-}
-
-class ASRouterUISurface extends react__WEBPACK_IMPORTED_MODULE_8___default.a.PureComponent {
-  constructor(props) {
-    super(props);
-    this.onMessageFromParent = this.onMessageFromParent.bind(this);
-    this.sendClick = this.sendClick.bind(this);
-    this.sendImpression = this.sendImpression.bind(this);
-    this.sendUserActionTelemetry = this.sendUserActionTelemetry.bind(this);
-    this.state = {
-      message: {},
-      bundle: {}
-    };
-  }
-
-  sendUserActionTelemetry(extraProps = {}) {
-    const {
-      message,
-      bundle
-    } = this.state;
-
-    if (!message && !extraProps.message_id) {
-      throw new Error(`You must provide a message_id for bundled messages`);
-    }
-
-    const eventType = `${message.provider || bundle.provider}_user_event`;
-    ASRouterUtils.sendTelemetry({
-      message_id: message.id || extraProps.message_id,
-      source: extraProps.id,
-      action: eventType,
-      ...extraProps
-    });
-  }
-
-  sendImpression(extraProps) {
-    if (this.state.message.provider === "preview") {
-      return;
-    }
-
-    ASRouterUtils.sendMessage({
-      type: "IMPRESSION",
-      data: this.state.message
-    });
-    this.sendUserActionTelemetry({
-      event: "IMPRESSION",
-      ...extraProps
-    });
-  } // If link has a `metric` data attribute send it as part of the `value`
-  // telemetry field which can have arbitrary values.
-  // Used for router messages with links as part of the content.
-
-
-  sendClick(event) {
-    const metric = {
-      value: event.target.dataset.metric,
-      // Used for the `source` of the event. Needed to differentiate
-      // from other snippet or onboarding events that may occur.
-      id: "NEWTAB_FOOTER_BAR_CONTENT"
-    };
-    const action = {
-      type: event.target.dataset.action,
-      data: {
-        args: event.target.dataset.args
-      }
-    };
-
-    if (action.type) {
-      ASRouterUtils.executeAction(action);
-    }
-
-    if (!this.state.message.content.do_not_autoblock && !event.target.dataset.do_not_autoblock) {
-      ASRouterUtils.blockById(this.state.message.id);
-    }
-
-    if (this.state.message.provider !== "preview") {
-      this.sendUserActionTelemetry({
-        event: "CLICK_BUTTON",
-        ...metric
-      });
-    }
-  }
-
-  onBlockById(id) {
-    return options => ASRouterUtils.blockById(id, options);
-  }
-
-  onDismissById(id) {
-    return () => ASRouterUtils.dismissById(id);
-  }
-
-  dismissBundle(bundle) {
-    return () => ASRouterUtils.dismissBundle(bundle);
-  }
-
-  triggerOnboarding() {
-    ASRouterUtils.sendMessage({
-      type: "TRIGGER",
-      data: {
-        trigger: {
-          id: "showOnboarding"
-        }
-      }
-    });
-  }
-
-  onMessageFromParent({
-    data: action
-  }) {
-    switch (action.type) {
-      case "SET_MESSAGE":
-        this.setState({
-          message: action.data
-        });
-        break;
-
-      case "SET_BUNDLED_MESSAGES":
-        this.setState({
-          bundle: action.data
-        });
-        break;
-
-      case "CLEAR_MESSAGE":
-        if (action.data.id === this.state.message.id) {
-          this.setState({
-            message: {}
-          }); // Remove any styles related to the RTAMO message
-
-          document.body.classList.remove("welcome", "hide-main", "amo");
-        }
-
-        break;
-
-      case "CLEAR_PROVIDER":
-        if (action.data.id === this.state.message.provider) {
-          this.setState({
-            message: {}
-          });
-        }
-
-        break;
-
-      case "CLEAR_BUNDLE":
-        if (this.state.bundle.bundle) {
-          this.setState({
-            bundle: {}
-          });
-        }
-
-        break;
-
-      case "CLEAR_ALL":
-        this.setState({
-          message: {},
-          bundle: {}
-        });
-    }
-  }
-
-  componentWillMount() {
-    // Add locale data for StartupOverlay because it uses react-intl
-    Object(react_intl__WEBPACK_IMPORTED_MODULE_0__["addLocaleData"])(global.document.documentElement.lang);
-    const endpoint = ASRouterUtils.getPreviewEndpoint();
-
-    if (endpoint && endpoint.theme === "dark") {
-      global.window.dispatchEvent(new CustomEvent("LightweightTheme:Set", {
-        detail: {
-          data: content_src_lib_constants__WEBPACK_IMPORTED_MODULE_6__["NEWTAB_DARK_THEME"]
-        }
-      }));
-    }
-
-    ASRouterUtils.addListener(this.onMessageFromParent); // If we are loading about:welcome we want to trigger the onboarding messages
-
-    if (this.props.document.location.href === "about:welcome") {
-      ASRouterUtils.sendMessage({
-        type: "TRIGGER",
-        data: {
-          trigger: {
-            id: "firstRun"
-          }
-        }
-      });
-    } else {
-      ASRouterUtils.sendMessage({
-        type: "SNIPPETS_REQUEST",
-        data: {
-          endpoint
-        }
-      });
-    }
-  }
-
-  componentWillUnmount() {
-    ASRouterUtils.removeListener(this.onMessageFromParent);
-  }
-
-  renderSnippets() {
-    if (this.state.bundle.template === "onboarding" || this.state.message.template === "fxa_overlay" || this.state.message.template === "return_to_amo_overlay") {
-      return null;
-    }
-
-    const SnippetComponent = _templates_template_manifest__WEBPACK_IMPORTED_MODULE_11__["SnippetsTemplates"][this.state.message.template];
-    const {
-      content
-    } = this.state.message;
-    return react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(_components_ImpressionsWrapper_ImpressionsWrapper__WEBPACK_IMPORTED_MODULE_4__["ImpressionsWrapper"], {
-      id: "NEWTAB_FOOTER_BAR",
-      message: this.state.message,
-      sendImpression: this.sendImpression,
-      shouldSendImpressionOnUpdate: shouldSendImpressionOnUpdate // This helps with testing
-      ,
-      document: this.props.document
-    }, react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(fluent_react__WEBPACK_IMPORTED_MODULE_5__["LocalizationProvider"], {
-      messages: Object(_rich_text_strings__WEBPACK_IMPORTED_MODULE_3__["generateMessages"])(content)
-    }, react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(SnippetComponent, _extends({}, this.state.message, {
-      UISurface: "NEWTAB_FOOTER_BAR",
-      onBlock: this.onBlockById(this.state.message.id),
-      onDismiss: this.onDismissById(this.state.message.id),
-      onAction: ASRouterUtils.executeAction,
-      sendClick: this.sendClick,
-      sendUserActionTelemetry: this.sendUserActionTelemetry
-    }))));
-  }
-
-  renderOnboarding() {
-    if (this.state.bundle.template === "onboarding") {
-      return react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(_templates_OnboardingMessage_OnboardingMessage__WEBPACK_IMPORTED_MODULE_7__["OnboardingMessage"], _extends({}, this.state.bundle, {
-        UISurface: "NEWTAB_OVERLAY",
-        onAction: ASRouterUtils.executeAction,
-        onDoneButton: this.dismissBundle(this.state.bundle.bundle),
-        sendUserActionTelemetry: this.sendUserActionTelemetry
-      }));
-    }
-
-    return null;
-  }
-
-  renderFirstRunOverlay() {
-    const {
-      message
-    } = this.state;
-
-    if (message.template === "fxa_overlay") {
-      global.document.body.classList.add("fxa");
-      return react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_0__["IntlProvider"], {
-        locale: global.document.documentElement.lang,
-        messages: global.gActivityStreamStrings
-      }, react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(_templates_StartupOverlay_StartupOverlay__WEBPACK_IMPORTED_MODULE_12__["StartupOverlay"], {
-        onReady: this.triggerOnboarding,
-        onBlock: this.onDismissById(message.id),
-        dispatch: this.props.activityStreamStore.dispatch,
-        store: this.props.activityStreamStore
-      }));
-    } else if (message.template === "return_to_amo_overlay") {
-      global.document.body.classList.add("amo");
-      return react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(fluent_react__WEBPACK_IMPORTED_MODULE_5__["LocalizationProvider"], {
-        messages: Object(_rich_text_strings__WEBPACK_IMPORTED_MODULE_3__["generateMessages"])({
-          "amo_html": message.content.text
-        })
-      }, react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(_templates_ReturnToAMO_ReturnToAMO__WEBPACK_IMPORTED_MODULE_10__["ReturnToAMO"], _extends({}, message, {
-        onReady: this.triggerOnboarding,
-        onBlock: this.onDismissById(message.id),
-        onAction: ASRouterUtils.executeAction
-      })));
-    }
-
-    return null;
-  }
-
-  renderPreviewBanner() {
-    if (this.state.message.provider !== "preview") {
-      return null;
-    }
-
-    return react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement("div", {
-      className: "snippets-preview-banner"
-    }, react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement("span", {
-      className: "icon icon-small-spacer icon-info"
-    }), react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement("span", null, "Preview Purposes Only"));
-  }
-
-  render() {
-    const {
-      message,
-      bundle
-    } = this.state;
-
-    if (!message.id && !bundle.template) {
-      return null;
-    }
-
-    return react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(react__WEBPACK_IMPORTED_MODULE_8___default.a.Fragment, null, this.renderPreviewBanner(), this.renderFirstRunOverlay(), this.renderOnboarding(), this.renderSnippets());
-  }
-
-}
-ASRouterUISurface.defaultProps = {
-  document: global.document
-};
-class ASRouterContent {
-  constructor() {
-    this.initialized = false;
-    this.containerElement = null;
-  }
-
-  _mount() {
-    this.containerElement = global.document.getElementById(ASR_CONTAINER_ID);
-
-    if (!this.containerElement) {
-      this.containerElement = global.document.createElement("div");
-      this.containerElement.id = ASR_CONTAINER_ID;
-      this.containerElement.style.zIndex = 1;
-      global.document.body.appendChild(this.containerElement);
-    }
-
-    react_dom__WEBPACK_IMPORTED_MODULE_9___default.a.render(react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(ASRouterUISurface, {
-      activityStreamStore: this._activityStreamStore
-    }), this.containerElement);
-  }
-
-  _unmount() {
-    react_dom__WEBPACK_IMPORTED_MODULE_9___default.a.unmountComponentAtNode(this.containerElement);
-  }
-
-  init(store) {
-    this._activityStreamStore = store;
-
-    this._mount();
-
-    this.initialized = true;
-  }
-
-  uninit() {
-    if (this.initialized) {
-      this._unmount();
-
-      this.initialized = false;
-    }
-  }
-
-}
-/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
-
-/***/ }),
-/* 5 */
-/***/ (function(module, exports) {
-
-module.exports = ReactIntl;
-
-/***/ }),
-/* 6 */
-/***/ (function(module, __webpack_exports__, __webpack_require__) {
-
-"use strict";
-__webpack_require__.r(__webpack_exports__);
-/* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MERGE_STORE_ACTION", function() { return MERGE_STORE_ACTION; });
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OUTGOING_MESSAGE_NAME", function() { return OUTGOING_MESSAGE_NAME; });
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "INCOMING_MESSAGE_NAME", function() { return INCOMING_MESSAGE_NAME; });
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EARLY_QUEUED_ACTIONS", function() { return EARLY_QUEUED_ACTIONS; });
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "rehydrationMiddleware", function() { return rehydrationMiddleware; });
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "queueEarlyMessageMiddleware", function() { return queueEarlyMessageMiddleware; });
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "initStore", function() { return initStore; });
-/* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
-/* harmony import */ var redux__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7);
-/* harmony import */ var redux__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(redux__WEBPACK_IMPORTED_MODULE_1__);
-/* eslint-env mozilla/frame-script */
-
-
-const MERGE_STORE_ACTION = "NEW_TAB_INITIAL_STATE";
-const OUTGOING_MESSAGE_NAME = "ActivityStream:ContentToMain";
-const INCOMING_MESSAGE_NAME = "ActivityStream:MainToContent";
-const EARLY_QUEUED_ACTIONS = [common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].SAVE_SESSION_PERF_DATA, common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].PAGE_PRERENDERED];
-/**
- * A higher-order function which returns a reducer that, on MERGE_STORE action,
- * will return the action.data object merged into the previous state.
- *
- * For all other actions, it merely calls mainReducer.
- *
- * Because we want this to merge the entire state object, it's written as a
- * higher order function which takes the main reducer (itself often a call to
- * combineReducers) as a parameter.
- *
- * @param  {function} mainReducer reducer to call if action != MERGE_STORE_ACTION
- * @return {function}             a reducer that, on MERGE_STORE_ACTION action,
- *                                will return the action.data object merged
- *                                into the previous state, and the result
- *                                of calling mainReducer otherwise.
- */
-
-function mergeStateReducer(mainReducer) {
-  return (prevState, action) => {
-    if (action.type === MERGE_STORE_ACTION) {
-      return { ...prevState,
-        ...action.data
-      };
-    }
-
-    return mainReducer(prevState, action);
-  };
-}
-/**
- * messageMiddleware - Middleware that looks for SentToMain type actions, and sends them if necessary
- */
-
-
-const messageMiddleware = store => next => action => {
-  const skipLocal = action.meta && action.meta.skipLocal;
-
-  if (common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionUtils"].isSendToMain(action)) {
-    RPMSendAsyncMessage(OUTGOING_MESSAGE_NAME, action);
-  }
-
-  if (!skipLocal) {
-    next(action);
-  }
-};
-
-const rehydrationMiddleware = store => next => action => {
-  if (store._didRehydrate) {
-    return next(action);
-  }
-
-  const isMergeStoreAction = action.type === MERGE_STORE_ACTION;
-  const isRehydrationRequest = action.type === common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].NEW_TAB_STATE_REQUEST;
-
-  if (isRehydrationRequest) {
-    store._didRequestInitialState = true;
-    return next(action);
-  }
-
-  if (isMergeStoreAction) {
-    store._didRehydrate = true;
-    return next(action);
-  } // If init happened after our request was made, we need to re-request
-
-
-  if (store._didRequestInitialState && action.type === common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].INIT) {
-    return next(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({
-      type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].NEW_TAB_STATE_REQUEST
-    }));
-  }
-
-  if (common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionUtils"].isBroadcastToContent(action) || common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionUtils"].isSendToOneContent(action) || common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionUtils"].isSendToPreloaded(action)) {
-    // Note that actions received before didRehydrate will not be dispatched
-    // because this could negatively affect preloading and the the state
-    // will be replaced by rehydration anyway.
-    return null;
-  }
-
-  return next(action);
-};
-/**
- * This middleware queues up all the EARLY_QUEUED_ACTIONS until it receives
- * the first action from main. This is useful for those actions for main which
- * require higher reliability, i.e. the action will not be lost in the case
- * that it gets sent before the main is ready to receive it. Conversely, any
- * actions allowed early are accepted to be ignorable or re-sendable.
- */
-
-const queueEarlyMessageMiddleware = store => next => action => {
-  if (store._receivedFromMain) {
-    next(action);
-  } else if (common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionUtils"].isFromMain(action)) {
-    next(action);
-    store._receivedFromMain = true; // Sending out all the early actions as main is ready now
-
-    if (store._earlyActionQueue) {
-      store._earlyActionQueue.forEach(next);
-
-      store._earlyActionQueue = [];
-    }
-  } else if (EARLY_QUEUED_ACTIONS.includes(action.type)) {
-    store._earlyActionQueue = store._earlyActionQueue || [];
-
-    store._earlyActionQueue.push(action);
-  } else {
-    // Let any other type of action go through
-    next(action);
-  }
-};
-/**
- * initStore - Create a store and listen for incoming actions
- *
- * @param  {object} reducers An object containing Redux reducers
- * @param  {object} intialState (optional) The initial state of the store, if desired
- * @return {object}          A redux store
- */
-
-function initStore(reducers, initialState) {
-  const store = Object(redux__WEBPACK_IMPORTED_MODULE_1__["createStore"])(mergeStateReducer(Object(redux__WEBPACK_IMPORTED_MODULE_1__["combineReducers"])(reducers)), initialState, global.RPMAddMessageListener && Object(redux__WEBPACK_IMPORTED_MODULE_1__["applyMiddleware"])(rehydrationMiddleware, queueEarlyMessageMiddleware, messageMiddleware));
-  store._didRehydrate = false;
-  store._didRequestInitialState = false;
-
-  if (global.RPMAddMessageListener) {
-    global.RPMAddMessageListener(INCOMING_MESSAGE_NAME, msg => {
-      try {
-        store.dispatch(msg.data);
-      } catch (ex) {
-        console.error("Content msg:", msg, "Dispatch error: ", ex); // eslint-disable-line no-console
-
-        dump(`Content msg: ${JSON.stringify(msg)}\nDispatch error: ${ex}\n${ex.stack}`);
-      }
-    });
-  }
-
-  return store;
-}
-/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
-
-/***/ }),
-/* 7 */
-/***/ (function(module, exports) {
-
-module.exports = Redux;
-
-/***/ }),
-/* 8 */
-/***/ (function(module, __webpack_exports__, __webpack_require__) {
-
-"use strict";
-__webpack_require__.r(__webpack_exports__);
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RICH_TEXT_KEYS", function() { return RICH_TEXT_KEYS; });
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "generateMessages", function() { return generateMessages; });
-/* harmony import */ var fluent__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(56);
-
-/**
- * Properties that allow rich text MUST be added to this list.
- *   key: the localization_id that should be used
- *   value: a property or array of properties on the message.content object
- */
-
-const RICH_TEXT_CONFIG = {
-  "text": ["text", "scene1_text"],
-  "success_text": "success_text",
-  "error_text": "error_text",
-  "scene2_text": "scene2_text",
-  "amo_html": "amo_html",
-  "privacy_html": "scene2_privacy_html",
-  "disclaimer_html": "scene2_disclaimer_html"
-};
-const RICH_TEXT_KEYS = Object.keys(RICH_TEXT_CONFIG);
-/**
- * Generates an array of messages suitable for fluent's localization provider
- * including all needed strings for rich text.
- * @param {object} content A .content object from an ASR message (i.e. message.content)
- * @returns {MessageContext[]} A array containing the fluent message context
- */
-
-function generateMessages(content) {
-  const cx = new fluent__WEBPACK_IMPORTED_MODULE_0__["MessageContext"]("en-US");
-  RICH_TEXT_KEYS.forEach(key => {
-    const attrs = RICH_TEXT_CONFIG[key];
-    const attrsToTry = Array.isArray(attrs) ? [...attrs] : [attrs];
-    let string = "";
-
-    while (!string && attrsToTry.length) {
-      const attr = attrsToTry.pop();
-      string = content[attr];
-    }
-
-    cx.addMessages(`${key} = ${string}`);
-  });
-  return [cx];
-}
-
-/***/ }),
-/* 9 */
-/***/ (function(module, __webpack_exports__, __webpack_require__) {
-
-"use strict";
-__webpack_require__.r(__webpack_exports__);
-/* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VISIBLE", function() { return VISIBLE; });
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VISIBILITY_CHANGE_EVENT", function() { return VISIBILITY_CHANGE_EVENT; });
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ImpressionsWrapper", function() { return ImpressionsWrapper; });
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(10);
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
-
-const VISIBLE = "visible";
-const VISIBILITY_CHANGE_EVENT = "visibilitychange";
-/**
- * Component wrapper used to send telemetry pings on every impression.
- */
-
-class ImpressionsWrapper extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComponent {
-  // This sends an event when a user sees a set of new content. If content
-  // changes while the page is hidden (i.e. preloaded or on a hidden tab),
-  // only send the event if the page becomes visible again.
-  sendImpressionOrAddListener() {
-    if (this.props.document.visibilityState === VISIBLE) {
-      this.props.sendImpression({
-        id: this.props.id
-      });
-    } else {
-      // We should only ever send the latest impression stats ping, so remove any
-      // older listeners.
-      if (this._onVisibilityChange) {
-        this.props.document.removeEventListener(VISIBILITY_CHANGE_EVENT, this._onVisibilityChange);
-      } // When the page becomes visible, send the impression stats ping if the section isn't collapsed.
-
-
-      this._onVisibilityChange = () => {
-        if (this.props.document.visibilityState === VISIBLE) {
-          this.props.sendImpression({
-            id: this.props.id
-          });
-          this.props.document.removeEventListener(VISIBILITY_CHANGE_EVENT, this._onVisibilityChange);
-        }
-      };
-
-      this.props.document.addEventListener(VISIBILITY_CHANGE_EVENT, this._onVisibilityChange);
-    }
-  }
-
-  componentWillUnmount() {
-    if (this._onVisibilityChange) {
-      this.props.document.removeEventListener(VISIBILITY_CHANGE_EVENT, this._onVisibilityChange);
-    }
-  }
-
-  componentDidMount() {
-    if (this.props.sendOnMount) {
-      this.sendImpressionOrAddListener();
-    }
-  }
-
-  componentDidUpdate(prevProps) {
-    if (this.props.shouldSendImpressionOnUpdate(this.props, prevProps)) {
-      this.sendImpressionOrAddListener();
-    }
-  }
-
-  render() {
-    return this.props.children;
-  }
-
-}
-ImpressionsWrapper.defaultProps = {
-  document: global.document,
-  sendOnMount: true
-};
-/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
-
-/***/ }),
-/* 10 */
-/***/ (function(module, exports) {
-
-module.exports = React;
-
-/***/ }),
-/* 11 */
-/***/ (function(module, exports) {
-
-module.exports = PropTypes;
-
-/***/ }),
-/* 12 */
-/***/ (function(module, __webpack_exports__, __webpack_require__) {
-
-"use strict";
-__webpack_require__.r(__webpack_exports__);
-/* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "IS_NEWTAB", function() { return IS_NEWTAB; });
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NEWTAB_DARK_THEME", function() { return NEWTAB_DARK_THEME; });
-const IS_NEWTAB = global.document && global.document.documentURI === "about:newtab";
-const NEWTAB_DARK_THEME = {
-  "ntp_background": {
-    "r": 42,
-    "g": 42,
-    "b": 46,
-    "a": 1
-  },
-  "ntp_text": {
-    "r": 249,
-    "g": 249,
-    "b": 250,
-    "a": 1
-  },
-  "sidebar": {
-    "r": 56,
-    "g": 56,
-    "b": 61,
-    "a": 1
-  },
-  "sidebar_text": {
-    "r": 249,
-    "g": 249,
-    "b": 250,
-    "a": 1
-  }
-};
-/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
-
-/***/ }),
-/* 13 */
-/***/ (function(module, __webpack_exports__, __webpack_require__) {
-
-"use strict";
-__webpack_require__.r(__webpack_exports__);
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OnboardingMessage", function() { return OnboardingMessage; });
-/* harmony import */ var _components_ModalOverlay_ModalOverlay__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(14);
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(10);
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
-function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
-
-
-
-
-class OnboardingCard extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureComponent {
-  constructor(props) {
-    super(props);
-    this.onClick = this.onClick.bind(this);
-  }
-
-  onClick() {
-    const {
-      props
-    } = this;
-    const ping = {
-      event: "CLICK_BUTTON",
-      message_id: props.id,
-      id: props.UISurface
-    };
-    props.sendUserActionTelemetry(ping);
-    props.onAction(props.content.primary_button.action);
-  }
-
-  render() {
-    const {
-      content
-    } = this.props;
-    return react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("div", {
-      className: "onboardingMessage"
-    }, react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("div", {
-      className: `onboardingMessageImage ${content.icon}`
-    }), react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("div", {
-      className: "onboardingContent"
-    }, react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("span", null, react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("h3", null, " ", content.title, " "), react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("p", null, " ", content.text, " ")), react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("span", null, react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("button", {
-      tabIndex: "1",
-      className: "button onboardingButton",
-      onClick: this.onClick
-    }, " ", content.primary_button.label, " "))));
-  }
-
-}
-
-class OnboardingMessage extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureComponent {
-  render() {
-    const {
-      props
-    } = this;
-    const {
-      button_label,
-      header
-    } = props.extraTemplateStrings;
-    return react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(_components_ModalOverlay_ModalOverlay__WEBPACK_IMPORTED_MODULE_0__["ModalOverlay"], _extends({}, props, {
-      button_label: button_label,
-      title: header
-    }), react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("div", {
-      className: "onboardingMessageContainer"
-    }, props.bundle.map(message => react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(OnboardingCard, _extends({
-      key: message.id,
-      sendUserActionTelemetry: props.sendUserActionTelemetry,
-      onAction: props.onAction,
-      UISurface: props.UISurface
-    }, message)))));
-  }
-
-}
-
-/***/ }),
-/* 14 */
-/***/ (function(module, __webpack_exports__, __webpack_require__) {
-
-"use strict";
-__webpack_require__.r(__webpack_exports__);
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ModalOverlay", function() { return ModalOverlay; });
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(10);
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
-
-class ModalOverlay extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComponent {
-  componentWillMount() {
-    this.setState({
-      active: true
-    });
-    document.body.classList.add("modal-open");
-  }
-
-  componentWillUnmount() {
-    document.body.classList.remove("modal-open");
-    this.setState({
-      active: false
-    });
-  }
-
-  render() {
-    const {
-      active
-    } = this.state;
-    const {
-      title,
-      button_label
-    } = this.props;
-    return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
-      className: `modalOverlayOuter ${active ? "active" : ""}`
-    }), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
-      className: `modalOverlayInner ${active ? "active" : ""}`
-    }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("h2", null, " ", title, " "), this.props.children, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
-      className: "footer"
-    }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("button", {
-      tabIndex: "2",
-      onClick: this.props.onDoneButton,
-      className: "button primary modalButton"
-    }, " ", button_label, " "))));
-  }
-
-}
-
-/***/ }),
-/* 15 */
-/***/ (function(module, exports) {
-
-module.exports = ReactDOM;
-
-/***/ }),
-/* 16 */
-/***/ (function(module, __webpack_exports__, __webpack_require__) {
-
-"use strict";
-__webpack_require__.r(__webpack_exports__);
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ReturnToAMO", function() { return ReturnToAMO; });
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(10);
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
-/* harmony import */ var _components_RichText_RichText__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(17);
-
-
-class ReturnToAMO extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComponent {
-  constructor(props) {
-    super(props);
-    this.onClickAddExtension = this.onClickAddExtension.bind(this);
-    this.onBlockButton = this.onBlockButton.bind(this);
-  }
-
-  componentDidMount() {
-    this.props.onReady();
-  }
-
-  onClickAddExtension() {
-    this.props.onAction(this.props.content.primary_button.action);
-  }
-
-  onBlockButton() {
-    this.props.onBlock();
-    document.body.classList.remove("welcome", "hide-main", "amo");
-  }
-
-  renderText() {
-    const customElement = react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("img", {
-      src: this.props.content.addon_icon,
-      width: "20px",
-      height: "20px"
-    });
-    return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_components_RichText_RichText__WEBPACK_IMPORTED_MODULE_1__["RichText"], {
-      customElements: {
-        icon: customElement
-      },
-      amo_html: this.props.content.text,
-      localization_id: "amo_html"
-    });
-  }
-
-  render() {
-    const {
-      content
-    } = this.props;
-    return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
-      className: "ReturnToAMOOverlay"
-    }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("h2", null, " ", content.header, " "), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
-      className: "ReturnToAMOContainer"
-    }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
-      className: "ReturnToAMOAddonContents"
-    }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("p", null, " ", content.title, " "), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
-      className: "ReturnToAMOText"
-    }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("span", null, " ", this.renderText(), " ")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("button", {
-      onClick: this.onClickAddExtension,
-      className: "puffy blue ReturnToAMOAddExtension"
-    }, " ", react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("span", {
-      className: "icon icon-add"
-    }), " ", content.primary_button.label, " ")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
-      className: "ReturnToAMOIcon"
-    })), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("button", {
-      onClick: this.onBlockButton,
-      className: "default grey ReturnToAMOGetStarted"
-    }, " ", content.secondary_button.label, " ")));
-  }
-
-}
-
-/***/ }),
-/* 17 */
-/***/ (function(module, __webpack_exports__, __webpack_require__) {
-
-"use strict";
-__webpack_require__.r(__webpack_exports__);
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "convertLinks", function() { return convertLinks; });
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RichText", function() { return RichText; });
-/* harmony import */ var fluent_react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(57);
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(10);
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
-/* harmony import */ var _rich_text_strings__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(8);
-/* harmony import */ var _template_utils__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(18);
-function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
-
-
-
-
- // Elements allowed in snippet content
-
-const ALLOWED_TAGS = {
-  b: react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("b", null),
-  i: react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("i", null),
-  u: react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("u", null),
-  strong: react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("strong", null),
-  em: react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("em", null),
-  br: react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("br", null)
-};
-/**
- * Transform an object (tag name: {url}) into (tag name: anchor) where the url
- * is used as href, in order to render links inside a Fluent.Localized component.
- */
-
-function convertLinks(links, sendClick, doNotAutoBlock, openNewWindow = false) {
-  if (links) {
-    return Object.keys(links).reduce((acc, linkTag) => {
-      const {
-        action
-      } = links[linkTag]; // Setting the value to false will not include the attribute in the anchor
-
-      const url = action ? false : Object(_template_utils__WEBPACK_IMPORTED_MODULE_3__["safeURI"])(links[linkTag].url);
-      acc[linkTag] = react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("a", {
-        href: url,
-        target: openNewWindow ? "_blank" : "",
-        "data-metric": links[linkTag].metric,
-        "data-action": action,
-        "data-args": links[linkTag].args,
-        "data-do_not_autoblock": doNotAutoBlock,
-        onClick: sendClick
-      });
-      return acc;
-    }, {});
-  }
-
-  return null;
-}
-/**
- * Message wrapper used to sanitize markup and render HTML.
- */
-
-function RichText(props) {
-  if (!_rich_text_strings__WEBPACK_IMPORTED_MODULE_2__["RICH_TEXT_KEYS"].includes(props.localization_id)) {
-    throw new Error(`ASRouter: ${props.localization_id} is not a valid rich text property. If you want it to be processed, you need to add it to asrouter/rich-text-strings.js`);
-  }
-
-  return react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(fluent_react__WEBPACK_IMPORTED_MODULE_0__["Localized"], _extends({
-    id: props.localization_id
-  }, ALLOWED_TAGS, props.customElements, convertLinks(props.links, props.sendClick, props.doNotAutoBlock, props.openNewWindow)), react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("span", null, props.text));
-}
-
-/***/ }),
-/* 18 */
-/***/ (function(module, __webpack_exports__, __webpack_require__) {
-
-"use strict";
-__webpack_require__.r(__webpack_exports__);
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "safeURI", function() { return safeURI; });
-function safeURI(url) {
-  if (!url) {
-    return "";
-  }
-
-  const {
-    protocol
-  } = new URL(url);
-  const isAllowed = ["http:", "https:", "data:", "resource:", "chrome:"].includes(protocol);
-
-  if (!isAllowed) {
-    console.warn(`The protocol ${protocol} is not allowed for template URLs.`); // eslint-disable-line no-console
-  }
-
-  return isAllowed ? url : "";
-}
-
-/***/ }),
-/* 19 */
-/***/ (function(module) {
-
-module.exports = {"title":"EOYSnippet","description":"Fundraising Snippet","version":"1.0.0","type":"object","definitions":{"plainText":{"description":"Plain text (no HTML allowed)","type":"string"},"richText":{"description":"Text with HTML subset allowed: i, b, u, strong, em, br","type":"string"},"link_url":{"description":"Target for links or buttons","type":"string","format":"uri"}},"properties":{"donation_form_url":{"type":"string","description":"Url to the donation form."},"currency_code":{"type":"string","description":"The code for the currency. Examle gbp, cad, usd.","default":"usd"},"locale":{"type":"string","description":"String for the locale code.","default":"en-US"},"text":{"allOf":[{"$ref":"#/definitions/richText"},{"description":"Main body text of snippet. HTML subset allowed: i, b, u, strong, em, br"}]},"text_color":{"type":"string","description":"Modify the text message color"},"background_color":{"type":"string","description":"Snippet background color."},"highlight_color":{"type":"string","description":"Paragraph em highlight color."},"donation_amount_first":{"type":"number","description":"First button amount."},"donation_amount_second":{"type":"number","description":"Second button amount."},"donation_amount_third":{"type":"number","description":"Third button amount."},"donation_amount_fourth":{"type":"number","description":"Fourth button amount."},"selected_button":{"type":"string","description":"Default donation_amount_second. Donation amount button that's selected by default.","default":"donation_amount_second"},"icon":{"type":"string","description":"Snippet icon. 64x64px. SVG or PNG preferred."},"title":{"allOf":[{"$ref":"#/definitions/plainText"},{"description":"Snippet title displayed before snippet text"}]},"title_icon":{"type":"string","description":"Small icon that shows up before the title / text. 16x16px. SVG or PNG preferred. Grayscale."},"button_label":{"allOf":[{"$ref":"#/definitions/plainText"},{"description":"Text for a button next to main snippet text that links to button_url. Requires button_url."}]},"button_color":{"type":"string","description":"The text color of the button. Valid CSS color."},"button_background_color":{"type":"string","description":"The background color of the button. Valid CSS color."},"block_button_text":{"type":"string","description":"Tooltip text used for dismiss button."},"monthly_checkbox_label_text":{"type":"string","description":"Label text for monthly checkbox.","default":"Make my donation monthly"},"test":{"type":"string","description":"Different styles for the snippet. Options are bold and takeover."},"do_not_autoblock":{"type":"boolean","description":"Used to prevent blocking the snippet after the CTA (link or button) has been clicked"},"links":{"additionalProperties":{"url":{"allOf":[{"$ref":"#/definitions/link_url"},{"description":"The url where the link points to."}]},"metric":{"type":"string","description":"Custom event name sent with telemetry event."},"args":{"type":"string","description":"Additional parameters for link action, example which specific menu the button should open"}}}},"additionalProperties":false,"required":["text","donation_form_url","donation_amount_first","donation_amount_second","donation_amount_third","donation_amount_fourth","button_label","currency_code"],"dependencies":{"button_color":["button_label"],"button_background_color":["button_label"]}};
-
-/***/ }),
-/* 20 */
-/***/ (function(module) {
-
-module.exports = {"title":"SimpleSnippet","description":"A simple template with an icon, text, and optional button.","version":"1.1.1","type":"object","definitions":{"plainText":{"description":"Plain text (no HTML allowed)","type":"string"},"richText":{"description":"Text with HTML subset allowed: i, b, u, strong, em, br","type":"string"},"link_url":{"description":"Target for links or buttons","type":"string","format":"uri"}},"properties":{"title":{"allOf":[{"$ref":"#/definitions/plainText"},{"description":"Snippet title displayed before snippet text"}]},"text":{"allOf":[{"$ref":"#/definitions/richText"},{"description":"Main body text of snippet. HTML subset allowed: i, b, u, strong, em, br"}]},"icon":{"type":"string","description":"Snippet icon. 64x64px. SVG or PNG preferred."},"title_icon":{"type":"string","description":"Small icon that shows up before the title / text. 16x16px. SVG or PNG preferred. Grayscale."},"button_action":{"type":"string","description":"The type of action the button should trigger."},"button_url":{"allOf":[{"$ref":"#/definitions/link_url"},{"description":"A url, button_label links to this"}]},"button_action_args":{"type":"string","description":"Additional parameters for button action, example which specific menu the button should open"},"button_label":{"allOf":[{"$ref":"#/definitions/plainText"},{"description":"Text for a button next to main snippet text that links to button_url. Requires button_url."}]},"button_color":{"type":"string","description":"The text color of the button. Valid CSS color."},"button_background_color":{"type":"string","description":"The background color of the button. Valid CSS color."},"block_button_text":{"type":"string","description":"Tooltip text used for dismiss button.","default":"Remove this"},"tall":{"type":"boolean","description":"To be used by fundraising only, increases height to roughly 120px. Defaults to false."},"do_not_autoblock":{"type":"boolean","description":"Used to prevent blocking the snippet after the CTA (link or button) has been clicked"},"links":{"additionalProperties":{"url":{"allOf":[{"$ref":"#/definitions/link_url"},{"description":"The url where the link points to."}]},"metric":{"type":"string","description":"Custom event name sent with telemetry event."},"args":{"type":"string","description":"Additional parameters for link action, example which specific menu the button should open"}}},"section_title_icon":{"type":"string","description":"Section title icon. 16x16px. SVG or PNG preferred. section_title_text must also be specified to display."},"section_title_text":{"type":"string","description":"Section title text. section_title_icon must also be specified to display."},"section_title_url":{"allOf":[{"$ref":"#/definitions/link_url"},{"description":"A url, section_title_text links to this"}]}},"additionalProperties":false,"required":["text"],"dependencies":{"button_action":["button_label"],"button_url":["button_label"],"button_color":["button_label"],"button_background_color":["button_label"],"section_title_url":["section_title_text"]}};
-
-/***/ }),
-/* 21 */
-/***/ (function(module) {
-
-module.exports = {"title":"FXASignupSnippet","description":"A snippet template for FxA sign up/sign in","version":"1.0.0","type":"object","definitions":{"plainText":{"description":"Plain text (no HTML allowed)","type":"string"},"richText":{"description":"Text with HTML subset allowed: i, b, u, strong, em, br","type":"string"},"link_url":{"description":"Target for links or buttons","type":"string","format":"uri"}},"properties":{"scene1_title":{"allof":[{"$ref":"#/definitions/plainText"},{"description":"snippet title displayed before snippet text"}]},"scene1_text":{"allOf":[{"$ref":"#/definitions/richText"},{"description":"Main body text of snippet. HTML subset allowed: i, b, u, strong, em, br"}]},"scene2_title":{"allOf":[{"$ref":"#/definitions/plainText"},{"description":"Title displayed before text in scene 2. Should be plain text."}]},"scene2_text":{"allOf":[{"$ref":"#/definitions/richText"},{"description":"Main body text of snippet. HTML subset allowed: i, b, u, strong, em, br"}]},"scene1_icon":{"type":"string","description":"Snippet icon. 64x64px. SVG or PNG preferred."},"scene1_title_icon":{"type":"string","description":"Small icon that shows up before the title / text. 16x16px. SVG or PNG preferred. Grayscale."},"scene2_email_placeholder_text":{"type":"string","description":"Value to show while input is empty.","default":"Your email here"},"scene2_button_label":{"type":"string","description":"Label for form submit button","default":"Sign me up"},"scene2_dismiss_button_text":{"type":"string","description":"Label for the dismiss button when the sign-up form is expanded.","default":"Dismiss"},"hidden_inputs":{"type":"object","description":"Each entry represents a hidden input, key is used as value for the name property.","properties":{"action":{"type":"string","enum":["email"]},"context":{"type":"string","enum":["fx_desktop_v3"]},"entrypoint":{"type":"string","enum":["snippets"]},"service":{"type":"string","enum":["sync"]},"utm_content":{"type":"number","description":"Firefox version number"},"utm_source":{"type":"string","enum":["snippet"]},"utm_campaign":{"type":"string","description":"(fxa) Value to pass through to GA as utm_campaign."},"utm_term":{"type":"string","description":"(fxa) Value to pass through to GA as utm_term."},"additionalProperties":false}},"scene1_button_label":{"allOf":[{"$ref":"#/definitions/plainText"},{"description":"Text for a button next to main snippet text that links to button_url. Requires button_url."}],"default":"Learn more"},"scene1_button_color":{"type":"string","description":"The text color of the button. Valid CSS color."},"scene1_button_background_color":{"type":"string","description":"The background color of the button. Valid CSS color."},"do_not_autoblock":{"type":"boolean","description":"Used to prevent blocking the snippet after the CTA (link or button) has been clicked","default":false},"utm_campaign":{"type":"string","description":"(fxa) Value to pass through to GA as utm_campaign."},"utm_term":{"type":"string","description":"(fxa) Value to pass through to GA as utm_term."},"links":{"additionalProperties":{"url":{"allOf":[{"$ref":"#/definitions/link_url"},{"description":"The url where the link points to."}]},"metric":{"type":"string","description":"Custom event name sent with telemetry event."}}}},"additionalProperties":false,"required":["scene1_text","scene2_text","scene1_button_label"],"dependencies":{"scene1_button_color":["scene1_button_label"],"scene1_button_background_color":["scene1_button_label"]}};
-
-/***/ }),
-/* 22 */
-/***/ (function(module) {
-
-module.exports = {"title":"NewsletterSnippet","description":"A snippet template for send to device mobile download","version":"1.0.0","type":"object","definitions":{"plainText":{"description":"Plain text (no HTML allowed)","type":"string"},"richText":{"description":"Text with HTML subset allowed: i, b, u, strong, em, br","type":"string"},"link_url":{"description":"Target for links or buttons","type":"string","format":"uri"}},"properties":{"locale":{"type":"string","description":"Two to five character string for the locale code","default":"en-US"},"scene1_title":{"allof":[{"$ref":"#/definitions/plainText"},{"description":"snippet title displayed before snippet text"}]},"scene1_text":{"allOf":[{"$ref":"#/definitions/richText"},{"description":"Main body text of snippet. HTML subset allowed: i, b, u, strong, em, br"}]},"scene2_title":{"allOf":[{"$ref":"#/definitions/plainText"},{"description":"Title displayed before text in scene 2. Should be plain text."}]},"scene2_text":{"allOf":[{"$ref":"#/definitions/richText"},{"description":"Main body text of snippet. HTML subset allowed: i, b, u, strong, em, br"}]},"scene1_icon":{"type":"string","description":"Snippet icon. 64x64px. SVG or PNG preferred."},"scene1_title_icon":{"type":"string","description":"Small icon that shows up before the title / text. 16x16px. SVG or PNG preferred. Grayscale."},"scene2_email_placeholder_text":{"type":"string","description":"Value to show while input is empty.","default":"Your email here"},"scene2_button_label":{"type":"string","description":"Label for form submit button","default":"Sign me up"},"scene2_privacy_html":{"type":"string","description":"(send to device) Html for disclaimer and link underneath input box."},"scene2_dismiss_button_text":{"type":"string","description":"Label for the dismiss button when the sign-up form is expanded.","default":"Dismiss"},"hidden_inputs":{"type":"object","description":"Each entry represents a hidden input, key is used as value for the name property.","properties":{"fmt":{"type":"string","description":"","default":"H"}}},"scene1_button_label":{"allOf":[{"$ref":"#/definitions/plainText"},{"description":"Text for a button next to main snippet text that links to button_url. Requires button_url."}],"default":"Learn more"},"scene1_button_color":{"type":"string","description":"The text color of the button. Valid CSS color."},"scene1_button_background_color":{"type":"string","description":"The background color of the button. Valid CSS color."},"do_not_autoblock":{"type":"boolean","description":"Used to prevent blocking the snippet after the CTA (link or button) has been clicked","default":false},"success_text":{"type":"string","description":"Message shown on successful registration."},"error_text":{"type":"string","description":"Message shown if registration failed."},"scene2_newsletter":{"type":"string","description":"Newsletter/basket id user is subscribing to.","default":"mozilla-foundation"},"links":{"additionalProperties":{"url":{"allOf":[{"$ref":"#/definitions/link_url"},{"description":"The url where the link points to."}]},"metric":{"type":"string","description":"Custom event name sent with telemetry event."}}}},"additionalProperties":false,"required":["scene1_text","scene2_text","scene1_button_label"],"dependencies":{"scene1_button_color":["scene1_button_label"],"scene1_button_background_color":["scene1_button_label"]}};
-
-/***/ }),
-/* 23 */
-/***/ (function(module) {
-
-module.exports = {"title":"SendToDeviceSnippet","description":"A snippet template for send to device mobile download","version":"1.0.0","type":"object","definitions":{"plainText":{"description":"Plain text (no HTML allowed)","type":"string"},"richText":{"description":"Text with HTML subset allowed: i, b, u, strong, em, br","type":"string"},"link_url":{"description":"Target for links or buttons","type":"string","format":"uri"}},"properties":{"locale":{"type":"string","description":"Two to five character string for the locale code","default":"en-US"},"country":{"type":"string","description":"Two character string for the country code (used for SMS)","default":"us"},"scene1_title":{"allof":[{"$ref":"#/definitions/plainText"},{"description":"snippet title displayed before snippet text"}]},"scene1_text":{"allOf":[{"$ref":"#/definitions/richText"},{"description":"Main body text of snippet. HTML subset allowed: i, b, u, strong, em, br"}]},"scene2_title":{"allOf":[{"$ref":"#/definitions/plainText"},{"description":"Title displayed before text in scene 2. Should be plain text."}]},"scene2_text":{"allOf":[{"$ref":"#/definitions/richText"},{"description":"Main body text of snippet. HTML subset allowed: i, b, u, strong, em, br"}]},"scene1_icon":{"type":"string","description":"Snippet icon. 64x64px. SVG or PNG preferred."},"scene2_icon":{"type":"string","description":"(send to device) Image to display above the form. 98x98px. SVG or PNG preferred."},"scene1_title_icon":{"type":"string","description":"Small icon that shows up before the title / text. 16x16px. SVG or PNG preferred. Grayscale."},"scene2_button_label":{"type":"string","description":"Label for form submit button","default":"Send"},"scene2_input_placeholder":{"type":"string","description":"(send to device) Value to show while input is empty.","default":"Your email here"},"scene2_disclaimer_html":{"type":"string","description":"(send to device) Html for disclaimer and link underneath input box."},"scene2_dismiss_button_text":{"type":"string","description":"Label for the dismiss button when the sign-up form is expanded.","default":"Dismiss"},"hidden_inputs":{"type":"object","description":"Each entry represents a hidden input, key is used as value for the name property.","properties":{"action":{"type":"string","enum":["email"]},"context":{"type":"string","enum":["fx_desktop_v3"]},"entrypoint":{"type":"string","enum":["snippets"]},"service":{"type":"string","enum":["sync"]},"utm_content":{"type":"string","description":"Firefox version number"},"utm_source":{"type":"string","enum":["snippet"]},"utm_campaign":{"type":"string","description":"(fxa) Value to pass through to GA as utm_campaign."},"utm_term":{"type":"string","description":"(fxa) Value to pass through to GA as utm_term."},"additionalProperties":false}},"scene1_button_label":{"allOf":[{"$ref":"#/definitions/plainText"},{"description":"Text for a button next to main snippet text that links to button_url. Requires button_url."}],"default":"Learn more"},"scene1_button_color":{"type":"string","description":"The text color of the button. Valid CSS color."},"scene1_button_background_color":{"type":"string","description":"The background color of the button. Valid CSS color."},"do_not_autoblock":{"type":"boolean","description":"Used to prevent blocking the snippet after the CTA (link or button) has been clicked","default":false},"success_title":{"type":"string","description":"(send to device) Title shown before text on successful registration."},"success_text":{"type":"string","description":"Message shown on successful registration."},"error_text":{"type":"string","description":"Message shown if registration failed."},"include_sms":{"type":"boolean","description":"(send to device) Allow users to send an SMS message with the form?","default":false},"message_id_sms":{"type":"string","description":"(send to device) Newsletter/basket id representing the SMS message to be sent."},"message_id_email":{"type":"string","description":"(send to device) Newsletter/basket id representing the email message to be sent. Must be a value from the 'Slug' column here: https://basket.mozilla.org/news/."},"utm_campaign":{"type":"string","description":"(fxa) Value to pass through to GA as utm_campaign."},"utm_term":{"type":"string","description":"(fxa) Value to pass through to GA as utm_term."},"links":{"additionalProperties":{"url":{"allOf":[{"$ref":"#/definitions/link_url"},{"description":"The url where the link points to."}]},"metric":{"type":"string","description":"Custom event name sent with telemetry event."}}}},"additionalProperties":false,"required":["scene1_text","scene2_text","scene1_button_label"],"dependencies":{"scene1_button_color":["scene1_button_label"],"scene1_button_background_color":["scene1_button_label"]}};
-
-/***/ }),
-/* 24 */
-/***/ (function(module, __webpack_exports__, __webpack_require__) {
-
-"use strict";
-__webpack_require__.r(__webpack_exports__);
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_StartupOverlay", function() { return _StartupOverlay; });
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "StartupOverlay", function() { return StartupOverlay; });
-/* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
-/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5);
-/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__);
-/* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(25);
-/* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(react_redux__WEBPACK_IMPORTED_MODULE_2__);
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(10);
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_3__);
-
-
-
-
-class _StartupOverlay extends react__WEBPACK_IMPORTED_MODULE_3___default.a.PureComponent {
-  constructor(props) {
-    super(props);
-    this.onInputChange = this.onInputChange.bind(this);
-    this.onSubmit = this.onSubmit.bind(this);
-    this.clickSkip = this.clickSkip.bind(this);
-    this.initScene = this.initScene.bind(this);
-    this.removeOverlay = this.removeOverlay.bind(this);
-    this.onInputInvalid = this.onInputInvalid.bind(this);
-    this.state = {
-      emailInput: "",
-      overlayRemoved: false,
-      flowId: "",
-      flowBeginTime: 0
-    };
-    this.didFetch = false;
-  }
-
-  async componentWillUpdate() {
-    if (this.props.fxa_endpoint && !this.didFetch) {
-      try {
-        this.didFetch = true;
-        const fxaParams = "entrypoint=activity-stream-firstrun&utm_source=activity-stream&utm_campaign=firstrun&form_type=email";
-        const response = await fetch(`${this.props.fxa_endpoint}/metrics-flow?${fxaParams}`, {
-          credentials: "omit"
-        });
-
-        if (response.status === 200) {
-          const {
-            flowId,
-            flowBeginTime
-          } = await response.json();
-          this.setState({
-            flowId,
-            flowBeginTime
-          });
-        } else {
-          this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
-            type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].TELEMETRY_UNDESIRED_EVENT,
-            data: {
-              event: "FXA_METRICS_FETCH_ERROR",
-              value: response.status
-            }
-          }));
-        }
-      } catch (error) {
-        this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
-          type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].TELEMETRY_UNDESIRED_EVENT,
-          data: {
-            event: "FXA_METRICS_ERROR"
-          }
-        }));
-      }
-    }
-  }
-
-  componentDidMount() {
-    this.initScene();
-  }
-
-  initScene() {
-    // Timeout to allow the scene to render once before attaching the attribute
-    // to trigger the animation.
-    setTimeout(() => {
-      this.setState({
-        show: true
-      });
-      this.props.onReady();
-    }, 10);
-  }
-
-  removeOverlay() {
-    window.removeEventListener("visibilitychange", this.removeOverlay);
-    document.body.classList.remove("hide-main", "fxa");
-    this.setState({
-      show: false
-    });
-    this.props.onBlock();
-    setTimeout(() => {
-      // Allow scrolling and fully remove overlay after animation finishes.
-      document.body.classList.remove("welcome");
-      this.setState({
-        overlayRemoved: true
-      });
-    }, 400);
-  }
-
-  onInputChange(e) {
-    let error = e.target.previousSibling;
-    this.setState({
-      emailInput: e.target.value
-    });
-    error.classList.remove("active");
-    e.target.classList.remove("invalid");
-  }
-
-  onSubmit() {
-    this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].UserEvent({
-      event: "SUBMIT_EMAIL",
-      ...this._getFormInfo()
-    }));
-    window.addEventListener("visibilitychange", this.removeOverlay);
-  }
-
-  clickSkip() {
-    this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].UserEvent({
-      event: "SKIPPED_SIGNIN",
-      ...this._getFormInfo()
-    }));
-    this.removeOverlay();
-  }
-  /**
-   * Report to telemetry additional information about the form submission.
-   */
-
-
-  _getFormInfo() {
-    const value = {
-      has_flow_params: this.state.flowId.length > 0
-    };
-    return {
-      value
-    };
-  }
-
-  onInputInvalid(e) {
-    let error = e.target.previousSibling;
-    error.classList.add("active");
-    e.target.classList.add("invalid");
-    e.preventDefault(); // Override built-in form validation popup
-
-    e.target.focus();
-  }
-
-  render() {
-    // When skipping the onboarding tour we show AS but we are still on
-    // about:welcome, prop.isFirstrun is true and StartupOverlay is rendered
-    if (this.state.overlayRemoved) {
-      return null;
-    }
-
-    let termsLink = react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("a", {
-      href: `${this.props.fxa_endpoint}/legal/terms`,
-      target: "_blank",
-      rel: "noopener noreferrer"
-    }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
-      id: "firstrun_terms_of_service"
-    }));
-    let privacyLink = react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("a", {
-      href: `${this.props.fxa_endpoint}/legal/privacy`,
-      target: "_blank",
-      rel: "noopener noreferrer"
-    }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
-      id: "firstrun_privacy_notice"
-    }));
-    return react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", {
-      className: `overlay-wrapper ${this.state.show ? "show" : ""}`
-    }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", {
-      className: "background"
-    }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", {
-      className: "firstrun-scene"
-    }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", {
-      className: "fxaccounts-container"
-    }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", {
-      className: "firstrun-left-divider"
-    }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("h1", {
-      className: "firstrun-title"
-    }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
-      id: "firstrun_title"
-    })), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("p", {
-      className: "firstrun-content"
-    }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
-      id: "firstrun_content"
-    })), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("a", {
-      className: "firstrun-link",
-      href: "https://www.mozilla.org/firefox/features/sync/",
-      target: "_blank",
-      rel: "noopener noreferrer"
-    }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
-      id: "firstrun_learn_more_link"
-    }))), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", {
-      className: "firstrun-sign-in"
-    }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("p", {
-      className: "form-header"
-    }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
-      id: "firstrun_form_header"
-    }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("span", {
-      className: "sub-header"
-    }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
-      id: "firstrun_form_sub_header"
-    }))), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("form", {
-      method: "get",
-      action: this.props.fxa_endpoint,
-      target: "_blank",
-      rel: "noopener noreferrer",
-      onSubmit: this.onSubmit
-    }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", {
-      name: "service",
-      type: "hidden",
-      value: "sync"
-    }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", {
-      name: "action",
-      type: "hidden",
-      value: "email"
-    }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", {
-      name: "context",
-      type: "hidden",
-      value: "fx_desktop_v3"
-    }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", {
-      name: "entrypoint",
-      type: "hidden",
-      value: "activity-stream-firstrun"
-    }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", {
-      name: "utm_source",
-      type: "hidden",
-      value: "activity-stream"
-    }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", {
-      name: "utm_campaign",
-      type: "hidden",
-      value: "firstrun"
-    }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", {
-      name: "flow_id",
-      type: "hidden",
-      value: this.state.flowId
-    }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", {
-      name: "flow_begin_time",
-      type: "hidden",
-      value: this.state.flowBeginTime
-    }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("span", {
-      className: "error"
-    }, this.props.intl.formatMessage({
-      id: "firstrun_invalid_input"
-    })), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", {
-      className: "email-input",
-      name: "email",
-      type: "email",
-      required: "true",
-      onInvalid: this.onInputInvalid,
-      placeholder: this.props.intl.formatMessage({
-        id: "firstrun_email_input_placeholder"
-      }),
-      onChange: this.onInputChange
-    }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", {
-      className: "extra-links"
-    }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
-      id: "firstrun_extra_legal_links",
-      values: {
-        terms: termsLink,
-        privacy: privacyLink
-      }
-    })), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("button", {
-      className: "continue-button",
-      type: "submit"
-    }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
-      id: "firstrun_continue_to_login"
-    }))), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("button", {
-      className: "skip-button",
-      disabled: !!this.state.emailInput,
-      onClick: this.clickSkip
-    }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
-      id: "firstrun_skip_login"
-    }))))));
-  }
-
-}
-
-const getState = state => ({
-  fxa_endpoint: state.Prefs.values.fxa_endpoint
-});
-
-const StartupOverlay = Object(react_redux__WEBPACK_IMPORTED_MODULE_2__["connect"])(getState)(Object(react_intl__WEBPACK_IMPORTED_MODULE_1__["injectIntl"])(_StartupOverlay));
-
-/***/ }),
-/* 25 */
-/***/ (function(module, exports) {
-
-module.exports = ReactRedux;
-
-/***/ }),
-/* 26 */
-/***/ (function(module, __webpack_exports__, __webpack_require__) {
-
-"use strict";
-__webpack_require__.r(__webpack_exports__);
 /* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_Base", function() { return _Base; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BaseContent", function() { return BaseContent; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Base", function() { return Base; });
 /* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
-/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5);
+/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4);
 /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__);
-/* harmony import */ var content_src_components_ASRouterAdmin_ASRouterAdmin__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(27);
-/* harmony import */ var content_src_components_ConfirmDialog_ConfirmDialog__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(29);
-/* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(25);
-/* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(react_redux__WEBPACK_IMPORTED_MODULE_4__);
-/* harmony import */ var content_src_components_DiscoveryStreamBase_DiscoveryStreamBase__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(54);
-/* harmony import */ var content_src_components_ErrorBoundary_ErrorBoundary__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(35);
-/* harmony import */ var content_src_components_ManualMigration_ManualMigration__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(45);
-/* harmony import */ var common_PrerenderData_jsm__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(46);
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(10);
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_9___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_9__);
-/* harmony import */ var content_src_components_Search_Search__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(47);
-/* harmony import */ var content_src_components_Sections_Sections__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(48);
+/* harmony import */ var content_src_components_ASRouterAdmin_ASRouterAdmin__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(5);
+/* harmony import */ var _asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(6);
+/* harmony import */ var content_src_components_ConfirmDialog_ConfirmDialog__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(27);
+/* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(25);
+/* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(react_redux__WEBPACK_IMPORTED_MODULE_5__);
+/* harmony import */ var content_src_components_DiscoveryStreamBase_DiscoveryStreamBase__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(52);
+/* harmony import */ var content_src_components_ErrorBoundary_ErrorBoundary__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(34);
+/* harmony import */ var content_src_components_ManualMigration_ManualMigration__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(44);
+/* harmony import */ var common_PrerenderData_jsm__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(45);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(11);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_10___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_10__);
+/* harmony import */ var content_src_components_Search_Search__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(46);
+/* harmony import */ var content_src_components_Sections_Sections__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(47);
 function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
 
 
 
 
 
 
 
 
 
 
 
 
 
-let didLogDevtoolsHelpText = false;
-const PrefsButton = Object(react_intl__WEBPACK_IMPORTED_MODULE_1__["injectIntl"])(props => react__WEBPACK_IMPORTED_MODULE_9___default.a.createElement("div", {
+
+const PrefsButton = Object(react_intl__WEBPACK_IMPORTED_MODULE_1__["injectIntl"])(props => react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement("div", {
   className: "prefs-button"
-}, react__WEBPACK_IMPORTED_MODULE_9___default.a.createElement("button", {
+}, react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement("button", {
   className: "icon icon-settings",
   onClick: props.onClick,
   title: props.intl.formatMessage({
     id: "settings_pane_button_label"
   })
 }))); // Add the locale data for pluralization and relative-time formatting for now,
 // this just uses english locale data. We can make this more sophisticated if
 // more features are needed.
@@ -2546,17 +608,17 @@ function debounce(func, wait) {
       timer = null;
     };
 
     timer = setTimeout(wakeUp, wait);
     func.apply(this, args);
   };
 }
 
-class _Base extends react__WEBPACK_IMPORTED_MODULE_9___default.a.PureComponent {
+class _Base extends react__WEBPACK_IMPORTED_MODULE_10___default.a.PureComponent {
   componentWillMount() {
     const {
       locale
     } = this.props;
     addLocaleDataForReactIntl(locale);
 
     if (this.props.isFirstrun) {
       global.document.body.classList.add("welcome", "hide-main");
@@ -2599,42 +661,32 @@ class _Base extends react__WEBPACK_IMPOR
     const {
       App,
       locale,
       strings
     } = props;
     const {
       initialized
     } = App;
-    const prefs = props.Prefs.values;
-
-    if (prefs["asrouter.devtoolsEnabled"]) {
-      if (window.location.hash.startsWith("#asrouter") || window.location.hash.startsWith("#devtools")) {
-        return react__WEBPACK_IMPORTED_MODULE_9___default.a.createElement(content_src_components_ASRouterAdmin_ASRouterAdmin__WEBPACK_IMPORTED_MODULE_2__["ASRouterAdmin"], null);
-      } else if (!didLogDevtoolsHelpText) {
-        console.log("Activity Stream devtools enabled. To access visit %cabout:newtab#devtools", "font-weight: bold"); // eslint-disable-line no-console
-
-        didLogDevtoolsHelpText = true;
-      }
-    }
+    const isDevtoolsEnabled = props.Prefs.values["asrouter.devtoolsEnabled"];
 
     if (!props.isPrerendered && !initialized) {
       return null;
     }
 
-    return react__WEBPACK_IMPORTED_MODULE_9___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["IntlProvider"], {
+    return react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["IntlProvider"], {
       locale: locale,
       messages: strings
-    }, react__WEBPACK_IMPORTED_MODULE_9___default.a.createElement(content_src_components_ErrorBoundary_ErrorBoundary__WEBPACK_IMPORTED_MODULE_6__["ErrorBoundary"], {
+    }, react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(content_src_components_ErrorBoundary_ErrorBoundary__WEBPACK_IMPORTED_MODULE_7__["ErrorBoundary"], {
       className: "base-content-fallback"
-    }, react__WEBPACK_IMPORTED_MODULE_9___default.a.createElement(BaseContent, this.props)));
-  }
-
-}
-class BaseContent extends react__WEBPACK_IMPORTED_MODULE_9___default.a.PureComponent {
+    }, react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(react__WEBPACK_IMPORTED_MODULE_10___default.a.Fragment, null, react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(BaseContent, this.props), isDevtoolsEnabled ? react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(content_src_components_ASRouterAdmin_ASRouterAdmin__WEBPACK_IMPORTED_MODULE_2__["ASRouterAdmin"], null) : null)));
+  }
+
+}
+class BaseContent extends react__WEBPACK_IMPORTED_MODULE_10___default.a.PureComponent {
   constructor(props) {
     super(props);
     this.openPreferences = this.openPreferences.bind(this);
     this.onWindowScroll = debounce(this.onWindowScroll.bind(this), 5);
     this.state = {
       fixedSearch: false
     };
   }
@@ -2676,68 +728,76 @@ class BaseContent extends react__WEBPACK
     } = this;
     const {
       App
     } = props;
     const {
       initialized
     } = App;
     const prefs = props.Prefs.values;
-    const shouldBeFixedToTop = common_PrerenderData_jsm__WEBPACK_IMPORTED_MODULE_8__["PrerenderData"].arePrefsValid(name => prefs[name]);
+    const shouldBeFixedToTop = common_PrerenderData_jsm__WEBPACK_IMPORTED_MODULE_9__["PrerenderData"].arePrefsValid(name => prefs[name]);
     const noSectionsEnabled = !prefs["feeds.topsites"] && props.Sections.filter(section => section.enabled).length === 0;
     const isDiscoveryStream = props.DiscoveryStream.config && props.DiscoveryStream.config.enabled;
     const searchHandoffEnabled = prefs["improvesearch.handoffToAwesomebar"];
     const outerClassName = ["outer-wrapper", isDiscoveryStream && "ds-outer-wrapper-search-alignment", isDiscoveryStream && "ds-outer-wrapper-breakpoint-override", shouldBeFixedToTop && "fixed-to-top", prefs.showSearch && this.state.fixedSearch && !noSectionsEnabled && "fixed-search", prefs.showSearch && noSectionsEnabled && "only-search"].filter(v => v).join(" ");
-    return react__WEBPACK_IMPORTED_MODULE_9___default.a.createElement("div", null, react__WEBPACK_IMPORTED_MODULE_9___default.a.createElement("div", {
+    return react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement("div", null, react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement("div", {
       className: outerClassName
-    }, react__WEBPACK_IMPORTED_MODULE_9___default.a.createElement("main", null, prefs.showSearch && react__WEBPACK_IMPORTED_MODULE_9___default.a.createElement("div", {
+    }, react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement("main", null, prefs.showSearch && react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement("div", {
       className: "non-collapsible-section"
-    }, react__WEBPACK_IMPORTED_MODULE_9___default.a.createElement(content_src_components_ErrorBoundary_ErrorBoundary__WEBPACK_IMPORTED_MODULE_6__["ErrorBoundary"], null, react__WEBPACK_IMPORTED_MODULE_9___default.a.createElement(content_src_components_Search_Search__WEBPACK_IMPORTED_MODULE_10__["Search"], _extends({
+    }, react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(content_src_components_ErrorBoundary_ErrorBoundary__WEBPACK_IMPORTED_MODULE_7__["ErrorBoundary"], null, react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(content_src_components_Search_Search__WEBPACK_IMPORTED_MODULE_11__["Search"], _extends({
       showLogo: noSectionsEnabled,
       handoffEnabled: searchHandoffEnabled
-    }, props.Search)))), react__WEBPACK_IMPORTED_MODULE_9___default.a.createElement("div", {
+    }, props.Search)))), react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement("div", {
       className: `body-wrapper${initialized ? " on" : ""}`
-    }, !isDiscoveryStream && !prefs.migrationExpired && react__WEBPACK_IMPORTED_MODULE_9___default.a.createElement("div", {
+    }, !isDiscoveryStream && !prefs.migrationExpired && react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement("div", {
       className: "non-collapsible-section"
-    }, react__WEBPACK_IMPORTED_MODULE_9___default.a.createElement(content_src_components_ManualMigration_ManualMigration__WEBPACK_IMPORTED_MODULE_7__["ManualMigration"], null)), isDiscoveryStream ? react__WEBPACK_IMPORTED_MODULE_9___default.a.createElement(content_src_components_ErrorBoundary_ErrorBoundary__WEBPACK_IMPORTED_MODULE_6__["ErrorBoundary"], {
+    }, react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(content_src_components_ManualMigration_ManualMigration__WEBPACK_IMPORTED_MODULE_8__["ManualMigration"], null)), isDiscoveryStream ? react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(content_src_components_ErrorBoundary_ErrorBoundary__WEBPACK_IMPORTED_MODULE_7__["ErrorBoundary"], {
       className: "borderless-error"
-    }, react__WEBPACK_IMPORTED_MODULE_9___default.a.createElement(content_src_components_DiscoveryStreamBase_DiscoveryStreamBase__WEBPACK_IMPORTED_MODULE_5__["DiscoveryStreamBase"], null)) : react__WEBPACK_IMPORTED_MODULE_9___default.a.createElement(content_src_components_Sections_Sections__WEBPACK_IMPORTED_MODULE_11__["Sections"], null), react__WEBPACK_IMPORTED_MODULE_9___default.a.createElement(PrefsButton, {
+    }, react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(content_src_components_DiscoveryStreamBase_DiscoveryStreamBase__WEBPACK_IMPORTED_MODULE_6__["DiscoveryStreamBase"], null)) : react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(content_src_components_Sections_Sections__WEBPACK_IMPORTED_MODULE_12__["Sections"], null), react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(PrefsButton, {
       onClick: this.openPreferences
-    })), react__WEBPACK_IMPORTED_MODULE_9___default.a.createElement(content_src_components_ConfirmDialog_ConfirmDialog__WEBPACK_IMPORTED_MODULE_3__["ConfirmDialog"], null))));
-  }
-
-}
-const Base = Object(react_redux__WEBPACK_IMPORTED_MODULE_4__["connect"])(state => ({
+    })), react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(content_src_components_ConfirmDialog_ConfirmDialog__WEBPACK_IMPORTED_MODULE_4__["ConfirmDialog"], null))), react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(_asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_3__["ASRouterUISurface"], {
+      dispatch: this.props.dispatch
+    }));
+  }
+
+}
+const Base = Object(react_redux__WEBPACK_IMPORTED_MODULE_5__["connect"])(state => ({
   App: state.App,
   Prefs: state.Prefs,
   Sections: state.Sections,
   DiscoveryStream: state.DiscoveryStream,
   Search: state.Search
 }))(_Base);
 /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
 
 /***/ }),
-/* 27 */
+/* 4 */
+/***/ (function(module, exports) {
+
+module.exports = ReactIntl;
+
+/***/ }),
+/* 5 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ToggleSpocButton", function() { return ToggleSpocButton; });
+/* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ToggleSpocButton", function() { return ToggleSpocButton; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DiscoveryStreamAdmin", function() { return DiscoveryStreamAdmin; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ASRouterAdminInner", function() { return ASRouterAdminInner; });
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_ASRouterAdmin", function() { return _ASRouterAdmin; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CollapseToggle", function() { return CollapseToggle; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ASRouterAdmin", function() { return ASRouterAdmin; });
 /* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
-/* harmony import */ var _asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4);
+/* harmony import */ var _asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6);
 /* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(25);
 /* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(react_redux__WEBPACK_IMPORTED_MODULE_2__);
-/* harmony import */ var _asrouter_components_ModalOverlay_ModalOverlay__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(14);
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(10);
+/* harmony import */ var _asrouter_components_ModalOverlay_ModalOverlay__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(15);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(11);
 /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_4__);
-/* harmony import */ var _SimpleHashRouter__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(28);
+/* harmony import */ var _SimpleHashRouter__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(26);
 function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
 
 
 
 
 
 
 
@@ -3552,17 +1612,17 @@ class ASRouterAdminInner extends react__
           className: "button",
           onClick: this.resetPref
         }, "Restore default prefs")), this.state.providers ? this.renderProviders() : null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("h2", null, "Messages"), this.renderMessageFilter(), this.renderMessages(), this.renderPasteModal());
     }
   }
 
   render() {
     return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", {
-      className: "asrouter-admin"
+      className: `asrouter-admin ${this.props.collapsed ? "collapsed" : "expanded"}`
     }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("aside", {
       className: "sidebar"
     }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("ul", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("li", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("a", {
       href: "#devtools"
     }, "General")), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("li", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("a", {
       href: "#devtools-targeting"
     }, "Targeting")), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("li", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("a", {
       href: "#devtools-pocket"
@@ -3578,31 +1638,1510 @@ class ASRouterAdminInner extends react__
       className: "icon icon-small-spacer icon-info"
     }), " ", react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("span", null, "Need help using these tools? Check out our ", react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("a", {
       target: "blank",
       href: "https://github.com/mozilla/activity-stream/blob/master/content-src/asrouter/docs/debugging-docs.md"
     }, "documentation"))), this.getSection()));
   }
 
 }
-const _ASRouterAdmin = props => react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(_SimpleHashRouter__WEBPACK_IMPORTED_MODULE_5__["SimpleHashRouter"], null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(ASRouterAdminInner, props));
+class CollapseToggle extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureComponent {
+  constructor(props) {
+    super(props);
+    this.onCollapseToggle = this.onCollapseToggle.bind(this);
+    this.state = {
+      collapsed: false
+    };
+  }
+
+  get renderAdmin() {
+    const {
+      props
+    } = this;
+    return props.location.hash && (props.location.hash.startsWith("#asrouter") || props.location.hash.startsWith("#devtools"));
+  }
+
+  onCollapseToggle(e) {
+    e.preventDefault();
+    this.setState(state => ({
+      collapsed: !state.collapsed
+    }));
+  }
+
+  setBodyClass() {
+    if (this.renderAdmin && !this.state.collapsed) {
+      global.document.body.classList.add("no-scroll");
+    } else {
+      global.document.body.classList.remove("no-scroll");
+    }
+  }
+
+  componentDidMount() {
+    this.setBodyClass();
+  }
+
+  componentDidUpdate() {
+    this.setBodyClass();
+  }
+
+  componentWillUnmount() {
+    global.document.body.classList.remove("no-scroll");
+  }
+
+  render() {
+    const {
+      props
+    } = this;
+    const {
+      renderAdmin
+    } = this;
+    const action = this.state.collapsed || !renderAdmin ? "Expand" : "Collapse";
+    return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(react__WEBPACK_IMPORTED_MODULE_4___default.a.Fragment, null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("a", {
+      href: "#devtools",
+      className: "asrouter-toggle",
+      onClick: this.renderAdmin ? this.onCollapseToggle : null
+    }, action, " Devtools"), renderAdmin ? react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(ASRouterAdminInner, _extends({}, props, {
+      collapsed: this.state.collapsed
+    })) : null);
+  }
+
+}
+
+const _ASRouterAdmin = props => react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(_SimpleHashRouter__WEBPACK_IMPORTED_MODULE_5__["SimpleHashRouter"], null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(CollapseToggle, props));
+
 const ASRouterAdmin = Object(react_redux__WEBPACK_IMPORTED_MODULE_2__["connect"])(state => ({
   Sections: state.Sections,
   DiscoveryStream: state.DiscoveryStream,
   Prefs: state.Prefs
 }))(_ASRouterAdmin);
+/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
+
+/***/ }),
+/* 6 */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ASRouterUtils", function() { return ASRouterUtils; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ASRouterUISurface", function() { return ASRouterUISurface; });
+/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4);
+/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_0__);
+/* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
+/* harmony import */ var content_src_lib_init_store__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(7);
+/* harmony import */ var _rich_text_strings__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(9);
+/* harmony import */ var _components_ImpressionsWrapper_ImpressionsWrapper__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(10);
+/* harmony import */ var fluent_react__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(55);
+/* harmony import */ var content_src_lib_constants__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(13);
+/* harmony import */ var _templates_OnboardingMessage_OnboardingMessage__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(14);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(11);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_8___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_8__);
+/* harmony import */ var _templates_ReturnToAMO_ReturnToAMO__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(16);
+/* harmony import */ var _templates_template_manifest__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(53);
+/* harmony import */ var _templates_StartupOverlay_StartupOverlay__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(24);
+function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
+
+
+
+
+
+
+
+
+
+
+
+
+
+const INCOMING_MESSAGE_NAME = "ASRouter:parent-to-child";
+const OUTGOING_MESSAGE_NAME = "ASRouter:child-to-parent";
+const ASRouterUtils = {
+  addListener(listener) {
+    if (global.RPMAddMessageListener) {
+      global.RPMAddMessageListener(INCOMING_MESSAGE_NAME, listener);
+    }
+  },
+
+  removeListener(listener) {
+    if (global.RPMRemoveMessageListener) {
+      global.RPMRemoveMessageListener(INCOMING_MESSAGE_NAME, listener);
+    }
+  },
+
+  sendMessage(action) {
+    if (global.RPMSendAsyncMessage) {
+      global.RPMSendAsyncMessage(OUTGOING_MESSAGE_NAME, action);
+    }
+  },
+
+  blockById(id, options) {
+    ASRouterUtils.sendMessage({
+      type: "BLOCK_MESSAGE_BY_ID",
+      data: {
+        id,
+        ...options
+      }
+    });
+  },
+
+  dismissById(id) {
+    ASRouterUtils.sendMessage({
+      type: "DISMISS_MESSAGE_BY_ID",
+      data: {
+        id
+      }
+    });
+  },
+
+  dismissBundle(bundle) {
+    ASRouterUtils.sendMessage({
+      type: "DISMISS_BUNDLE",
+      data: {
+        bundle
+      }
+    });
+  },
+
+  executeAction(button_action) {
+    ASRouterUtils.sendMessage({
+      type: "USER_ACTION",
+      data: button_action
+    });
+  },
+
+  unblockById(id) {
+    ASRouterUtils.sendMessage({
+      type: "UNBLOCK_MESSAGE_BY_ID",
+      data: {
+        id
+      }
+    });
+  },
+
+  unblockBundle(bundle) {
+    ASRouterUtils.sendMessage({
+      type: "UNBLOCK_BUNDLE",
+      data: {
+        bundle
+      }
+    });
+  },
+
+  overrideMessage(id) {
+    ASRouterUtils.sendMessage({
+      type: "OVERRIDE_MESSAGE",
+      data: {
+        id
+      }
+    });
+  },
+
+  sendTelemetry(ping) {
+    if (global.RPMSendAsyncMessage) {
+      const payload = common_Actions_jsm__WEBPACK_IMPORTED_MODULE_1__["actionCreators"].ASRouterUserEvent(ping);
+      global.RPMSendAsyncMessage(content_src_lib_init_store__WEBPACK_IMPORTED_MODULE_2__["OUTGOING_MESSAGE_NAME"], payload);
+    }
+  },
+
+  getPreviewEndpoint() {
+    if (global.location && global.location.href.includes("endpoint")) {
+      const params = new URLSearchParams(global.location.href.slice(global.location.href.indexOf("endpoint")));
+
+      try {
+        const endpoint = new URL(params.get("endpoint"));
+        return {
+          url: endpoint.href,
+          snippetId: params.get("snippetId"),
+          theme: this.getPreviewTheme()
+        };
+      } catch (e) {}
+    }
+
+    return null;
+  },
+
+  getPreviewTheme() {
+    return new URLSearchParams(global.location.href.slice(global.location.href.indexOf("theme"))).get("theme");
+  }
+
+}; // Note: nextProps/prevProps refer to props passed to <ImpressionsWrapper />, not <ASRouterUISurface />
+
+function shouldSendImpressionOnUpdate(nextProps, prevProps) {
+  return nextProps.message.id && (!prevProps.message || prevProps.message.id !== nextProps.message.id);
+}
+
+class ASRouterUISurface extends react__WEBPACK_IMPORTED_MODULE_8___default.a.PureComponent {
+  constructor(props) {
+    super(props);
+    this.onMessageFromParent = this.onMessageFromParent.bind(this);
+    this.sendClick = this.sendClick.bind(this);
+    this.sendImpression = this.sendImpression.bind(this);
+    this.sendUserActionTelemetry = this.sendUserActionTelemetry.bind(this);
+    this.state = {
+      message: {},
+      bundle: {}
+    };
+  }
+
+  sendUserActionTelemetry(extraProps = {}) {
+    const {
+      message,
+      bundle
+    } = this.state;
+
+    if (!message && !extraProps.message_id) {
+      throw new Error(`You must provide a message_id for bundled messages`);
+    }
+
+    const eventType = `${message.provider || bundle.provider}_user_event`;
+    ASRouterUtils.sendTelemetry({
+      message_id: message.id || extraProps.message_id,
+      source: extraProps.id,
+      action: eventType,
+      ...extraProps
+    });
+  }
+
+  sendImpression(extraProps) {
+    if (this.state.message.provider === "preview") {
+      return;
+    }
+
+    ASRouterUtils.sendMessage({
+      type: "IMPRESSION",
+      data: this.state.message
+    });
+    this.sendUserActionTelemetry({
+      event: "IMPRESSION",
+      ...extraProps
+    });
+  } // If link has a `metric` data attribute send it as part of the `value`
+  // telemetry field which can have arbitrary values.
+  // Used for router messages with links as part of the content.
+
+
+  sendClick(event) {
+    const metric = {
+      value: event.target.dataset.metric,
+      // Used for the `source` of the event. Needed to differentiate
+      // from other snippet or onboarding events that may occur.
+      id: "NEWTAB_FOOTER_BAR_CONTENT"
+    };
+    const action = {
+      type: event.target.dataset.action,
+      data: {
+        args: event.target.dataset.args
+      }
+    };
+
+    if (action.type) {
+      ASRouterUtils.executeAction(action);
+    }
+
+    if (!this.state.message.content.do_not_autoblock && !event.target.dataset.do_not_autoblock) {
+      ASRouterUtils.blockById(this.state.message.id);
+    }
+
+    if (this.state.message.provider !== "preview") {
+      this.sendUserActionTelemetry({
+        event: "CLICK_BUTTON",
+        ...metric
+      });
+    }
+  }
+
+  onBlockById(id) {
+    return options => ASRouterUtils.blockById(id, options);
+  }
+
+  onDismissById(id) {
+    return () => ASRouterUtils.dismissById(id);
+  }
+
+  dismissBundle(bundle) {
+    return () => ASRouterUtils.dismissBundle(bundle);
+  }
+
+  triggerOnboarding() {
+    ASRouterUtils.sendMessage({
+      type: "TRIGGER",
+      data: {
+        trigger: {
+          id: "showOnboarding"
+        }
+      }
+    });
+  }
+
+  onMessageFromParent({
+    data: action
+  }) {
+    switch (action.type) {
+      case "SET_MESSAGE":
+        this.setState({
+          message: action.data
+        });
+        break;
+
+      case "SET_BUNDLED_MESSAGES":
+        this.setState({
+          bundle: action.data
+        });
+        break;
+
+      case "CLEAR_MESSAGE":
+        if (action.data.id === this.state.message.id) {
+          this.setState({
+            message: {}
+          }); // Remove any styles related to the RTAMO message
+
+          document.body.classList.remove("welcome", "hide-main", "amo");
+        }
+
+        break;
+
+      case "CLEAR_PROVIDER":
+        if (action.data.id === this.state.message.provider) {
+          this.setState({
+            message: {}
+          });
+        }
+
+        break;
+
+      case "CLEAR_BUNDLE":
+        if (this.state.bundle.bundle) {
+          this.setState({
+            bundle: {}
+          });
+        }
+
+        break;
+
+      case "CLEAR_ALL":
+        this.setState({
+          message: {},
+          bundle: {}
+        });
+    }
+  }
+
+  componentWillMount() {
+    if (global.document) {
+      // Add locale data for StartupOverlay because it uses react-intl
+      Object(react_intl__WEBPACK_IMPORTED_MODULE_0__["addLocaleData"])(global.document.documentElement.lang);
+    }
+
+    const endpoint = ASRouterUtils.getPreviewEndpoint();
+
+    if (endpoint && endpoint.theme === "dark") {
+      global.window.dispatchEvent(new CustomEvent("LightweightTheme:Set", {
+        detail: {
+          data: content_src_lib_constants__WEBPACK_IMPORTED_MODULE_6__["NEWTAB_DARK_THEME"]
+        }
+      }));
+    }
+
+    ASRouterUtils.addListener(this.onMessageFromParent); // If we are loading about:welcome we want to trigger the onboarding messages
+
+    if (this.props.document && this.props.document.location.href === "about:welcome") {
+      ASRouterUtils.sendMessage({
+        type: "TRIGGER",
+        data: {
+          trigger: {
+            id: "firstRun"
+          }
+        }
+      });
+    } else {
+      ASRouterUtils.sendMessage({
+        type: "SNIPPETS_REQUEST",
+        data: {
+          endpoint
+        }
+      });
+    }
+  }
+
+  componentWillUnmount() {
+    ASRouterUtils.removeListener(this.onMessageFromParent);
+  }
+
+  renderSnippets() {
+    if (this.state.bundle.template === "onboarding" || this.state.message.template === "fxa_overlay" || this.state.message.template === "return_to_amo_overlay") {
+      return null;
+    }
+
+    const SnippetComponent = _templates_template_manifest__WEBPACK_IMPORTED_MODULE_10__["SnippetsTemplates"][this.state.message.template];
+    const {
+      content
+    } = this.state.message;
+    return react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(_components_ImpressionsWrapper_ImpressionsWrapper__WEBPACK_IMPORTED_MODULE_4__["ImpressionsWrapper"], {
+      id: "NEWTAB_FOOTER_BAR",
+      message: this.state.message,
+      sendImpression: this.sendImpression,
+      shouldSendImpressionOnUpdate: shouldSendImpressionOnUpdate // This helps with testing
+      ,
+      document: this.props.document
+    }, react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(fluent_react__WEBPACK_IMPORTED_MODULE_5__["LocalizationProvider"], {
+      messages: Object(_rich_text_strings__WEBPACK_IMPORTED_MODULE_3__["generateMessages"])(content)
+    }, react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(SnippetComponent, _extends({}, this.state.message, {
+      UISurface: "NEWTAB_FOOTER_BAR",
+      onBlock: this.onBlockById(this.state.message.id),
+      onDismiss: this.onDismissById(this.state.message.id),
+      onAction: ASRouterUtils.executeAction,
+      sendClick: this.sendClick,
+      sendUserActionTelemetry: this.sendUserActionTelemetry
+    }))));
+  }
+
+  renderOnboarding() {
+    if (this.state.bundle.template === "onboarding") {
+      return react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(_templates_OnboardingMessage_OnboardingMessage__WEBPACK_IMPORTED_MODULE_7__["OnboardingMessage"], _extends({}, this.state.bundle, {
+        UISurface: "NEWTAB_OVERLAY",
+        onAction: ASRouterUtils.executeAction,
+        onDoneButton: this.dismissBundle(this.state.bundle.bundle),
+        sendUserActionTelemetry: this.sendUserActionTelemetry
+      }));
+    }
+
+    return null;
+  }
+
+  renderFirstRunOverlay() {
+    const {
+      message
+    } = this.state;
+
+    if (message.template === "fxa_overlay") {
+      global.document.body.classList.add("fxa");
+      return react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_0__["IntlProvider"], {
+        locale: global.document.documentElement.lang,
+        messages: global.gActivityStreamStrings
+      }, react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(_templates_StartupOverlay_StartupOverlay__WEBPACK_IMPORTED_MODULE_11__["StartupOverlay"], {
+        onReady: this.triggerOnboarding,
+        onBlock: this.onDismissById(message.id),
+        dispatch: this.props.dispatch
+      }));
+    } else if (message.template === "return_to_amo_overlay") {
+      global.document.body.classList.add("amo");
+      return react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(fluent_react__WEBPACK_IMPORTED_MODULE_5__["LocalizationProvider"], {
+        messages: Object(_rich_text_strings__WEBPACK_IMPORTED_MODULE_3__["generateMessages"])({
+          "amo_html": message.content.text
+        })
+      }, react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(_templates_ReturnToAMO_ReturnToAMO__WEBPACK_IMPORTED_MODULE_9__["ReturnToAMO"], _extends({}, message, {
+        onReady: this.triggerOnboarding,
+        onBlock: this.onDismissById(message.id),
+        onAction: ASRouterUtils.executeAction
+      })));
+    }
+
+    return null;
+  }
+
+  renderPreviewBanner() {
+    if (this.state.message.provider !== "preview") {
+      return null;
+    }
+
+    return react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement("div", {
+      className: "snippets-preview-banner"
+    }, react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement("span", {
+      className: "icon icon-small-spacer icon-info"
+    }), react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement("span", null, "Preview Purposes Only"));
+  }
+
+  render() {
+    const {
+      message,
+      bundle
+    } = this.state;
+
+    if (!message.id && !bundle.template) {
+      return null;
+    }
+
+    return react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(react__WEBPACK_IMPORTED_MODULE_8___default.a.Fragment, null, this.renderPreviewBanner(), this.renderFirstRunOverlay(), this.renderOnboarding(), this.renderSnippets());
+  }
+
+}
+ASRouterUISurface.defaultProps = {
+  document: global.document
+};
+/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
+
+/***/ }),
+/* 7 */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MERGE_STORE_ACTION", function() { return MERGE_STORE_ACTION; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OUTGOING_MESSAGE_NAME", function() { return OUTGOING_MESSAGE_NAME; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "INCOMING_MESSAGE_NAME", function() { return INCOMING_MESSAGE_NAME; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EARLY_QUEUED_ACTIONS", function() { return EARLY_QUEUED_ACTIONS; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "rehydrationMiddleware", function() { return rehydrationMiddleware; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "queueEarlyMessageMiddleware", function() { return queueEarlyMessageMiddleware; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "initStore", function() { return initStore; });
+/* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
+/* harmony import */ var redux__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(8);
+/* harmony import */ var redux__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(redux__WEBPACK_IMPORTED_MODULE_1__);
+/* eslint-env mozilla/frame-script */
+
+
+const MERGE_STORE_ACTION = "NEW_TAB_INITIAL_STATE";
+const OUTGOING_MESSAGE_NAME = "ActivityStream:ContentToMain";
+const INCOMING_MESSAGE_NAME = "ActivityStream:MainToContent";
+const EARLY_QUEUED_ACTIONS = [common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].SAVE_SESSION_PERF_DATA, common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].PAGE_PRERENDERED];
+/**
+ * A higher-order function which returns a reducer that, on MERGE_STORE action,
+ * will return the action.data object merged into the previous state.
+ *
+ * For all other actions, it merely calls mainReducer.
+ *
+ * Because we want this to merge the entire state object, it's written as a
+ * higher order function which takes the main reducer (itself often a call to
+ * combineReducers) as a parameter.
+ *
+ * @param  {function} mainReducer reducer to call if action != MERGE_STORE_ACTION
+ * @return {function}             a reducer that, on MERGE_STORE_ACTION action,
+ *                                will return the action.data object merged
+ *                                into the previous state, and the result
+ *                                of calling mainReducer otherwise.
+ */
+
+function mergeStateReducer(mainReducer) {
+  return (prevState, action) => {
+    if (action.type === MERGE_STORE_ACTION) {
+      return { ...prevState,
+        ...action.data
+      };
+    }
+
+    return mainReducer(prevState, action);
+  };
+}
+/**
+ * messageMiddleware - Middleware that looks for SentToMain type actions, and sends them if necessary
+ */
+
+
+const messageMiddleware = store => next => action => {
+  const skipLocal = action.meta && action.meta.skipLocal;
+
+  if (common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionUtils"].isSendToMain(action)) {
+    RPMSendAsyncMessage(OUTGOING_MESSAGE_NAME, action);
+  }
+
+  if (!skipLocal) {
+    next(action);
+  }
+};
+
+const rehydrationMiddleware = store => next => action => {
+  if (store._didRehydrate) {
+    return next(action);
+  }
+
+  const isMergeStoreAction = action.type === MERGE_STORE_ACTION;
+  const isRehydrationRequest = action.type === common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].NEW_TAB_STATE_REQUEST;
+
+  if (isRehydrationRequest) {
+    store._didRequestInitialState = true;
+    return next(action);
+  }
+
+  if (isMergeStoreAction) {
+    store._didRehydrate = true;
+    return next(action);
+  } // If init happened after our request was made, we need to re-request
+
+
+  if (store._didRequestInitialState && action.type === common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].INIT) {
+    return next(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({
+      type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].NEW_TAB_STATE_REQUEST
+    }));
+  }
+
+  if (common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionUtils"].isBroadcastToContent(action) || common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionUtils"].isSendToOneContent(action) || common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionUtils"].isSendToPreloaded(action)) {
+    // Note that actions received before didRehydrate will not be dispatched
+    // because this could negatively affect preloading and the the state
+    // will be replaced by rehydration anyway.
+    return null;
+  }
+
+  return next(action);
+};
+/**
+ * This middleware queues up all the EARLY_QUEUED_ACTIONS until it receives
+ * the first action from main. This is useful for those actions for main which
+ * require higher reliability, i.e. the action will not be lost in the case
+ * that it gets sent before the main is ready to receive it. Conversely, any
+ * actions allowed early are accepted to be ignorable or re-sendable.
+ */
+
+const queueEarlyMessageMiddleware = store => next => action => {
+  if (store._receivedFromMain) {
+    next(action);
+  } else if (common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionUtils"].isFromMain(action)) {
+    next(action);
+    store._receivedFromMain = true; // Sending out all the early actions as main is ready now
+
+    if (store._earlyActionQueue) {
+      store._earlyActionQueue.forEach(next);
+
+      store._earlyActionQueue = [];
+    }
+  } else if (EARLY_QUEUED_ACTIONS.includes(action.type)) {
+    store._earlyActionQueue = store._earlyActionQueue || [];
+
+    store._earlyActionQueue.push(action);
+  } else {
+    // Let any other type of action go through
+    next(action);
+  }
+};
+/**
+ * initStore - Create a store and listen for incoming actions
+ *
+ * @param  {object} reducers An object containing Redux reducers
+ * @param  {object} intialState (optional) The initial state of the store, if desired
+ * @return {object}          A redux store
+ */
+
+function initStore(reducers, initialState) {
+  const store = Object(redux__WEBPACK_IMPORTED_MODULE_1__["createStore"])(mergeStateReducer(Object(redux__WEBPACK_IMPORTED_MODULE_1__["combineReducers"])(reducers)), initialState, global.RPMAddMessageListener && Object(redux__WEBPACK_IMPORTED_MODULE_1__["applyMiddleware"])(rehydrationMiddleware, queueEarlyMessageMiddleware, messageMiddleware));
+  store._didRehydrate = false;
+  store._didRequestInitialState = false;
+
+  if (global.RPMAddMessageListener) {
+    global.RPMAddMessageListener(INCOMING_MESSAGE_NAME, msg => {
+      try {
+        store.dispatch(msg.data);
+      } catch (ex) {
+        console.error("Content msg:", msg, "Dispatch error: ", ex); // eslint-disable-line no-console
+
+        dump(`Content msg: ${JSON.stringify(msg)}\nDispatch error: ${ex}\n${ex.stack}`);
+      }
+    });
+  }
+
+  return store;
+}
+/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
+
+/***/ }),
+/* 8 */
+/***/ (function(module, exports) {
+
+module.exports = Redux;
+
+/***/ }),
+/* 9 */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RICH_TEXT_KEYS", function() { return RICH_TEXT_KEYS; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "generateMessages", function() { return generateMessages; });
+/* harmony import */ var fluent__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(54);
+
+/**
+ * Properties that allow rich text MUST be added to this list.
+ *   key: the localization_id that should be used
+ *   value: a property or array of properties on the message.content object
+ */
+
+const RICH_TEXT_CONFIG = {
+  "text": ["text", "scene1_text"],
+  "success_text": "success_text",
+  "error_text": "error_text",
+  "scene2_text": "scene2_text",
+  "amo_html": "amo_html",
+  "privacy_html": "scene2_privacy_html",
+  "disclaimer_html": "scene2_disclaimer_html"
+};
+const RICH_TEXT_KEYS = Object.keys(RICH_TEXT_CONFIG);
+/**
+ * Generates an array of messages suitable for fluent's localization provider
+ * including all needed strings for rich text.
+ * @param {object} content A .content object from an ASR message (i.e. message.content)
+ * @returns {MessageContext[]} A array containing the fluent message context
+ */
+
+function generateMessages(content) {
+  const cx = new fluent__WEBPACK_IMPORTED_MODULE_0__["MessageContext"]("en-US");
+  RICH_TEXT_KEYS.forEach(key => {
+    const attrs = RICH_TEXT_CONFIG[key];
+    const attrsToTry = Array.isArray(attrs) ? [...attrs] : [attrs];
+    let string = "";
+
+    while (!string && attrsToTry.length) {
+      const attr = attrsToTry.pop();
+      string = content[attr];
+    }
+
+    cx.addMessages(`${key} = ${string}`);
+  });
+  return [cx];
+}
 
 /***/ }),
-/* 28 */
+/* 10 */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VISIBLE", function() { return VISIBLE; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VISIBILITY_CHANGE_EVENT", function() { return VISIBILITY_CHANGE_EVENT; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ImpressionsWrapper", function() { return ImpressionsWrapper; });
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(11);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
+
+const VISIBLE = "visible";
+const VISIBILITY_CHANGE_EVENT = "visibilitychange";
+/**
+ * Component wrapper used to send telemetry pings on every impression.
+ */
+
+class ImpressionsWrapper extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComponent {
+  // This sends an event when a user sees a set of new content. If content
+  // changes while the page is hidden (i.e. preloaded or on a hidden tab),
+  // only send the event if the page becomes visible again.
+  sendImpressionOrAddListener() {
+    if (this.props.document.visibilityState === VISIBLE) {
+      this.props.sendImpression({
+        id: this.props.id
+      });
+    } else {
+      // We should only ever send the latest impression stats ping, so remove any
+      // older listeners.
+      if (this._onVisibilityChange) {
+        this.props.document.removeEventListener(VISIBILITY_CHANGE_EVENT, this._onVisibilityChange);
+      } // When the page becomes visible, send the impression stats ping if the section isn't collapsed.
+
+
+      this._onVisibilityChange = () => {
+        if (this.props.document.visibilityState === VISIBLE) {
+          this.props.sendImpression({
+            id: this.props.id
+          });
+          this.props.document.removeEventListener(VISIBILITY_CHANGE_EVENT, this._onVisibilityChange);
+        }
+      };
+
+      this.props.document.addEventListener(VISIBILITY_CHANGE_EVENT, this._onVisibilityChange);
+    }
+  }
+
+  componentWillUnmount() {
+    if (this._onVisibilityChange) {
+      this.props.document.removeEventListener(VISIBILITY_CHANGE_EVENT, this._onVisibilityChange);
+    }
+  }
+
+  componentDidMount() {
+    if (this.props.sendOnMount) {
+      this.sendImpressionOrAddListener();
+    }
+  }
+
+  componentDidUpdate(prevProps) {
+    if (this.props.shouldSendImpressionOnUpdate(this.props, prevProps)) {
+      this.sendImpressionOrAddListener();
+    }
+  }
+
+  render() {
+    return this.props.children;
+  }
+
+}
+ImpressionsWrapper.defaultProps = {
+  document: global.document,
+  sendOnMount: true
+};
+/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
+
+/***/ }),
+/* 11 */
+/***/ (function(module, exports) {
+
+module.exports = React;
+
+/***/ }),
+/* 12 */
+/***/ (function(module, exports) {
+
+module.exports = PropTypes;
+
+/***/ }),
+/* 13 */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "IS_NEWTAB", function() { return IS_NEWTAB; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NEWTAB_DARK_THEME", function() { return NEWTAB_DARK_THEME; });
+const IS_NEWTAB = global.document && global.document.documentURI === "about:newtab";
+const NEWTAB_DARK_THEME = {
+  "ntp_background": {
+    "r": 42,
+    "g": 42,
+    "b": 46,
+    "a": 1
+  },
+  "ntp_text": {
+    "r": 249,
+    "g": 249,
+    "b": 250,
+    "a": 1
+  },
+  "sidebar": {
+    "r": 56,
+    "g": 56,
+    "b": 61,
+    "a": 1
+  },
+  "sidebar_text": {
+    "r": 249,
+    "g": 249,
+    "b": 250,
+    "a": 1
+  }
+};
+/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
+
+/***/ }),
+/* 14 */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OnboardingMessage", function() { return OnboardingMessage; });
+/* harmony import */ var _components_ModalOverlay_ModalOverlay__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(15);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
+function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
+
+
+
+
+class OnboardingCard extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureComponent {
+  constructor(props) {
+    super(props);
+    this.onClick = this.onClick.bind(this);
+  }
+
+  onClick() {
+    const {
+      props
+    } = this;
+    const ping = {
+      event: "CLICK_BUTTON",
+      message_id: props.id,
+      id: props.UISurface
+    };
+    props.sendUserActionTelemetry(ping);
+    props.onAction(props.content.primary_button.action);
+  }
+
+  render() {
+    const {
+      content
+    } = this.props;
+    return react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("div", {
+      className: "onboardingMessage"
+    }, react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("div", {
+      className: `onboardingMessageImage ${content.icon}`
+    }), react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("div", {
+      className: "onboardingContent"
+    }, react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("span", null, react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("h3", null, " ", content.title, " "), react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("p", null, " ", content.text, " ")), react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("span", null, react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("button", {
+      tabIndex: "1",
+      className: "button onboardingButton",
+      onClick: this.onClick
+    }, " ", content.primary_button.label, " "))));
+  }
+
+}
+
+class OnboardingMessage extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureComponent {
+  render() {
+    const {
+      props
+    } = this;
+    const {
+      button_label,
+      header
+    } = props.extraTemplateStrings;
+    return react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(_components_ModalOverlay_ModalOverlay__WEBPACK_IMPORTED_MODULE_0__["ModalOverlay"], _extends({}, props, {
+      button_label: button_label,
+      title: header
+    }), react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("div", {
+      className: "onboardingMessageContainer"
+    }, props.bundle.map(message => react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(OnboardingCard, _extends({
+      key: message.id,
+      sendUserActionTelemetry: props.sendUserActionTelemetry,
+      onAction: props.onAction,
+      UISurface: props.UISurface
+    }, message)))));
+  }
+
+}
+
+/***/ }),
+/* 15 */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ModalOverlay", function() { return ModalOverlay; });
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(11);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
+
+class ModalOverlay extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComponent {
+  componentWillMount() {
+    this.setState({
+      active: true
+    });
+    document.body.classList.add("modal-open");
+  }
+
+  componentWillUnmount() {
+    document.body.classList.remove("modal-open");
+    this.setState({
+      active: false
+    });
+  }
+
+  render() {
+    const {
+      active
+    } = this.state;
+    const {
+      title,
+      button_label
+    } = this.props;
+    return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+      className: `modalOverlayOuter ${active ? "active" : ""}`
+    }), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+      className: `modalOverlayInner ${active ? "active" : ""}`
+    }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("h2", null, " ", title, " "), this.props.children, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+      className: "footer"
+    }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("button", {
+      tabIndex: "2",
+      onClick: this.props.onDoneButton,
+      className: "button primary modalButton"
+    }, " ", button_label, " "))));
+  }
+
+}
+
+/***/ }),
+/* 16 */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ReturnToAMO", function() { return ReturnToAMO; });
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(11);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
+/* harmony import */ var _components_RichText_RichText__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(17);
+
+
+class ReturnToAMO extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComponent {
+  constructor(props) {
+    super(props);
+    this.onClickAddExtension = this.onClickAddExtension.bind(this);
+    this.onBlockButton = this.onBlockButton.bind(this);
+  }
+
+  componentDidMount() {
+    this.props.onReady();
+  }
+
+  onClickAddExtension() {
+    this.props.onAction(this.props.content.primary_button.action);
+  }
+
+  onBlockButton() {
+    this.props.onBlock();
+    document.body.classList.remove("welcome", "hide-main", "amo");
+  }
+
+  renderText() {
+    const customElement = react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("img", {
+      src: this.props.content.addon_icon,
+      width: "20px",
+      height: "20px"
+    });
+    return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_components_RichText_RichText__WEBPACK_IMPORTED_MODULE_1__["RichText"], {
+      customElements: {
+        icon: customElement
+      },
+      amo_html: this.props.content.text,
+      localization_id: "amo_html"
+    });
+  }
+
+  render() {
+    const {
+      content
+    } = this.props;
+    return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+      className: "ReturnToAMOOverlay"
+    }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("h2", null, " ", content.header, " "), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+      className: "ReturnToAMOContainer"
+    }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+      className: "ReturnToAMOAddonContents"
+    }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("p", null, " ", content.title, " "), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+      className: "ReturnToAMOText"
+    }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("span", null, " ", this.renderText(), " ")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("button", {
+      onClick: this.onClickAddExtension,
+      className: "puffy blue ReturnToAMOAddExtension"
+    }, " ", react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("span", {
+      className: "icon icon-add"
+    }), " ", content.primary_button.label, " ")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+      className: "ReturnToAMOIcon"
+    })), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("button", {
+      onClick: this.onBlockButton,
+      className: "default grey ReturnToAMOGetStarted"
+    }, " ", content.secondary_button.label, " ")));
+  }
+
+}
+
+/***/ }),
+/* 17 */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "convertLinks", function() { return convertLinks; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RichText", function() { return RichText; });
+/* harmony import */ var fluent_react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(55);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
+/* harmony import */ var _rich_text_strings__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(9);
+/* harmony import */ var _template_utils__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(18);
+function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
+
+
+
+
+ // Elements allowed in snippet content
+
+const ALLOWED_TAGS = {
+  b: react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("b", null),
+  i: react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("i", null),
+  u: react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("u", null),
+  strong: react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("strong", null),
+  em: react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("em", null),
+  br: react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("br", null)
+};
+/**
+ * Transform an object (tag name: {url}) into (tag name: anchor) where the url
+ * is used as href, in order to render links inside a Fluent.Localized component.
+ */
+
+function convertLinks(links, sendClick, doNotAutoBlock, openNewWindow = false) {
+  if (links) {
+    return Object.keys(links).reduce((acc, linkTag) => {
+      const {
+        action
+      } = links[linkTag]; // Setting the value to false will not include the attribute in the anchor
+
+      const url = action ? false : Object(_template_utils__WEBPACK_IMPORTED_MODULE_3__["safeURI"])(links[linkTag].url);
+      acc[linkTag] = react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("a", {
+        href: url,
+        target: openNewWindow ? "_blank" : "",
+        "data-metric": links[linkTag].metric,
+        "data-action": action,
+        "data-args": links[linkTag].args,
+        "data-do_not_autoblock": doNotAutoBlock,
+        onClick: sendClick
+      });
+      return acc;
+    }, {});
+  }
+
+  return null;
+}
+/**
+ * Message wrapper used to sanitize markup and render HTML.
+ */
+
+function RichText(props) {
+  if (!_rich_text_strings__WEBPACK_IMPORTED_MODULE_2__["RICH_TEXT_KEYS"].includes(props.localization_id)) {
+    throw new Error(`ASRouter: ${props.localization_id} is not a valid rich text property. If you want it to be processed, you need to add it to asrouter/rich-text-strings.js`);
+  }
+
+  return react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(fluent_react__WEBPACK_IMPORTED_MODULE_0__["Localized"], _extends({
+    id: props.localization_id
+  }, ALLOWED_TAGS, props.customElements, convertLinks(props.links, props.sendClick, props.doNotAutoBlock, props.openNewWindow)), react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("span", null, props.text));
+}
+
+/***/ }),
+/* 18 */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "safeURI", function() { return safeURI; });
+function safeURI(url) {
+  if (!url) {
+    return "";
+  }
+
+  const {
+    protocol
+  } = new URL(url);
+  const isAllowed = ["http:", "https:", "data:", "resource:", "chrome:"].includes(protocol);
+
+  if (!isAllowed) {
+    console.warn(`The protocol ${protocol} is not allowed for template URLs.`); // eslint-disable-line no-console
+  }
+
+  return isAllowed ? url : "";
+}
+
+/***/ }),
+/* 19 */
+/***/ (function(module) {
+
+module.exports = {"title":"EOYSnippet","description":"Fundraising Snippet","version":"1.0.0","type":"object","definitions":{"plainText":{"description":"Plain text (no HTML allowed)","type":"string"},"richText":{"description":"Text with HTML subset allowed: i, b, u, strong, em, br","type":"string"},"link_url":{"description":"Target for links or buttons","type":"string","format":"uri"}},"properties":{"donation_form_url":{"type":"string","description":"Url to the donation form."},"currency_code":{"type":"string","description":"The code for the currency. Examle gbp, cad, usd.","default":"usd"},"locale":{"type":"string","description":"String for the locale code.","default":"en-US"},"text":{"allOf":[{"$ref":"#/definitions/richText"},{"description":"Main body text of snippet. HTML subset allowed: i, b, u, strong, em, br"}]},"text_color":{"type":"string","description":"Modify the text message color"},"background_color":{"type":"string","description":"Snippet background color."},"highlight_color":{"type":"string","description":"Paragraph em highlight color."},"donation_amount_first":{"type":"number","description":"First button amount."},"donation_amount_second":{"type":"number","description":"Second button amount."},"donation_amount_third":{"type":"number","description":"Third button amount."},"donation_amount_fourth":{"type":"number","description":"Fourth button amount."},"selected_button":{"type":"string","description":"Default donation_amount_second. Donation amount button that's selected by default.","default":"donation_amount_second"},"icon":{"type":"string","description":"Snippet icon. 64x64px. SVG or PNG preferred."},"title":{"allOf":[{"$ref":"#/definitions/plainText"},{"description":"Snippet title displayed before snippet text"}]},"title_icon":{"type":"string","description":"Small icon that shows up before the title / text. 16x16px. SVG or PNG preferred. Grayscale."},"button_label":{"allOf":[{"$ref":"#/definitions/plainText"},{"description":"Text for a button next to main snippet text that links to button_url. Requires button_url."}]},"button_color":{"type":"string","description":"The text color of the button. Valid CSS color."},"button_background_color":{"type":"string","description":"The background color of the button. Valid CSS color."},"block_button_text":{"type":"string","description":"Tooltip text used for dismiss button."},"monthly_checkbox_label_text":{"type":"string","description":"Label text for monthly checkbox.","default":"Make my donation monthly"},"test":{"type":"string","description":"Different styles for the snippet. Options are bold and takeover."},"do_not_autoblock":{"type":"boolean","description":"Used to prevent blocking the snippet after the CTA (link or button) has been clicked"},"links":{"additionalProperties":{"url":{"allOf":[{"$ref":"#/definitions/link_url"},{"description":"The url where the link points to."}]},"metric":{"type":"string","description":"Custom event name sent with telemetry event."},"args":{"type":"string","description":"Additional parameters for link action, example which specific menu the button should open"}}}},"additionalProperties":false,"required":["text","donation_form_url","donation_amount_first","donation_amount_second","donation_amount_third","donation_amount_fourth","button_label","currency_code"],"dependencies":{"button_color":["button_label"],"button_background_color":["button_label"]}};
+
+/***/ }),
+/* 20 */
+/***/ (function(module) {
+
+module.exports = {"title":"SimpleSnippet","description":"A simple template with an icon, text, and optional button.","version":"1.1.1","type":"object","definitions":{"plainText":{"description":"Plain text (no HTML allowed)","type":"string"},"richText":{"description":"Text with HTML subset allowed: i, b, u, strong, em, br","type":"string"},"link_url":{"description":"Target for links or buttons","type":"string","format":"uri"}},"properties":{"title":{"allOf":[{"$ref":"#/definitions/plainText"},{"description":"Snippet title displayed before snippet text"}]},"text":{"allOf":[{"$ref":"#/definitions/richText"},{"description":"Main body text of snippet. HTML subset allowed: i, b, u, strong, em, br"}]},"icon":{"type":"string","description":"Snippet icon. 64x64px. SVG or PNG preferred."},"title_icon":{"type":"string","description":"Small icon that shows up before the title / text. 16x16px. SVG or PNG preferred. Grayscale."},"button_action":{"type":"string","description":"The type of action the button should trigger."},"button_url":{"allOf":[{"$ref":"#/definitions/link_url"},{"description":"A url, button_label links to this"}]},"button_action_args":{"type":"string","description":"Additional parameters for button action, example which specific menu the button should open"},"button_label":{"allOf":[{"$ref":"#/definitions/plainText"},{"description":"Text for a button next to main snippet text that links to button_url. Requires button_url."}]},"button_color":{"type":"string","description":"The text color of the button. Valid CSS color."},"button_background_color":{"type":"string","description":"The background color of the button. Valid CSS color."},"block_button_text":{"type":"string","description":"Tooltip text used for dismiss button.","default":"Remove this"},"tall":{"type":"boolean","description":"To be used by fundraising only, increases height to roughly 120px. Defaults to false."},"do_not_autoblock":{"type":"boolean","description":"Used to prevent blocking the snippet after the CTA (link or button) has been clicked"},"links":{"additionalProperties":{"url":{"allOf":[{"$ref":"#/definitions/link_url"},{"description":"The url where the link points to."}]},"metric":{"type":"string","description":"Custom event name sent with telemetry event."},"args":{"type":"string","description":"Additional parameters for link action, example which specific menu the button should open"}}},"section_title_icon":{"type":"string","description":"Section title icon. 16x16px. SVG or PNG preferred. section_title_text must also be specified to display."},"section_title_text":{"type":"string","description":"Section title text. section_title_icon must also be specified to display."},"section_title_url":{"allOf":[{"$ref":"#/definitions/link_url"},{"description":"A url, section_title_text links to this"}]}},"additionalProperties":false,"required":["text"],"dependencies":{"button_action":["button_label"],"button_url":["button_label"],"button_color":["button_label"],"button_background_color":["button_label"],"section_title_url":["section_title_text"]}};
+
+/***/ }),
+/* 21 */
+/***/ (function(module) {
+
+module.exports = {"title":"FXASignupSnippet","description":"A snippet template for FxA sign up/sign in","version":"1.0.0","type":"object","definitions":{"plainText":{"description":"Plain text (no HTML allowed)","type":"string"},"richText":{"description":"Text with HTML subset allowed: i, b, u, strong, em, br","type":"string"},"link_url":{"description":"Target for links or buttons","type":"string","format":"uri"}},"properties":{"scene1_title":{"allof":[{"$ref":"#/definitions/plainText"},{"description":"snippet title displayed before snippet text"}]},"scene1_text":{"allOf":[{"$ref":"#/definitions/richText"},{"description":"Main body text of snippet. HTML subset allowed: i, b, u, strong, em, br"}]},"scene2_title":{"allOf":[{"$ref":"#/definitions/plainText"},{"description":"Title displayed before text in scene 2. Should be plain text."}]},"scene2_text":{"allOf":[{"$ref":"#/definitions/richText"},{"description":"Main body text of snippet. HTML subset allowed: i, b, u, strong, em, br"}]},"scene1_icon":{"type":"string","description":"Snippet icon. 64x64px. SVG or PNG preferred."},"scene1_title_icon":{"type":"string","description":"Small icon that shows up before the title / text. 16x16px. SVG or PNG preferred. Grayscale."},"scene2_email_placeholder_text":{"type":"string","description":"Value to show while input is empty.","default":"Your email here"},"scene2_button_label":{"type":"string","description":"Label for form submit button","default":"Sign me up"},"scene2_dismiss_button_text":{"type":"string","description":"Label for the dismiss button when the sign-up form is expanded.","default":"Dismiss"},"hidden_inputs":{"type":"object","description":"Each entry represents a hidden input, key is used as value for the name property.","properties":{"action":{"type":"string","enum":["email"]},"context":{"type":"string","enum":["fx_desktop_v3"]},"entrypoint":{"type":"string","enum":["snippets"]},"service":{"type":"string","enum":["sync"]},"utm_content":{"type":"number","description":"Firefox version number"},"utm_source":{"type":"string","enum":["snippet"]},"utm_campaign":{"type":"string","description":"(fxa) Value to pass through to GA as utm_campaign."},"utm_term":{"type":"string","description":"(fxa) Value to pass through to GA as utm_term."},"additionalProperties":false}},"scene1_button_label":{"allOf":[{"$ref":"#/definitions/plainText"},{"description":"Text for a button next to main snippet text that links to button_url. Requires button_url."}],"default":"Learn more"},"scene1_button_color":{"type":"string","description":"The text color of the button. Valid CSS color."},"scene1_button_background_color":{"type":"string","description":"The background color of the button. Valid CSS color."},"do_not_autoblock":{"type":"boolean","description":"Used to prevent blocking the snippet after the CTA (link or button) has been clicked","default":false},"utm_campaign":{"type":"string","description":"(fxa) Value to pass through to GA as utm_campaign."},"utm_term":{"type":"string","description":"(fxa) Value to pass through to GA as utm_term."},"links":{"additionalProperties":{"url":{"allOf":[{"$ref":"#/definitions/link_url"},{"description":"The url where the link points to."}]},"metric":{"type":"string","description":"Custom event name sent with telemetry event."}}}},"additionalProperties":false,"required":["scene1_text","scene2_text","scene1_button_label"],"dependencies":{"scene1_button_color":["scene1_button_label"],"scene1_button_background_color":["scene1_button_label"]}};
+
+/***/ }),
+/* 22 */
+/***/ (function(module) {
+
+module.exports = {"title":"NewsletterSnippet","description":"A snippet template for send to device mobile download","version":"1.0.0","type":"object","definitions":{"plainText":{"description":"Plain text (no HTML allowed)","type":"string"},"richText":{"description":"Text with HTML subset allowed: i, b, u, strong, em, br","type":"string"},"link_url":{"description":"Target for links or buttons","type":"string","format":"uri"}},"properties":{"locale":{"type":"string","description":"Two to five character string for the locale code","default":"en-US"},"scene1_title":{"allof":[{"$ref":"#/definitions/plainText"},{"description":"snippet title displayed before snippet text"}]},"scene1_text":{"allOf":[{"$ref":"#/definitions/richText"},{"description":"Main body text of snippet. HTML subset allowed: i, b, u, strong, em, br"}]},"scene2_title":{"allOf":[{"$ref":"#/definitions/plainText"},{"description":"Title displayed before text in scene 2. Should be plain text."}]},"scene2_text":{"allOf":[{"$ref":"#/definitions/richText"},{"description":"Main body text of snippet. HTML subset allowed: i, b, u, strong, em, br"}]},"scene1_icon":{"type":"string","description":"Snippet icon. 64x64px. SVG or PNG preferred."},"scene1_title_icon":{"type":"string","description":"Small icon that shows up before the title / text. 16x16px. SVG or PNG preferred. Grayscale."},"scene2_email_placeholder_text":{"type":"string","description":"Value to show while input is empty.","default":"Your email here"},"scene2_button_label":{"type":"string","description":"Label for form submit button","default":"Sign me up"},"scene2_privacy_html":{"type":"string","description":"(send to device) Html for disclaimer and link underneath input box."},"scene2_dismiss_button_text":{"type":"string","description":"Label for the dismiss button when the sign-up form is expanded.","default":"Dismiss"},"hidden_inputs":{"type":"object","description":"Each entry represents a hidden input, key is used as value for the name property.","properties":{"fmt":{"type":"string","description":"","default":"H"}}},"scene1_button_label":{"allOf":[{"$ref":"#/definitions/plainText"},{"description":"Text for a button next to main snippet text that links to button_url. Requires button_url."}],"default":"Learn more"},"scene1_button_color":{"type":"string","description":"The text color of the button. Valid CSS color."},"scene1_button_background_color":{"type":"string","description":"The background color of the button. Valid CSS color."},"do_not_autoblock":{"type":"boolean","description":"Used to prevent blocking the snippet after the CTA (link or button) has been clicked","default":false},"success_text":{"type":"string","description":"Message shown on successful registration."},"error_text":{"type":"string","description":"Message shown if registration failed."},"scene2_newsletter":{"type":"string","description":"Newsletter/basket id user is subscribing to.","default":"mozilla-foundation"},"links":{"additionalProperties":{"url":{"allOf":[{"$ref":"#/definitions/link_url"},{"description":"The url where the link points to."}]},"metric":{"type":"string","description":"Custom event name sent with telemetry event."}}}},"additionalProperties":false,"required":["scene1_text","scene2_text","scene1_button_label"],"dependencies":{"scene1_button_color":["scene1_button_label"],"scene1_button_background_color":["scene1_button_label"]}};
+
+/***/ }),
+/* 23 */
+/***/ (function(module) {
+
+module.exports = {"title":"SendToDeviceSnippet","description":"A snippet template for send to device mobile download","version":"1.0.0","type":"object","definitions":{"plainText":{"description":"Plain text (no HTML allowed)","type":"string"},"richText":{"description":"Text with HTML subset allowed: i, b, u, strong, em, br","type":"string"},"link_url":{"description":"Target for links or buttons","type":"string","format":"uri"}},"properties":{"locale":{"type":"string","description":"Two to five character string for the locale code","default":"en-US"},"country":{"type":"string","description":"Two character string for the country code (used for SMS)","default":"us"},"scene1_title":{"allof":[{"$ref":"#/definitions/plainText"},{"description":"snippet title displayed before snippet text"}]},"scene1_text":{"allOf":[{"$ref":"#/definitions/richText"},{"description":"Main body text of snippet. HTML subset allowed: i, b, u, strong, em, br"}]},"scene2_title":{"allOf":[{"$ref":"#/definitions/plainText"},{"description":"Title displayed before text in scene 2. Should be plain text."}]},"scene2_text":{"allOf":[{"$ref":"#/definitions/richText"},{"description":"Main body text of snippet. HTML subset allowed: i, b, u, strong, em, br"}]},"scene1_icon":{"type":"string","description":"Snippet icon. 64x64px. SVG or PNG preferred."},"scene2_icon":{"type":"string","description":"(send to device) Image to display above the form. 98x98px. SVG or PNG preferred."},"scene1_title_icon":{"type":"string","description":"Small icon that shows up before the title / text. 16x16px. SVG or PNG preferred. Grayscale."},"scene2_button_label":{"type":"string","description":"Label for form submit button","default":"Send"},"scene2_input_placeholder":{"type":"string","description":"(send to device) Value to show while input is empty.","default":"Your email here"},"scene2_disclaimer_html":{"type":"string","description":"(send to device) Html for disclaimer and link underneath input box."},"scene2_dismiss_button_text":{"type":"string","description":"Label for the dismiss button when the sign-up form is expanded.","default":"Dismiss"},"hidden_inputs":{"type":"object","description":"Each entry represents a hidden input, key is used as value for the name property.","properties":{"action":{"type":"string","enum":["email"]},"context":{"type":"string","enum":["fx_desktop_v3"]},"entrypoint":{"type":"string","enum":["snippets"]},"service":{"type":"string","enum":["sync"]},"utm_content":{"type":"string","description":"Firefox version number"},"utm_source":{"type":"string","enum":["snippet"]},"utm_campaign":{"type":"string","description":"(fxa) Value to pass through to GA as utm_campaign."},"utm_term":{"type":"string","description":"(fxa) Value to pass through to GA as utm_term."},"additionalProperties":false}},"scene1_button_label":{"allOf":[{"$ref":"#/definitions/plainText"},{"description":"Text for a button next to main snippet text that links to button_url. Requires button_url."}],"default":"Learn more"},"scene1_button_color":{"type":"string","description":"The text color of the button. Valid CSS color."},"scene1_button_background_color":{"type":"string","description":"The background color of the button. Valid CSS color."},"do_not_autoblock":{"type":"boolean","description":"Used to prevent blocking the snippet after the CTA (link or button) has been clicked","default":false},"success_title":{"type":"string","description":"(send to device) Title shown before text on successful registration."},"success_text":{"type":"string","description":"Message shown on successful registration."},"error_text":{"type":"string","description":"Message shown if registration failed."},"include_sms":{"type":"boolean","description":"(send to device) Allow users to send an SMS message with the form?","default":false},"message_id_sms":{"type":"string","description":"(send to device) Newsletter/basket id representing the SMS message to be sent."},"message_id_email":{"type":"string","description":"(send to device) Newsletter/basket id representing the email message to be sent. Must be a value from the 'Slug' column here: https://basket.mozilla.org/news/."},"utm_campaign":{"type":"string","description":"(fxa) Value to pass through to GA as utm_campaign."},"utm_term":{"type":"string","description":"(fxa) Value to pass through to GA as utm_term."},"links":{"additionalProperties":{"url":{"allOf":[{"$ref":"#/definitions/link_url"},{"description":"The url where the link points to."}]},"metric":{"type":"string","description":"Custom event name sent with telemetry event."}}}},"additionalProperties":false,"required":["scene1_text","scene2_text","scene1_button_label"],"dependencies":{"scene1_button_color":["scene1_button_label"],"scene1_button_background_color":["scene1_button_label"]}};
+
+/***/ }),
+/* 24 */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_StartupOverlay", function() { return _StartupOverlay; });
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "StartupOverlay", function() { return StartupOverlay; });
+/* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
+/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4);
+/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__);
+/* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(25);
+/* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(react_redux__WEBPACK_IMPORTED_MODULE_2__);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(11);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_3__);
+
+
+
+
+class _StartupOverlay extends react__WEBPACK_IMPORTED_MODULE_3___default.a.PureComponent {
+  constructor(props) {
+    super(props);
+    this.onInputChange = this.onInputChange.bind(this);
+    this.onSubmit = this.onSubmit.bind(this);
+    this.clickSkip = this.clickSkip.bind(this);
+    this.initScene = this.initScene.bind(this);
+    this.removeOverlay = this.removeOverlay.bind(this);
+    this.onInputInvalid = this.onInputInvalid.bind(this);
+    this.state = {
+      emailInput: "",
+      overlayRemoved: false,
+      flowId: "",
+      flowBeginTime: 0
+    };
+    this.didFetch = false;
+  }
+
+  async componentWillUpdate() {
+    if (this.props.fxa_endpoint && !this.didFetch) {
+      try {
+        this.didFetch = true;
+        const fxaParams = "entrypoint=activity-stream-firstrun&utm_source=activity-stream&utm_campaign=firstrun&form_type=email";
+        const response = await fetch(`${this.props.fxa_endpoint}/metrics-flow?${fxaParams}`, {
+          credentials: "omit"
+        });
+
+        if (response.status === 200) {
+          const {
+            flowId,
+            flowBeginTime
+          } = await response.json();
+          this.setState({
+            flowId,
+            flowBeginTime
+          });
+        } else {
+          this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
+            type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].TELEMETRY_UNDESIRED_EVENT,
+            data: {
+              event: "FXA_METRICS_FETCH_ERROR",
+              value: response.status
+            }
+          }));
+        }
+      } catch (error) {
+        this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
+          type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].TELEMETRY_UNDESIRED_EVENT,
+          data: {
+            event: "FXA_METRICS_ERROR"
+          }
+        }));
+      }
+    }
+  }
+
+  componentDidMount() {
+    this.initScene();
+  }
+
+  initScene() {
+    // Timeout to allow the scene to render once before attaching the attribute
+    // to trigger the animation.
+    setTimeout(() => {
+      this.setState({
+        show: true
+      });
+      this.props.onReady();
+    }, 10);
+  }
+
+  removeOverlay() {
+    window.removeEventListener("visibilitychange", this.removeOverlay);
+    document.body.classList.remove("hide-main", "fxa");
+    this.setState({
+      show: false
+    });
+    this.props.onBlock();
+    setTimeout(() => {
+      // Allow scrolling and fully remove overlay after animation finishes.
+      document.body.classList.remove("welcome");
+      this.setState({
+        overlayRemoved: true
+      });
+    }, 400);
+  }
+
+  onInputChange(e) {
+    let error = e.target.previousSibling;
+    this.setState({
+      emailInput: e.target.value
+    });
+    error.classList.remove("active");
+    e.target.classList.remove("invalid");
+  }
+
+  onSubmit() {
+    this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].UserEvent({
+      event: "SUBMIT_EMAIL",
+      ...this._getFormInfo()
+    }));
+    window.addEventListener("visibilitychange", this.removeOverlay);
+  }
+
+  clickSkip() {
+    this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].UserEvent({
+      event: "SKIPPED_SIGNIN",
+      ...this._getFormInfo()
+    }));
+    this.removeOverlay();
+  }
+  /**
+   * Report to telemetry additional information about the form submission.
+   */
+
+
+  _getFormInfo() {
+    const value = {
+      has_flow_params: this.state.flowId.length > 0
+    };
+    return {
+      value
+    };
+  }
+
+  onInputInvalid(e) {
+    let error = e.target.previousSibling;
+    error.classList.add("active");
+    e.target.classList.add("invalid");
+    e.preventDefault(); // Override built-in form validation popup
+
+    e.target.focus();
+  }
+
+  render() {
+    // When skipping the onboarding tour we show AS but we are still on
+    // about:welcome, prop.isFirstrun is true and StartupOverlay is rendered
+    if (this.state.overlayRemoved) {
+      return null;
+    }
+
+    let termsLink = react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("a", {
+      href: `${this.props.fxa_endpoint}/legal/terms`,
+      target: "_blank",
+      rel: "noopener noreferrer"
+    }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
+      id: "firstrun_terms_of_service"
+    }));
+    let privacyLink = react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("a", {
+      href: `${this.props.fxa_endpoint}/legal/privacy`,
+      target: "_blank",
+      rel: "noopener noreferrer"
+    }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
+      id: "firstrun_privacy_notice"
+    }));
+    return react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", {
+      className: `overlay-wrapper ${this.state.show ? "show" : ""}`
+    }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", {
+      className: "background"
+    }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", {
+      className: "firstrun-scene"
+    }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", {
+      className: "fxaccounts-container"
+    }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", {
+      className: "firstrun-left-divider"
+    }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("h1", {
+      className: "firstrun-title"
+    }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
+      id: "firstrun_title"
+    })), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("p", {
+      className: "firstrun-content"
+    }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
+      id: "firstrun_content"
+    })), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("a", {
+      className: "firstrun-link",
+      href: "https://www.mozilla.org/firefox/features/sync/",
+      target: "_blank",
+      rel: "noopener noreferrer"
+    }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
+      id: "firstrun_learn_more_link"
+    }))), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", {
+      className: "firstrun-sign-in"
+    }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("p", {
+      className: "form-header"
+    }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
+      id: "firstrun_form_header"
+    }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("span", {
+      className: "sub-header"
+    }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
+      id: "firstrun_form_sub_header"
+    }))), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("form", {
+      method: "get",
+      action: this.props.fxa_endpoint,
+      target: "_blank",
+      rel: "noopener noreferrer",
+      onSubmit: this.onSubmit
+    }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", {
+      name: "service",
+      type: "hidden",
+      value: "sync"
+    }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", {
+      name: "action",
+      type: "hidden",
+      value: "email"
+    }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", {
+      name: "context",
+      type: "hidden",
+      value: "fx_desktop_v3"
+    }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", {
+      name: "entrypoint",
+      type: "hidden",
+      value: "activity-stream-firstrun"
+    }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", {
+      name: "utm_source",
+      type: "hidden",
+      value: "activity-stream"
+    }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", {
+      name: "utm_campaign",
+      type: "hidden",
+      value: "firstrun"
+    }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", {
+      name: "flow_id",
+      type: "hidden",
+      value: this.state.flowId
+    }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", {
+      name: "flow_begin_time",
+      type: "hidden",
+      value: this.state.flowBeginTime
+    }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("span", {
+      className: "error"
+    }, this.props.intl.formatMessage({
+      id: "firstrun_invalid_input"
+    })), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", {
+      className: "email-input",
+      name: "email",
+      type: "email",
+      required: "true",
+      onInvalid: this.onInputInvalid,
+      placeholder: this.props.intl.formatMessage({
+        id: "firstrun_email_input_placeholder"
+      }),
+      onChange: this.onInputChange
+    }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", {
+      className: "extra-links"
+    }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
+      id: "firstrun_extra_legal_links",
+      values: {
+        terms: termsLink,
+        privacy: privacyLink
+      }
+    })), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("button", {
+      className: "continue-button",
+      type: "submit"
+    }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
+      id: "firstrun_continue_to_login"
+    }))), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("button", {
+      className: "skip-button",
+      disabled: !!this.state.emailInput,
+      onClick: this.clickSkip
+    }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
+      id: "firstrun_skip_login"
+    }))))));
+  }
+
+}
+
+const getState = state => ({
+  fxa_endpoint: state.Prefs.values.fxa_endpoint
+});
+
+const StartupOverlay = Object(react_redux__WEBPACK_IMPORTED_MODULE_2__["connect"])(getState)(Object(react_intl__WEBPACK_IMPORTED_MODULE_1__["injectIntl"])(_StartupOverlay));
+
+/***/ }),
+/* 25 */
+/***/ (function(module, exports) {
+
+module.exports = ReactRedux;
+
+/***/ }),
+/* 26 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SimpleHashRouter", function() { return SimpleHashRouter; });
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(10);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(11);
 /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
 
 class SimpleHashRouter extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComponent {
   constructor(props) {
     super(props);
     this.onHashChange = this.onHashChange.bind(this);
     this.state = {
       hash: global.location.hash
@@ -3619,42 +3158,42 @@ class SimpleHashRouter extends react__WE
     global.addEventListener("hashchange", this.onHashChange);
   }
 
   componentWillUnmount() {
     global.removeEventListener("hashchange", this.onHashChange);
   }
 
   render() {
-    const [, ...routes] = this.state.hash.replace("#asrouter", "").split("-");
+    const [, ...routes] = this.state.hash.split("-");
     return react__WEBPACK_IMPORTED_MODULE_0___default.a.cloneElement(this.props.children, {
       location: {
         hash: this.state.hash,
         routes
       }
     });
   }
 
 }
 /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
 
 /***/ }),
-/* 29 */
+/* 27 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_ConfirmDialog", function() { return _ConfirmDialog; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConfirmDialog", function() { return ConfirmDialog; });
 /* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
 /* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(25);
 /* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_redux__WEBPACK_IMPORTED_MODULE_1__);
-/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(5);
+/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(4);
 /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_2__);
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(10);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(11);
 /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_3__);
 
 
 
 
 /**
  * ConfirmDialog component.
  * One primary action button, one cancel button.
@@ -3739,31 +3278,37 @@ class _ConfirmDialog extends react__WEBP
       id: this.props.data.confirm_button_string_id
     })))));
   }
 
 }
 const ConfirmDialog = Object(react_redux__WEBPACK_IMPORTED_MODULE_1__["connect"])(state => state.Dialog)(_ConfirmDialog);
 
 /***/ }),
-/* 30 */
+/* 28 */
+/***/ (function(module, exports) {
+
+module.exports = ReactDOM;
+
+/***/ }),
+/* 29 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_LinkMenu", function() { return _LinkMenu; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LinkMenu", function() { return LinkMenu; });
 /* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
 /* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(25);
 /* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_redux__WEBPACK_IMPORTED_MODULE_1__);
-/* harmony import */ var content_src_components_ContextMenu_ContextMenu__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(31);
-/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(5);
+/* harmony import */ var content_src_components_ContextMenu_ContextMenu__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(30);
+/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(4);
 /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_3__);
-/* harmony import */ var content_src_lib_link_menu_options__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(32);
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(10);
+/* harmony import */ var content_src_lib_link_menu_options__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(31);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(11);
 /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_5__);
 
 
 
 
 
 
 const DEFAULT_SITE_MENU_OPTIONS = ["CheckPinTopSite", "EditTopSite", "Separator", "OpenInNewWindow", "OpenInPrivateWindow", "Separator", "BlockUrl"];
@@ -3838,24 +3383,24 @@ class _LinkMenu extends react__WEBPACK_I
 const getState = state => ({
   isPrivateBrowsingEnabled: state.Prefs.values.isPrivateBrowsingEnabled,
   platform: state.Prefs.values.platform
 });
 
 const LinkMenu = Object(react_redux__WEBPACK_IMPORTED_MODULE_1__["connect"])(getState)(Object(react_intl__WEBPACK_IMPORTED_MODULE_3__["injectIntl"])(_LinkMenu));
 
 /***/ }),
-/* 31 */
+/* 30 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ContextMenu", function() { return ContextMenu; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ContextMenuItem", function() { return ContextMenuItem; });
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(10);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(11);
 /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
 
 class ContextMenu extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComponent {
   constructor(props) {
     super(props);
     this.hideContext = this.hideContext.bind(this);
     this.onShow = this.onShow.bind(this);
     this.onClick = this.onClick.bind(this);
@@ -3958,17 +3503,17 @@ class ContextMenuItem extends react__WEB
       className: `icon icon-spacer icon-${option.icon}`
     }), option.label));
   }
 
 }
 /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
 
 /***/ }),
-/* 32 */
+/* 31 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GetPlatformString", function() { return GetPlatformString; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LinkMenuOptions", function() { return LinkMenuOptions; });
 /* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
 
@@ -4251,25 +3796,25 @@ const LinkMenuOptions = {
   CheckBookmark: site => site.bookmarkGuid ? LinkMenuOptions.RemoveBookmark(site) : LinkMenuOptions.AddBookmark(site),
   CheckPinTopSite: (site, index) => site.isPinned ? LinkMenuOptions.UnpinTopSite(site) : LinkMenuOptions.PinTopSite(site, index),
   CheckSavedToPocket: (site, index) => site.pocket_id ? LinkMenuOptions.DeleteFromPocket(site) : LinkMenuOptions.SaveToPocket(site, index),
   CheckBookmarkOrArchive: site => site.pocket_id ? LinkMenuOptions.ArchiveFromPocket(site) : LinkMenuOptions.CheckBookmark(site),
   OpenInPrivateWindow: (site, index, eventSource, isEnabled) => isEnabled ? _OpenInPrivateWindow(site) : LinkMenuOptions.EmptyItem()
 };
 
 /***/ }),
-/* 33 */
+/* 32 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "INTERSECTION_RATIO", function() { return INTERSECTION_RATIO; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ImpressionStats", function() { return ImpressionStats; });
 /* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(10);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11);
 /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
 
 
 const VISIBLE = "visible";
 const VISIBILITY_CHANGE_EVENT = "visibilitychange"; // Per analytical requirement, we set the minimal intersection ratio to
 // 0.5, and an impression is identified when the wrapped item has at least
 // 50% visibility.
 //
@@ -4472,31 +4017,31 @@ ImpressionStats.defaultProps = {
   IntersectionObserver: global.IntersectionObserver,
   document: global.document,
   rows: [],
   source: ""
 };
 /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
 
 /***/ }),
-/* 34 */
+/* 33 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_CollapsibleSection", function() { return _CollapsibleSection; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CollapsibleSection", function() { return CollapsibleSection; });
-/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5);
+/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4);
 /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
-/* harmony import */ var content_src_components_ErrorBoundary_ErrorBoundary__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(35);
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(10);
+/* harmony import */ var content_src_components_ErrorBoundary_ErrorBoundary__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(34);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(11);
 /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_3__);
-/* harmony import */ var content_src_components_SectionMenu_SectionMenu__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(36);
-/* harmony import */ var content_src_lib_section_menu_options__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(37);
+/* harmony import */ var content_src_components_SectionMenu_SectionMenu__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(35);
+/* harmony import */ var content_src_lib_section_menu_options__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(36);
 
 
 
 
 
 
 const VISIBLE = "visible";
 const VISIBILITY_CHANGE_EVENT = "visibilitychange";
@@ -4768,26 +4313,26 @@ class _CollapsibleSection extends react_
   Prefs: {
     values: {}
   }
 };
 const CollapsibleSection = Object(react_intl__WEBPACK_IMPORTED_MODULE_0__["injectIntl"])(_CollapsibleSection);
 /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
 
 /***/ }),
-/* 35 */
+/* 34 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ErrorBoundaryFallback", function() { return ErrorBoundaryFallback; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ErrorBoundary", function() { return ErrorBoundary; });
-/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5);
+/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4);
 /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_0__);
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(10);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11);
 /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
 
 
 class ErrorBoundaryFallback extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureComponent {
   constructor(props) {
     super(props);
     this.windowObj = this.props.windowObj || window;
     this.onClick = this.onClick.bind(this);
@@ -4857,30 +4402,30 @@ class ErrorBoundary extends react__WEBPA
   }
 
 }
 ErrorBoundary.defaultProps = {
   FallbackComponent: ErrorBoundaryFallback
 };
 
 /***/ }),
-/* 36 */
+/* 35 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_SectionMenu", function() { return _SectionMenu; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SectionMenu", function() { return SectionMenu; });
 /* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
-/* harmony import */ var content_src_components_ContextMenu_ContextMenu__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(31);
-/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(5);
+/* harmony import */ var content_src_components_ContextMenu_ContextMenu__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(30);
+/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(4);
 /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_2__);
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(10);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(11);
 /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_3__);
-/* harmony import */ var content_src_lib_section_menu_options__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(37);
+/* harmony import */ var content_src_lib_section_menu_options__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(36);
 
 
 
 
 
 const DEFAULT_SECTION_MENU_OPTIONS = ["MoveUp", "MoveDown", "Separator", "RemoveSection", "CheckCollapsed", "Separator", "ManageSection"];
 const WEBEXT_SECTION_MENU_OPTIONS = ["MoveUp", "MoveDown", "Separator", "CheckCollapsed", "Separator", "ManageWebExtension"];
 class _SectionMenu extends react__WEBPACK_IMPORTED_MODULE_3___default.a.PureComponent {
@@ -4945,17 +4490,17 @@ class _SectionMenu extends react__WEBPAC
       options: this.getOptions()
     });
   }
 
 }
 const SectionMenu = Object(react_intl__WEBPACK_IMPORTED_MODULE_2__["injectIntl"])(_SectionMenu);
 
 /***/ }),
-/* 37 */
+/* 36 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SectionMenuOptions", function() { return SectionMenuOptions; });
 /* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
 
 /**
@@ -5072,37 +4617,37 @@ const SectionMenuOptions = {
       }
     }),
     userEvent: "MENU_PRIVACY_NOTICE"
   }),
   CheckCollapsed: section => section.collapsed ? SectionMenuOptions.ExpandSection(section) : SectionMenuOptions.CollapseSection(section)
 };
 
 /***/ }),
-/* 38 */
+/* 37 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_TopSites", function() { return _TopSites; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TopSites", function() { return TopSites; });
 /* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
-/* harmony import */ var _TopSitesConstants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(39);
-/* harmony import */ var content_src_components_CollapsibleSection_CollapsibleSection__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(34);
-/* harmony import */ var content_src_components_ComponentPerfTimer_ComponentPerfTimer__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(40);
+/* harmony import */ var _TopSitesConstants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(38);
+/* harmony import */ var content_src_components_CollapsibleSection_CollapsibleSection__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(33);
+/* harmony import */ var content_src_components_ComponentPerfTimer_ComponentPerfTimer__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(39);
 /* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(25);
 /* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(react_redux__WEBPACK_IMPORTED_MODULE_4__);
-/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(5);
+/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(4);
 /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_5__);
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(10);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(11);
 /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_6__);
-/* harmony import */ var _SearchShortcutsForm__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(42);
-/* harmony import */ var common_Reducers_jsm__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(58);
-/* harmony import */ var _TopSiteForm__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(60);
-/* harmony import */ var _TopSite__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(43);
+/* harmony import */ var _SearchShortcutsForm__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(41);
+/* harmony import */ var common_Reducers_jsm__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(56);
+/* harmony import */ var _TopSiteForm__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(58);
+/* harmony import */ var _TopSite__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(42);
 function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
 
 
 
 
 
 
 
@@ -5300,17 +4845,17 @@ class _TopSites extends react__WEBPACK_I
 const TopSites = Object(react_redux__WEBPACK_IMPORTED_MODULE_4__["connect"])(state => ({
   TopSites: state.TopSites,
   Prefs: state.Prefs,
   TopSitesRows: state.Prefs.values.topSitesRows
 }))(Object(react_intl__WEBPACK_IMPORTED_MODULE_5__["injectIntl"])(_TopSites));
 /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
 
 /***/ }),
-/* 39 */
+/* 38 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TOP_SITES_SOURCE", function() { return TOP_SITES_SOURCE; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TOP_SITES_CONTEXT_MENU_OPTIONS", function() { return TOP_SITES_CONTEXT_MENU_OPTIONS; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TOP_SITES_SEARCH_SHORTCUTS_CONTEXT_MENU_OPTIONS", function() { return TOP_SITES_SEARCH_SHORTCUTS_CONTEXT_MENU_OPTIONS; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MIN_RICH_FAVICON_SIZE", function() { return MIN_RICH_FAVICON_SIZE; });
@@ -5320,25 +4865,25 @@ const TOP_SITES_CONTEXT_MENU_OPTIONS = [
 
 const TOP_SITES_SEARCH_SHORTCUTS_CONTEXT_MENU_OPTIONS = ["CheckPinTopSite", "Separator", "BlockUrl"]; // minimum size necessary to show a rich icon instead of a screenshot
 
 const MIN_RICH_FAVICON_SIZE = 96; // minimum size necessary to show any icon in the top left corner with a screenshot
 
 const MIN_CORNER_FAVICON_SIZE = 16;
 
 /***/ }),
-/* 40 */
+/* 39 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ComponentPerfTimer", function() { return ComponentPerfTimer; });
 /* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
-/* harmony import */ var common_PerfService_jsm__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(41);
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(10);
+/* harmony import */ var common_PerfService_jsm__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(40);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(11);
 /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_2__);
 
 
  // Currently record only a fixed set of sections. This will prevent data
 // from custom sections from showing up or from topstories.
 
 const RECORDED_SECTIONS = ["highlights", "topsites"];
 class ComponentPerfTimer extends react__WEBPACK_IMPORTED_MODULE_2___default.a.Component {
@@ -5497,17 +5042,17 @@ class ComponentPerfTimer extends react__
     }
 
     return this.props.children;
   }
 
 }
 
 /***/ }),
-/* 41 */
+/* 40 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_PerfService", function() { return _PerfService; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "perfService", function() { return perfService; });
 
 
@@ -5635,29 +5180,29 @@ function _PerfService(options) {
     let mostRecentEntry = entries[entries.length - 1];
     return this._perf.timeOrigin + mostRecentEntry.startTime;
   }
 
 };
 var perfService = new _PerfService();
 
 /***/ }),
-/* 42 */
+/* 41 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SelectableSearchShortcut", function() { return SelectableSearchShortcut; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SearchShortcutsForm", function() { return SearchShortcutsForm; });
 /* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
-/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5);
+/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4);
 /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__);
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(10);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(11);
 /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_2__);
-/* harmony import */ var _TopSitesConstants__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(39);
+/* harmony import */ var _TopSitesConstants__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(38);
 
 
 
 
 class SelectableSearchShortcut extends react__WEBPACK_IMPORTED_MODULE_2___default.a.PureComponent {
   render() {
     const {
       shortcut,
@@ -5829,35 +5374,35 @@ class SearchShortcutsForm extends react_
     }, react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
       id: "topsites_form_save_button"
     }))));
   }
 
 }
 
 /***/ }),
-/* 43 */
+/* 42 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TopSiteLink", function() { return TopSiteLink; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TopSite", function() { return TopSite; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TopSitePlaceholder", function() { return TopSitePlaceholder; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_TopSiteList", function() { return _TopSiteList; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TopSiteList", function() { return TopSiteList; });
 /* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
-/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5);
+/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4);
 /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__);
-/* harmony import */ var _TopSitesConstants__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(39);
-/* harmony import */ var content_src_components_LinkMenu_LinkMenu__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(30);
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(10);
+/* harmony import */ var _TopSitesConstants__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(38);
+/* harmony import */ var content_src_components_LinkMenu_LinkMenu__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(29);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(11);
 /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_4__);
-/* harmony import */ var content_src_lib_screenshot_utils__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(44);
-/* harmony import */ var common_Reducers_jsm__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(58);
+/* harmony import */ var content_src_lib_screenshot_utils__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(43);
+/* harmony import */ var common_Reducers_jsm__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(56);
 function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
 
 
 
 
 
 
 
@@ -6487,17 +6032,17 @@ class _TopSiteList extends react__WEBPAC
       className: `top-sites-list${this.state.draggedSite ? " dnd-active" : ""}`
     }, topSitesUI);
   }
 
 }
 const TopSiteList = Object(react_intl__WEBPACK_IMPORTED_MODULE_1__["injectIntl"])(_TopSiteList);
 
 /***/ }),
-/* 44 */
+/* 43 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ScreenshotUtils", function() { return ScreenshotUtils; });
 /**
  * List of helper functions for screenshot-based images.
  *
@@ -6552,29 +6097,29 @@ const ScreenshotUtils = {
 
     return !remoteImage && !localImage;
   }
 
 };
 /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
 
 /***/ }),
-/* 45 */
+/* 44 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_ManualMigration", function() { return _ManualMigration; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ManualMigration", function() { return ManualMigration; });
 /* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
 /* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(25);
 /* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_redux__WEBPACK_IMPORTED_MODULE_1__);
-/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(5);
+/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(4);
 /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_2__);
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(10);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(11);
 /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_3__);
 
 
 
 
 /**
  * Manual migration component used to start the profile import wizard.
  * Message is presented temporarily and will go away if:
@@ -6629,17 +6174,17 @@ class _ManualMigration extends react__WE
       id: "manual_migration_import_button"
     }))));
   }
 
 }
 const ManualMigration = Object(react_redux__WEBPACK_IMPORTED_MODULE_1__["connect"])()(_ManualMigration);
 
 /***/ }),
-/* 46 */
+/* 45 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_PrerenderData", function() { return _PrerenderData; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PrerenderData", function() { return PrerenderData; });
 class _PrerenderData {
   constructor(options) {
@@ -6768,30 +6313,30 @@ var PrerenderData = new _PrerenderData({
     order: 2,
     title: {
       id: "header_highlights"
     }
   }]
 });
 
 /***/ }),
-/* 47 */
+/* 46 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_Search", function() { return _Search; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Search", function() { return Search; });
 /* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
-/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5);
+/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4);
 /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(25);
 /* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(react_redux__WEBPACK_IMPORTED_MODULE_2__);
-/* harmony import */ var content_src_lib_constants__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(12);
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(10);
+/* harmony import */ var content_src_lib_constants__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(13);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(11);
 /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_4__);
 /* globals ContentSearchUIController */
 
 
 
 
 
 
@@ -6976,39 +6521,39 @@ class _Search extends react__WEBPACK_IMP
       ref: this.onInputMount
     })));
   }
 
 }
 const Search = Object(react_redux__WEBPACK_IMPORTED_MODULE_2__["connect"])()(Object(react_intl__WEBPACK_IMPORTED_MODULE_1__["injectIntl"])(_Search));
 
 /***/ }),
-/* 48 */
+/* 47 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Section", function() { return Section; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SectionIntl", function() { return SectionIntl; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_Sections", function() { return _Sections; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Sections", function() { return Sections; });
 /* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
-/* harmony import */ var content_src_components_Card_Card__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(59);
-/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(5);
+/* harmony import */ var content_src_components_Card_Card__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(57);
+/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(4);
 /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_2__);
-/* harmony import */ var content_src_components_CollapsibleSection_CollapsibleSection__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(34);
-/* harmony import */ var content_src_components_ComponentPerfTimer_ComponentPerfTimer__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(40);
+/* harmony import */ var content_src_components_CollapsibleSection_CollapsibleSection__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(33);
+/* harmony import */ var content_src_components_ComponentPerfTimer_ComponentPerfTimer__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(39);
 /* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(25);
 /* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(react_redux__WEBPACK_IMPORTED_MODULE_5__);
-/* harmony import */ var content_src_components_MoreRecommendations_MoreRecommendations__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(49);
-/* harmony import */ var content_src_components_PocketLoggedInCta_PocketLoggedInCta__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(50);
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(10);
+/* harmony import */ var content_src_components_MoreRecommendations_MoreRecommendations__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(48);
+/* harmony import */ var content_src_components_PocketLoggedInCta_PocketLoggedInCta__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(49);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(11);
 /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_8___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_8__);
-/* harmony import */ var content_src_components_Topics_Topics__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(51);
-/* harmony import */ var content_src_components_TopSites_TopSites__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(38);
+/* harmony import */ var content_src_components_Topics_Topics__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(50);
+/* harmony import */ var content_src_components_TopSites_TopSites__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(37);
 function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
 
 
 
 
 
 
 
@@ -7347,25 +6892,25 @@ class _Sections extends react__WEBPACK_I
 }
 const Sections = Object(react_redux__WEBPACK_IMPORTED_MODULE_5__["connect"])(state => ({
   Sections: state.Sections,
   Prefs: state.Prefs
 }))(_Sections);
 /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
 
 /***/ }),
-/* 49 */
+/* 48 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MoreRecommendations", function() { return MoreRecommendations; });
-/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5);
+/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4);
 /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_0__);
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(10);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11);
 /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
 
 
 class MoreRecommendations extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureComponent {
   render() {
     const {
       read_more_endpoint
     } = this.props;
@@ -7380,28 +6925,28 @@ class MoreRecommendations extends react_
     }
 
     return null;
   }
 
 }
 
 /***/ }),
-/* 50 */
+/* 49 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_PocketLoggedInCta", function() { return _PocketLoggedInCta; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PocketLoggedInCta", function() { return PocketLoggedInCta; });
 /* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25);
 /* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_redux__WEBPACK_IMPORTED_MODULE_0__);
-/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5);
+/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4);
 /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__);
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(10);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(11);
 /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_2__);
 
 
 
 class _PocketLoggedInCta extends react__WEBPACK_IMPORTED_MODULE_2___default.a.PureComponent {
   render() {
     const {
       pocketCta
@@ -7423,26 +6968,26 @@ class _PocketLoggedInCta extends react__
   }
 
 }
 const PocketLoggedInCta = Object(react_redux__WEBPACK_IMPORTED_MODULE_0__["connect"])(state => ({
   Pocket: state.Pocket
 }))(_PocketLoggedInCta);
 
 /***/ }),
-/* 51 */
+/* 50 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Topic", function() { return Topic; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Topics", function() { return Topics; });
-/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5);
+/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4);
 /* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_0__);
-/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(10);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11);
 /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
 
 
 class Topic extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureComponent {
   render() {
     const {
       url,
       name
@@ -7468,24 +7013,24 @@ class Topics extends react__WEBPACK_IMPO
       url: t.url,
       name: t.name
     }))));
   }
 
 }
 
 /***/ }),
-/* 52 */
+/* 51 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DetectUserSessionStart", function() { return DetectUserSessionStart; });
 /* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
-/* harmony import */ var common_PerfService_jsm__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(41);
+/* harmony import */ var common_PerfService_jsm__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(40);
 
 
 const VISIBLE = "visible";
 const VISIBILITY_CHANGE_EVENT = "visibilitychange";
 class DetectUserSessionStart {
   constructor(store, options = {}) {
     this._store = store; // Overrides for testing
 
@@ -7547,124 +7092,70 @@ class DetectUserSessionStart {
       this.document.removeEventListener(VISIBILITY_CHANGE_EVENT, this._onVisibilityChange);
     }
   }
 
 }
 /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
 
 /***/ }),
-/* 53 */
-/***/ (function(module, __webpack_exports__, __webpack_require__) {
-
-"use strict";
-__webpack_require__.r(__webpack_exports__);
-/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "enableASRouterContent", function() { return enableASRouterContent; });
-function enableASRouterContent(store, asrouterContent) {
-  // Enable asrouter content
-  store.subscribe(() => {
-    const state = store.getState();
-
-    if (!state.ASRouter.initialized) {
-      return;
-    }
-
-    if (!asrouterContent.initialized) {
-      asrouterContent.init(store);
-    }
-  }); // Return this for testing purposes
-
-  return {
-    asrouterContent
-  };
-}
-
-/***/ }),
-/* 54 */
+/* 52 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 
 // EXTERNAL MODULE: ./common/Actions.jsm
 var Actions = __webpack_require__(2);
 
-// CONCATENATED MODULE: ./content-src/components/DiscoveryStreamComponents/DSImage/cache.js
-// This cache is for tracking queued image source requests from DSImage instances and leveraging
-//  larger sizes of images to scale down in the browser instead of making additional
-//  requests for smaller sizes from the server.
-let cache = {
-  query(url, size, set) {
-    // Create an empty set if none exists
-    // Need multiple cache sets because the browser decides what set to use based on pixel density
-    if (this.queuedImages[set] === undefined) {
-      this.queuedImages[set] = {};
-    }
-
-    let sizeToRequest; // The px width to request from Thumbor via query value
-
-    if (!this.queuedImages[set][url] || this.queuedImages[set][url] < size) {
-      this.queuedImages[set][url] = size;
-      sizeToRequest = size;
-    } else {
-      // Use the larger size already queued for download (and allow browser to scale down)
-      sizeToRequest = this.queuedImages[set][url];
-    }
-
-    return sizeToRequest;
-  },
-
-  queuedImages: {}
-};
-
 // EXTERNAL MODULE: external "React"
-var external_React_ = __webpack_require__(10);
+var external_React_ = __webpack_require__(11);
 var external_React_default = /*#__PURE__*/__webpack_require__.n(external_React_);
 
 // EXTERNAL MODULE: external "ReactDOM"
-var external_ReactDOM_ = __webpack_require__(15);
+var external_ReactDOM_ = __webpack_require__(28);
 var external_ReactDOM_default = /*#__PURE__*/__webpack_require__.n(external_ReactDOM_);
 
 // CONCATENATED MODULE: ./content-src/components/DiscoveryStreamComponents/DSImage/DSImage.jsx
 
 
-
 class DSImage_DSImage extends external_React_default.a.PureComponent {
   constructor(props) {
     super(props);
     this.onOptimizedImageError = this.onOptimizedImageError.bind(this);
     this.state = {
       isSeen: false,
       optimizedImageFailed: false
     };
   }
 
   onSeen(entries) {
     if (this.state) {
       if (entries.some(entry => entry.isIntersecting)) {
         if (this.props.optimize) {
           this.setState({
-            containerWidth: external_ReactDOM_default.a.findDOMNode(this).clientWidth
+            containerWidth: external_ReactDOM_default.a.findDOMNode(this).clientWidth,
+            containerHeight: external_ReactDOM_default.a.findDOMNode(this).clientHeight
           });
         }
 
         this.setState({
           isSeen: true
         }); // Stop observing since element has been seen
 
         this.observer.unobserve(external_ReactDOM_default.a.findDOMNode(this));
       }
     }
   }
 
-  reformatImageURL(url, width) {
+  reformatImageURL(url, width, height) {
     // Change the image URL to request a size tailored for the parent container width
     // Also: force JPEG, quality 60, no upscaling, no EXIF data
     // Uses Thumbor: https://thumbor.readthedocs.io/en/latest/usage.html
-    return `https://img-getpocket.cdn.mozilla.net/${width}x0/filters:format(jpeg):quality(60):no_upscale():strip_exif()/${encodeURIComponent(url)}`;
+    return `https://img-getpocket.cdn.mozilla.net/${width}x${height}/filters:format(jpeg):quality(60):no_upscale():strip_exif()/${encodeURIComponent(url)}`;
   }
 
   componentDidMount() {
     this.observer = new IntersectionObserver(this.onSeen.bind(this));
     this.observer.observe(external_ReactDOM_default.a.findDOMNode(this));
   }
 
   componentWillUnmount() {
@@ -7680,18 +7171,18 @@ class DSImage_DSImage extends external_R
 
     if (this.state && this.state.isSeen) {
       if (this.props.optimize && this.props.rawSource && !this.state.optimizedImageFailed) {
         let source;
         let source2x;
 
         if (this.state && this.state.containerWidth) {
           let baseSource = this.props.rawSource;
-          source = this.reformatImageURL(baseSource, cache.query(baseSource, this.state.containerWidth, `1x`));
-          source2x = this.reformatImageURL(baseSource, cache.query(baseSource, this.state.containerWidth * 2, `2x`));
+          source = this.reformatImageURL(baseSource, this.state.containerWidth, this.state.containerHeight);
+          source2x = this.reformatImageURL(baseSource, this.state.containerWidth * 2, this.state.containerHeight * 2);
           img = external_React_default.a.createElement("img", {
             onError: this.onOptimizedImageError,
             src: source,
             srcSet: `${source2x} 2x`
           });
         }
       } else {
         img = external_React_default.a.createElement("img", {
@@ -7719,20 +7210,20 @@ DSImage_DSImage.defaultProps = {
   rawSource: null,
   // Unadulterated image URL to filter through Thumbor
   extraClassNames: null,
   // Additional classnames to append to component
   optimize: true // Measure parent container to request exact sizes
 
 };
 // EXTERNAL MODULE: external "ReactIntl"
-var external_ReactIntl_ = __webpack_require__(5);
+var external_ReactIntl_ = __webpack_require__(4);
 
 // EXTERNAL MODULE: ./content-src/components/LinkMenu/LinkMenu.jsx
-var LinkMenu = __webpack_require__(30);
+var LinkMenu = __webpack_require__(29);
 
 // CONCATENATED MODULE: ./content-src/components/DiscoveryStreamComponents/DSLinkMenu/DSLinkMenu.jsx
 
 
 
 class DSLinkMenu_DSLinkMenu extends external_React_default.a.PureComponent {
   constructor(props) {
     super(props);
@@ -7816,17 +7307,17 @@ class DSLinkMenu_DSLinkMenu extends exte
         bookmarkGuid: this.props.bookmarkGuid
       }
     }));
   }
 
 }
 const DSLinkMenu = Object(external_ReactIntl_["injectIntl"])(DSLinkMenu_DSLinkMenu);
 // EXTERNAL MODULE: ./content-src/components/DiscoveryStreamImpressionStats/ImpressionStats.jsx
-var ImpressionStats = __webpack_require__(33);
+var ImpressionStats = __webpack_require__(32);
 
 // CONCATENATED MODULE: ./content-src/components/DiscoveryStreamComponents/SafeAnchor/SafeAnchor.jsx
 
 
 class SafeAnchor_SafeAnchor extends external_React_default.a.PureComponent {
   constructor(props) {
     super(props);
     this.onClick = this.onClick.bind(this);
@@ -8059,17 +7550,17 @@ class CardGrid_CardGrid extends external
 
 }
 CardGrid_CardGrid.defaultProps = {
   border: `border`,
   items: 4 // Number of stories to display
 
 };
 // EXTERNAL MODULE: ./content-src/components/CollapsibleSection/CollapsibleSection.jsx
-var CollapsibleSection = __webpack_require__(34);
+var CollapsibleSection = __webpack_require__(33);
 
 // EXTERNAL MODULE: external "ReactRedux"
 var external_ReactRedux_ = __webpack_require__(25);
 
 // CONCATENATED MODULE: ./content-src/components/DiscoveryStreamComponents/DSMessage/DSMessage.jsx
 
 
 class DSMessage_DSMessage extends external_React_default.a.PureComponent {
@@ -8288,16 +7779,17 @@ class Hero_Hero extends external_React_d
     const cards = [];
 
     for (let index = 0; index < this.props.items - 1; index++) {
       const rec = otherRecs[index];
       cards.push(rec ? external_React_default.a.createElement(DSCard_DSCard, {
         campaignId: rec.campaign_id,
         key: `dscard-${index}`,
         image_src: rec.image_src,
+        raw_image_src: rec.raw_image_src,
         title: rec.title,
         url: rec.url,
         id: rec.id,
         pos: rec.pos,
         type: this.props.type,
         dispatch: this.props.dispatch,
         context: rec.context,
         source: rec.domain,
@@ -8551,17 +8043,17 @@ const selectLayoutRender = (state, prefs
 
       return { ...component,
         data
       };
     })
   })).filter(row => row.components.length);
 };
 // EXTERNAL MODULE: ./content-src/components/TopSites/TopSites.jsx
-var TopSites = __webpack_require__(38);
+var TopSites = __webpack_require__(37);
 
 // CONCATENATED MODULE: ./content-src/components/DiscoveryStreamComponents/TopSites/TopSites.jsx
 
 
 
 class TopSites_TopSites extends external_React_default.a.PureComponent {
   render() {
     const header = this.props.header || {};
@@ -8847,24 +8339,24 @@ class DiscoveryStreamBase_DiscoveryStrea
 }
 const DiscoveryStreamBase = Object(external_ReactRedux_["connect"])(state => ({
   DiscoveryStream: state.DiscoveryStream,
   Prefs: state.Prefs,
   Sections: state.Sections
 }))(DiscoveryStreamBase_DiscoveryStreamBase);
 
 /***/ }),
-/* 55 */
+/* 53 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 
 // EXTERNAL MODULE: external "React"
-var external_React_ = __webpack_require__(10);
+var external_React_ = __webpack_require__(11);
 var external_React_default = /*#__PURE__*/__webpack_require__.n(external_React_);
 
 // EXTERNAL MODULE: ./content-src/asrouter/templates/EOYSnippet/EOYSnippet.schema.json
 var EOYSnippet_schema = __webpack_require__(19);
 
 // CONCATENATED MODULE: ./content-src/asrouter/components/Button/Button.jsx
 
 const ALLOWED_STYLE_TAGS = ["color", "backgroundColor"];
@@ -9818,17 +9310,17 @@ const SnippetsTemplates = {
   newsletter_snippet: NewsletterSnippet,
   fxa_signup_snippet: FXASignupSnippet,
   send_to_device_snippet: SendToDeviceSnippet,
   eoy_snippet: EOYSnippet,
   simple_below_search_snippet: SimpleBelowSearchSnippet_SimpleBelowSearchSnippet
 };
 
 /***/ }),
-/* 56 */
+/* 54 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 
 // CONCATENATED MODULE: ./node_modules/fluent/src/parser.js
 /*  eslint no-magic-numbers: [0]  */
 const MAX_PLACEABLES = 100;
@@ -12021,31 +11513,31 @@ function ftl(strings) {
 
 
 
 
 
 
 
 /***/ }),
-/* 57 */
+/* 55 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 
 // EXTERNAL MODULE: external "React"
-var external_React_ = __webpack_require__(10);
+var external_React_ = __webpack_require__(11);
 
 // EXTERNAL MODULE: external "PropTypes"
-var external_PropTypes_ = __webpack_require__(11);
+var external_PropTypes_ = __webpack_require__(12);
 var external_PropTypes_default = /*#__PURE__*/__webpack_require__.n(external_PropTypes_);
 
 // EXTERNAL MODULE: ./node_modules/fluent/src/index.js + 8 modules
-var src = __webpack_require__(56);
+var src = __webpack_require__(54);
 
 // CONCATENATED MODULE: ./node_modules/fluent-react/src/localization.js
 
 /*
  * `ReactLocalization` handles translation formatting and fallback.
  *
  * The current negotiated fallback chain of languages is stored in the
  * `ReactLocalization` instance in form of an iterable of `MessageContext`
@@ -12549,17 +12041,17 @@ localized_Localized.propTypes = {
  * components for more information.
  */
 
 
 
 
 
 /***/ }),
-/* 58 */
+/* 56 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 
 // EXTERNAL MODULE: ./common/Actions.jsm
 var Actions = __webpack_require__(2);
 
@@ -13271,17 +12763,17 @@ function DiscoveryStream(prevState = INI
           data: action.data || prevState.feeds.data,
           loaded: true
         }
       };
 
     case Actions["actionTypes"].DISCOVERY_STREAM_SPOCS_CAPS:
       return { ...prevState,
         spocs: { ...prevState.spocs,
-          frequency_caps: action.data
+          frequency_caps: [...prevState.spocs.frequency_caps, ...action.data]
         }
       };
 
     case Actions["actionTypes"].DISCOVERY_STREAM_SPOCS_ENDPOINT:
       return { ...prevState,
         spocs: { ...INITIAL_STATE.DiscoveryStream.spocs,
           spocs_endpoint: action.data || INITIAL_STATE.DiscoveryStream.spocs.spocs_endpoint
         }
@@ -13393,27 +12885,27 @@ var reducers = {
   Dialog,
   Sections,
   Pocket,
   DiscoveryStream,
   Search
 };
 
 /***/ }),
-/* 59 */
+/* 57 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 
 // EXTERNAL MODULE: ./common/Actions.jsm
 var Actions = __webpack_require__(2);
 
 // EXTERNAL MODULE: external "ReactIntl"
-var external_ReactIntl_ = __webpack_require__(5);
+var external_ReactIntl_ = __webpack_require__(4);
 
 // CONCATENATED MODULE: ./content-src/components/Card/types.js
 const cardContextTypes = {
   history: {
     intlID: "type_label_visited",
     icon: "history-item"
   },
   bookmark: {
@@ -13436,27 +12928,27 @@ const cardContextTypes = {
     intlID: "type_label_downloaded",
     icon: "download"
   }
 };
 // EXTERNAL MODULE: external "ReactRedux"
 var external_ReactRedux_ = __webpack_require__(25);
 
 // EXTERNAL MODULE: ./content-src/lib/link-menu-options.js
-var link_menu_options = __webpack_require__(32);
+var link_menu_options = __webpack_require__(31);
 
 // EXTERNAL MODULE: ./content-src/components/LinkMenu/LinkMenu.jsx
-var LinkMenu = __webpack_require__(30);
+var LinkMenu = __webpack_require__(29);
 
 // EXTERNAL MODULE: external "React"
-var external_React_ = __webpack_require__(10);
+var external_React_ = __webpack_require__(11);
 var external_React_default = /*#__PURE__*/__webpack_require__.n(external_React_);
 
 // EXTERNAL MODULE: ./content-src/lib/screenshot-utils.js
-var screenshot_utils = __webpack_require__(44);
+var screenshot_utils = __webpack_require__(43);
 
 // CONCATENATED MODULE: ./content-src/components/Card/Card.jsx
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_Card", function() { return Card_Card; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Card", function() { return Card; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PlaceholderCard", function() { return PlaceholderCard; });
 
 
 
@@ -13785,34 +13277,34 @@ const Card = Object(external_ReactRedux_
   platform: state.Prefs.values.platform
 }))(Object(external_ReactIntl_["injectIntl"])(Card_Card));
 const PlaceholderCard = props => external_React_default.a.createElement(Card, {
   placeholder: true,
   className: props.className
 });
 
 /***/ }),
-/* 60 */
+/* 58 */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 
 // EXTERNAL MODULE: ./common/Actions.jsm
 var Actions = __webpack_require__(2);
 
 // EXTERNAL MODULE: external "ReactIntl"
-var external_ReactIntl_ = __webpack_require__(5);
+var external_ReactIntl_ = __webpack_require__(4);
 
 // EXTERNAL MODULE: external "React"
-var external_React_ = __webpack_require__(10);
+var external_React_ = __webpack_require__(11);
 var external_React_default = /*#__PURE__*/__webpack_require__.n(external_React_);
 
 // EXTERNAL MODULE: ./content-src/components/TopSites/TopSitesConstants.js
-var TopSitesConstants = __webpack_require__(39);
+var TopSitesConstants = __webpack_require__(38);
 
 // CONCATENATED MODULE: ./content-src/components/TopSites/TopSiteFormInput.jsx
 
 
 class TopSiteFormInput_TopSiteFormInput extends external_React_default.a.PureComponent {
   constructor(props) {
     super(props);
     this.state = {
@@ -13893,17 +13385,17 @@ class TopSiteFormInput_TopSiteFormInput 
 
 }
 TopSiteFormInput_TopSiteFormInput.defaultProps = {
   showClearButton: false,
   value: "",
   validationError: false
 };
 // EXTERNAL MODULE: ./content-src/components/TopSites/TopSite.jsx
-var TopSite = __webpack_require__(43);
+var TopSite = __webpack_require__(42);
 
 // CONCATENATED MODULE: ./content-src/components/TopSites/TopSiteForm.jsx
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TopSiteForm", function() { return TopSiteForm_TopSiteForm; });
 
 
 
 
 
deleted file mode 100644
--- a/browser/components/newtab/docs/v2-system-addon/snippets.md
+++ /dev/null
@@ -1,125 +0,0 @@
-# Snippets in ActivityStream
-
-## `gSnippetsMap`
-
-`gSnippetsMap` is available to all snippet templates and has methods that a
-regular `Map` has: `set`, `get`, `delete`, `clear`, etc.
-
-If you don't care about the completion of the transaction, you may simply use these
-methods synchronously:
-
-```js
-function setFoo() {
-  gSnippetsMap.set("foo", 123);
-  return gSnippetsMap.get("foo"); // returns 123
-}
-```
-
-However, unlike the previous version of snippets, `set`, `delete`, and `clear`
-all return a `Promise` that will resolve or reject when the `indexedDB` transaction
-is complete. For example:
-
-```js
-async function setFoo() {
-  await gSnippetsMap.set("foo", 123);
-  return gSnippetsMap.get("foo");
-}
-```
-
-### Methods on gSnippetsMap
-
-`.blockList`: (Array) An array of snippet IDs that have been blocked by the users, or an empty array if none have been blocked.
-
-`.blockSnippetById(id)`: (func) A function that adds an id to a blockList and returns
-a Promise that resolves when the blockList has been written to indexedDB.
-
-`.showFirefoxAccounts()`: (func) A function that opens the Firefox Accounts signup page
-(specifically `about:accounts?action=signup&entrypoint=snippets`)
-
-`.disableOnboarding()`: (func) DEPRECATED - A function that disables onboarding for future new tabs (until Firefox restarts).
-You should ensure `gSnippetsMap.get("appData.onboardingFinished")` is false before calling this. Note that this
-does not hide onboarding notifications on the **current** page, since that would be a disruptive user experience.
-
-`.getTotalBookmarksCount()`: (func) An async function that resolves with an integer representing the number of
-bookmarks a user has (including default bookmarks). Note that is value is only updated once per day or when a
-a user restarts the browser.
-
-`.getAddonsInfo()`:( func) An async function that resolves with an object `{isFullData: (bool), addons: (obj)}`.
-Note that at startup, we are sometimes unable to provide full data due to performance constraints (`.isFullData` will be `false`).
-E.g.
-
-```js
-{
-  isFullData: true,
-  addons: {
-      // This is the ID of the addon
-    "someaddon@mozilla.org": {
-      type: "extension",
-      isSystem: false,
-      isWebExtension: true,
-      version: "29.0.0"
-
-      // The following properties may not be available when the browser starts up
-      name: "Firefox Screenshots",
-      userDisabled: false,
-      installDate: Date 2018-02-27T19:33:33.440Z,
-    }
-  }
-}
-```
-
-### Expected values in gSnippetsMap
-
-Note that names and functionality of values in v4 snippets have been preserved
-where possible. You can access each value by calling `gSnippetsMap.get(id)`. For example,
-to find out if a user has a Firefox account, you would check `gSnippetsMap.get("appData.fxaccount")`.
-
-`snippets-cached-version`: (int) The version number of the snippets cached in `snippets`.
-
-`snippets-last-update`: (int) The last time snippets were updated.
-
-`snippets`: (str) The cached payload of the response from the snippets server.
-
-`appData.snippetsURL`: (str) The URL at from which snippets are fetched
-
-`appData.version`: (int) The current version of snippets
-
-`appData.profileCreatedWeeksAgo`: (int) The date the user's profile was created
-
-`appData.profileResetWeeksAgo`: (int) The date the user's profile was reset. `null` if the profile hasn't been reset.
-
-`appData.telemetryEnabled`: (bool) Is telemetry enabled for the user?
-
-`appData.onboardingFinished`: (bool) DEPRECATED - Has the onboarding tour been completed?
-
-`appData.fxaccount`: (bool) Does the user have a Firefox account?
-
-`appData.selectedSearchEngine`: (obj) An object containing a array of search
-engines and a search engine identifier for the currently selected search engine.
-For example:
-
-```js
-{
-  engines: ["searchEngine-google", "searchEngine-yahoo", "searchEngine-bing"],
-  searchEngineIdentifier : "google"
-}
-```
-
-`appData.defaultBrowser`: (bool) Is Firefox the user's default browser?
-If we could not determine the default browser, this value is `null`. Note that
-currently this value is only checked once when the browser is initialized.
-
-`appData.isDevtoolsUser`: (bool) Has the user ever used devtools?
-
-## Events
-
-ActivityStream dispatches custom DOM events on the window to allow snippets
-providers to respond to ActivityStream snippets events.
-
-### `Snippets:Enabled`
-
-Fired when the user chooses to enable snippets.
-
-### `Snippets:Disabled`
-
-Fired when the user chooses to disable snippets.
--- a/browser/components/newtab/karma.mc.config.js
+++ b/browser/components/newtab/karma.mc.config.js
@@ -57,22 +57,16 @@ module.exports = function(config) {
           branches: 66,
           overrides: {
             "lib/ActivityStreamStorage.jsm": {
               statements: 100,
               lines: 100,
               functions: 100,
               branches: 83,
             },
-            "lib/SnippetsFeed.jsm": {
-              statements: 100,
-              lines: 100,
-              functions: 100,
-              branches: 66,
-            },
             "lib/UTEventReporting.jsm": {
               statements: 100,
               lines: 100,
               functions: 100,
               branches: 75,
             },
             "lib/*.jsm": {
               statements: 100,
@@ -172,17 +166,16 @@ module.exports = function(config) {
               path.resolve("content-src"),
               path.resolve("lib"),
               path.resolve("common"),
             ],
             exclude: [
               path.resolve("test"),
               path.resolve("vendor"),
               path.resolve("lib/ASRouterTargeting.jsm"),
-              path.resolve("content-src/lib/snippets.js"),
               path.resolve("lib/ASRouterTriggerListeners.jsm"),
               path.resolve("lib/OnboardingMessageProvider.jsm"),
               path.resolve("lib/CFRMessageProvider.jsm"),
               path.resolve("lib/CFRPageActions.jsm"),
             ],
           },
         ],
       },
--- a/browser/components/newtab/lib/ASRouter.jsm
+++ b/browser/components/newtab/lib/ASRouter.jsm
@@ -189,16 +189,17 @@ const MessageLoaderUtils = {
     return RemoteSettings(bucket).get();
   },
 
   _handleRemoteSettingsUndesiredEvent(event, providerId, dispatchToAS) {
     if (dispatchToAS) {
       dispatchToAS(ac.ASRouterUserEvent({
         action: "asrouter_undesired_event",
         event,
+        message_id: "n/a",
         value: providerId,
       }));
     }
   },
 
   /**
    * _getMessageLoader - return the right loading function given the provider's type
    *
--- a/browser/components/newtab/lib/ActivityStream.jsm
+++ b/browser/components/newtab/lib/ActivityStream.jsm
@@ -16,17 +16,16 @@ const {actionCreators: ac, actionTypes: 
 const {AboutPreferences} = ChromeUtils.import("resource://activity-stream/lib/AboutPreferences.jsm");
 const {DefaultPrefs} = ChromeUtils.import("resource://activity-stream/lib/ActivityStreamPrefs.jsm");
 const {ManualMigration} = ChromeUtils.import("resource://activity-stream/lib/ManualMigration.jsm");
 const {NewTabInit} = ChromeUtils.import("resource://activity-stream/lib/NewTabInit.jsm");
 const {SectionsFeed} = ChromeUtils.import("resource://activity-stream/lib/SectionsManager.jsm");
 const {PlacesFeed} = ChromeUtils.import("resource://activity-stream/lib/PlacesFeed.jsm");
 const {PrefsFeed} = ChromeUtils.import("resource://activity-stream/lib/PrefsFeed.jsm");
 const {Store} = ChromeUtils.import("resource://activity-stream/lib/Store.jsm");
-const {SnippetsFeed} = ChromeUtils.import("resource://activity-stream/lib/SnippetsFeed.jsm");
 const {SystemTickFeed} = ChromeUtils.import("resource://activity-stream/lib/SystemTickFeed.jsm");
 const {TelemetryFeed} = ChromeUtils.import("resource://activity-stream/lib/TelemetryFeed.jsm");
 const {FaviconFeed} = ChromeUtils.import("resource://activity-stream/lib/FaviconFeed.jsm");
 const {TopSitesFeed} = ChromeUtils.import("resource://activity-stream/lib/TopSitesFeed.jsm");
 const {TopStoriesFeed} = ChromeUtils.import("resource://activity-stream/lib/TopStoriesFeed.jsm");
 const {HighlightsFeed} = ChromeUtils.import("resource://activity-stream/lib/HighlightsFeed.jsm");
 const {ASRouterFeed} = ChromeUtils.import("resource://activity-stream/lib/ASRouterFeed.jsm");
 const {DiscoveryStreamFeed} = ChromeUtils.import("resource://activity-stream/lib/DiscoveryStreamFeed.jsm");
@@ -69,17 +68,17 @@ const PREFS_CONFIG = new Map([
       provider_name: "Pocket",
       read_more_endpoint: "https://getpocket.com/explore/trending?src=fx_new_tab",
       stories_endpoint: `https://getpocket.cdn.mozilla.net/v3/firefox/global-recs?version=3&consumer_key=$apiKey&locale_lang=${args.locale}&feed_variant=${showSpocs(args) ? "default_spocs_on" : "default_spocs_off"}`,
       stories_referrer: "https://getpocket.com/recommendations",
       topics_endpoint: `https://getpocket.cdn.mozilla.net/v3/firefox/trending-topics?version=2&consumer_key=$apiKey&locale_lang=${args.locale}`,
       model_keys: ["nmf_model_animals", "nmf_model_business", "nmf_model_career", "nmf_model_datascience", "nmf_model_design", "nmf_model_education", "nmf_model_entertainment", "nmf_model_environment", "nmf_model_fashion", "nmf_model_finance", "nmf_model_food", "nmf_model_health", "nmf_model_home", "nmf_model_life", "nmf_model_marketing", "nmf_model_politics", "nmf_model_programming", "nmf_model_science", "nmf_model_shopping", "nmf_model_sports", "nmf_model_tech", "nmf_model_travel", "nb_model_animals", "nb_model_books", "nb_model_business", "nb_model_career", "nb_model_datascience", "nb_model_design", "nb_model_economics", "nb_model_education", "nb_model_entertainment", "nb_model_environment", "nb_model_fashion", "nb_model_finance", "nb_model_food", "nb_model_game", "nb_model_health", "nb_model_history", "nb_model_home", "nb_model_life", "nb_model_marketing", "nb_model_military", "nb_model_philosophy", "nb_model_photography", "nb_model_politics", "nb_model_productivity", "nb_model_programming", "nb_model_psychology", "nb_model_science", "nb_model_shopping", "nb_model_society", "nb_model_space", "nb_model_sports", "nb_model_tech", "nb_model_travel", "nb_model_writing"],
       show_spocs: showSpocs(args),
       personalized: true,
-      version: IS_NIGHTLY_OR_UNBRANDED_BUILD ? 2 : 1,
+      version: 1,
     }),
   }],
   ["showSponsored", {
     title: "Show sponsored cards in spoc experiment (show_spocs in topstories.options has to be set to true as well)",
     value: true,
   }],
   ["pocketCta", {
     title: "Pocket cta and button for logged out users.",
@@ -109,19 +108,19 @@ const PREFS_CONFIG = new Map([
   ["prerender", {
     title: "Use the prerendered version of activity-stream.html. This is set automatically by PrefsFeed.jsm.",
     value: true,
   }],
   ["showSearch", {
     title: "Show the Search bar",
     value: true,
   }],
-  ["disableSnippets", {
-    title: "Disable snippets on activity stream",
-    value: false,
+  ["feeds.snippets", {
+    title: "Show snippets on activity stream",
+    value: true,
   }],
   ["topSitesRows", {
     title: "Number of rows of Top Sites to display",
     value: 1,
   }],
   ["telemetry", {
     title: "Enable system error and usage data collection",
     value: true,
@@ -220,30 +219,41 @@ const PREFS_CONFIG = new Map([
       id: "onboarding",
       type: "local",
       localProvider: "OnboardingMessageProvider",
       enabled: true,
       // Block specific messages from this local provider
       exclude: [],
     }),
   }],
+  ["asrouter.providers.cfr-fxa", {
+    title: "Configuration for CFR FxA Messages provider",
+    value: JSON.stringify({
+      id: "cfr-fxa",
+      enabled: false,
+      type: "remote-settings",
+      bucket: "cfr-fxa",
+      frequency: {custom: [{period: "daily", cap: 1}]},
+    }),
+  }],
   // See browser/app/profile/firefox.js for other ASR preferences. They must be defined there to enable roll-outs.
   ["discoverystream.config", {
     title: "Configuration for the new pocket new tab",
     getValue: ({geo, locale}) => {
       const locales = ({
         "US": ["en-CA", "en-GB", "en-US", "en-ZA"],
         "CA": ["en-CA", "en-GB", "en-US", "en-ZA"],
       })[geo];
       const isEnabled = IS_NIGHTLY_OR_UNBRANDED_BUILD && locales && locales.includes(locale);
       return JSON.stringify({
         api_key_pref: "extensions.pocket.oAuthConsumerKey",
         collapsible: true,
         enabled: isEnabled,
         show_spocs: showSpocs({geo}),
+        hardcoded_layout: false,
         personalized: false,
         // This is currently an exmple layout used for dev purposes.
         layout_endpoint: "https://getpocket.cdn.mozilla.net/v3/newtab/layout?version=1&consumer_key=$apiKey&layout_variant=basic",
       });
     },
   }],
   ["discoverystream.endpoints", {
     title: "Endpoint prefixes (comma-separated) that are allowed to be requested",
@@ -319,22 +329,16 @@ const FEEDS_DATA = [
         "US": ["en-CA", "en-GB", "en-US", "en-ZA"],
         "CA": ["en-CA", "en-GB", "en-US", "en-ZA"],
         "DE": ["de", "de-DE", "de-AT", "de-CH"],
       })[geo];
       return !!locales && locales.includes(locale);
     },
   },
   {
-    name: "snippets",
-    factory: () => new SnippetsFeed(),
-    title: "Gets snippets data",
-    value: true,
-  },
-  {
     name: "systemtick",
     factory: () => new SystemTickFeed(),
     title: "Produces system tick events to periodically check for data expiry",
     value: true,
   },
   {
     name: "telemetry",
     factory: () => new TelemetryFeed(),
--- a/browser/components/newtab/lib/DiscoveryStreamFeed.jsm
+++ b/browser/components/newtab/lib/DiscoveryStreamFeed.jsm
@@ -24,16 +24,18 @@ const MAX_LIFETIME_CAP = 500; // Guard a
 const DEFAULT_MAX_HISTORY_QUERY_RESULTS = 1000;
 const PREF_CONFIG = "discoverystream.config";
 const PREF_ENDPOINTS = "discoverystream.endpoints";
 const PREF_OPT_OUT = "discoverystream.optOut.0";
 const PREF_SHOW_SPONSORED = "showSponsored";
 const PREF_SPOC_IMPRESSIONS = "discoverystream.spoc.impressions";
 const PREF_REC_IMPRESSIONS = "discoverystream.rec.impressions";
 
+let defaultLayoutResp;
+
 this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
   constructor() {
     // Internal state for checking if we've intialized all our data
     this.loaded = false;
 
     // Persistent cache for remote endpoint data.
     this.cache = new PersistentCache(CACHE_KEY, true);
     // Internal in-memory cache for parsing json prefs.
@@ -49,16 +51,17 @@ this.DiscoveryStreamFeed = class Discove
 
   get config() {
     if (this._prefCache.config) {
       return this._prefCache.config;
     }
     try {
       this._prefCache.config = JSON.parse(this.store.getState().Prefs.values[PREF_CONFIG]);
       const layoutUrl = this._prefCache.config.layout_endpoint;
+
       const apiKeyPref = this._prefCache.config.api_key_pref;
       if (layoutUrl && apiKeyPref) {
         const apiKey = Services.prefs.getCharPref(apiKeyPref, "");
         this._prefCache.config.layout_endpoint = this.finalLayoutEndpoint(layoutUrl, apiKey);
       }
 
       // Modify the cached config with the user set opt-out for other consumers
       this._prefCache.config.enabled = this._prefCache.config.enabled &&
@@ -86,21 +89,30 @@ this.DiscoveryStreamFeed = class Discove
     this.store.dispatch(ac.BroadcastToContent({type: at.DISCOVERY_STREAM_CONFIG_SETUP, data: this.config}));
   }
 
   uninitPrefs() {
     // Reset in-memory cache
     this._prefCache = {};
   }
 
-  async fetchFromEndpoint(endpoint) {
-    if (!endpoint) {
+  async fetchFromEndpoint(rawEndpoint) {
+    if (!rawEndpoint) {
       Cu.reportError("Tried to fetch endpoint but none was configured.");
       return null;
     }
+
+    const apiKeyPref = this._prefCache.config.api_key_pref;
+    const apiKey = Services.prefs.getCharPref(apiKeyPref, "");
+
+    // The server somtimes returns this value already replaced, but we try this for two reasons:
+    // 1. Layout endpoints are not from the server.
+    // 2. Hardcoded layouts don't have this already done for us.
+    const endpoint = rawEndpoint.replace("$apiKey", apiKey);
+
     try {
       // Make sure the requested endpoint is allowed
       const allowed = this.store.getState().Prefs.values[PREF_ENDPOINTS].split(",");
       if (!allowed.some(prefix => endpoint.startsWith(prefix))) {
         throw new Error(`Not one of allowed prefixes (${allowed})`);
       }
 
       const response = await fetch(endpoint, {credentials: "omit"});
@@ -157,17 +169,17 @@ this.DiscoveryStreamFeed = class Discove
    */
   async checkIfAnyCacheExpired() {
     const expirationPerComponent = await this._checkExpirationPerComponent();
     return expirationPerComponent.layout ||
       expirationPerComponent.spocs ||
       expirationPerComponent.feeds;
   }
 
-  async loadLayout(sendUpdate, isStartup) {
+  async fetchLayout(isStartup) {
     const cachedData = await this.cache.get() || {};
     let {layout} = cachedData;
     if (this.isExpired({cachedData, key: "layout", isStartup})) {
       const start = perfService.absNow();
       const layoutResponse = await this.fetchFromEndpoint(this.config.layout_endpoint);
       if (layoutResponse && layoutResponse.layout) {
         this.layoutRequestTime = Math.round(perfService.absNow() - start);
         layout = {
@@ -176,16 +188,26 @@ this.DiscoveryStreamFeed = class Discove
           layout: layoutResponse.layout,
         };
 
         await this.cache.set("layout", layout);
       } else {
         Cu.reportError("No response for response.layout prop");
       }
     }
+    return layout;
+  }
+
+  async loadLayout(sendUpdate, isStartup) {
+    let layout = {};
+    if (this.config.hardcoded_layout) {
+      layout = {lastUpdate: Date.now(), ...defaultLayoutResp};
+    } else {
+      layout = await this.fetchLayout(isStartup);
+    }
 
     if (layout && layout.layout) {
       sendUpdate({
         type: at.DISCOVERY_STREAM_LAYOUT_UPDATE,
         data: layout,
       });
     }
     if (layout && layout.spocs && layout.spocs.url) {
@@ -235,17 +257,20 @@ this.DiscoveryStreamFeed = class Discove
 
         newFeedsPromises.push(feedPromise);
       }
     };
   }
 
   filterRecommendations(feed) {
     if (feed && feed.data && feed.data.recommendations && feed.data.recommendations.length) {
-      return {data: this.filterBlocked(feed.data, "recommendations")};
+      return {
+        ...feed,
+        data: this.filterBlocked(feed.data, "recommendations"),
+      };
     }
     return feed;
   }
 
   /**
    * reduceFeedComponents - Filters out components with no feeds, and combines
    *                        all feeds on this component with the feeds from other components.
    * @param {Boolean} isStartup We have different cache handling for startup.
@@ -457,18 +482,20 @@ this.DiscoveryStreamFeed = class Discove
         spocs: spocs.filter(s => {
           const isBelow = this.isBelowFrequencyCap(impressions, s);
           if (!isBelow) {
             caps.push(s);
           }
           return isBelow;
         }),
       };
-      // send caps to redux
-      this.store.dispatch({type: at.DISCOVERY_STREAM_SPOCS_CAPS, data: caps});
+      // send caps to redux if any.
+      if (caps.length) {
+        this.store.dispatch({type: at.DISCOVERY_STREAM_SPOCS_CAPS, data: caps});
+      }
       return result;
     }
     return data;
   }
 
   // Frequency caps are based on campaigns, which may include multiple spocs.
   // We currently support two types of frequency caps:
   // - lifetime: Indicates how many times spocs from a campaign can be shown in total
@@ -820,26 +847,29 @@ this.DiscoveryStreamFeed = class Discove
         if (action.data.tiles && action.data.tiles[0] && action.data.tiles[0].id) {
           this.recordTopRecImpressions(action.data.tiles[0].id);
         }
         break;
       case at.DISCOVERY_STREAM_SPOC_IMPRESSION:
         if (this.showSpocs) {
           this.recordCampaignImpression(action.data.campaignId);
 
-          const cachedData = await this.cache.get() || {};
-          const {spocs} = cachedData;
-
-          this.store.dispatch(ac.AlsoToPreloaded({
-            type: at.DISCOVERY_STREAM_SPOCS_UPDATE,
-            data: {
-              lastUpdated: spocs.lastUpdated,
-              spocs: this.transform(this.frequencyCapSpocs(spocs.data)),
-            },
-          }));
+          // Apply frequency capping to SPOCs in the redux store, only update the
+          // store if the SPOCs are changed.
+          const {spocs} = this.store.getState().DiscoveryStream;
+          const newSpocs = this.frequencyCapSpocs(spocs.data);
+          if (spocs.data.spocs.length !== newSpocs.spocs.length) {
+            this.store.dispatch(ac.AlsoToPreloaded({
+              type: at.DISCOVERY_STREAM_SPOCS_UPDATE,
+              data: {
+                lastUpdated: spocs.lastUpdated,
+                spocs: newSpocs,
+              },
+            }));
+          }
         }
         break;
       case at.UNINIT:
         // When this feed is shutting down:
         this.uninitPrefs();
         break;
       case at.PREF_CHANGED:
         switch (action.data.name) {
@@ -857,9 +887,255 @@ this.DiscoveryStreamFeed = class Discove
             await this.loadSpocs(update => this.store.dispatch(ac.BroadcastToContent(update)));
             break;
         }
         break;
     }
   }
 };
 
+defaultLayoutResp = {
+  "spocs": {
+    "url": "https://getpocket.cdn.mozilla.net/v3/firefox/unique-spocs?consumer_key=$apiKey",
+    "spocs_per_domain": 1,
+  },
+  "layout": [
+    {
+      "width": 12,
+      "components": [
+        {
+          "type": "TopSites",
+          "header": {
+            "title": "Top Sites",
+          },
+          "properties": {},
+        },
+      ],
+    },
+    {
+      "width": 12,
+      "components": [
+        {
+          "type": "Message",
+          "header": {
+            "title": "Recommended by Pocket",
+            "subtitle": "",
+            "link_text": "How it works",
+            "link_url": "https://getpocket.com/firefox/new_tab_learn_more",
+            "icon": "resource://activity-stream/data/content/assets/glyph-pocket-16.svg",
+          },
+          "properties": {},
+          "styles": {
+            ".ds-message": "margin-bottom: -20px",
+          },
+        },
+      ],
+    },
+    {
+      "width": 8,
+      "components": [
+        {
+          "type": "List",
+          "header": {
+            "title": "",
+          },
+          "feed": {
+            "embed_reference": null,
+            "url": "https://getpocket.cdn.mozilla.net/v3/firefox/global-recs?version=3&consumer_key=$apiKey&locale_lang=en-US",
+          },
+          "properties": {
+            "items": 8,
+            "has_numbers": false,
+            "has_images": true,
+            "border": "no-border",
+          },
+          "styles": {
+            ".ds-list": "margin-right: -12px",
+          },
+        },
+      ],
+    },
+    {
+      "width": 4,
+      "components": [
+        {
+          "type": "CardGrid",
+          "properties": {
+            "items": 1,
+            "border": "no-border",
+            "offset": 8,
+          },
+          "header": {
+            "title": "",
+          },
+          "feed": {
+            "embed_reference": null,
+            "url": "https://getpocket.cdn.mozilla.net/v3/firefox/global-recs?version=3&consumer_key=$apiKey&locale_lang=en-US",
+          },
+          "styles": {
+            ".ds-card": "margin-left: -12px;",
+            ".ds-card .meta .excerpt": "max-height: 100px;",
+          },
+          "spocs": {
+            "probability": 1,
+            "positions": [
+              {
+                "index": 0,
+              },
+            ],
+          },
+        },
+      ],
+    },
+    {
+      "width": 12,
+      "components": [
+        {
+          "type": "List",
+          "header": {
+            "title": "Health & Fitness 💪",
+          },
+          "feed": {
+            "embed_reference": null,
+            "url": "https://getpocket.cdn.mozilla.net/v3/firefox/global-recs?topic_id=4&duration=2592000&end_time_offset=172800&version=3&consumer_key=$apiKey&locale_lang=en-US&feed_variant=OptimalCuratedLinksForLocaleFeed&model_id=external_time_live",
+          },
+          "properties": {
+            "items": 6,
+            "has_numbers": false,
+            "has_images": true,
+            "border": "no-border",
+          },
+          "spocs": {
+            "probability": 1,
+            "positions": [
+              {
+                "index": 5,
+              },
+            ],
+          },
+        },
+      ],
+    },
+    {
+      "width": 12,
+      "components": [
+        {
+          "type": "List",
+          "header": {
+            "title": "Tech 🖥",
+          },
+          "feed": {
+            "embed_reference": null,
+            "url": "https://getpocket.cdn.mozilla.net/v3/firefox/global-recs?topic_id=5&duration=2592000&end_time_offset=172800&version=3&consumer_key=$apiKey&locale_lang=en-US&feed_variant=OptimalCuratedLinksForLocaleFeed&model_id=external_time_live",
+          },
+          "properties": {
+            "items": 6,
+            "has_numbers": false,
+            "has_images": true,
+            "border": "no-border",
+          },
+        },
+      ],
+    },
+    {
+      "width": 12,
+      "components": [
+        {
+          "type": "List",
+          "header": {
+            "title": "Entertainment 🍿",
+          },
+          "feed": {
+            "embed_reference": null,
+            "url": "https://getpocket.cdn.mozilla.net/v3/firefox/global-recs?topic_id=8&duration=2592000&end_time_offset=172800&version=3&consumer_key=$apiKey&locale_lang=en-US&feed_variant=OptimalCuratedLinksForLocaleFeed&model_id=external_time_live",
+          },
+          "properties": {
+            "items": 6,
+            "has_numbers": false,
+            "has_images": true,
+            "border": "no-border",
+          },
+          "spocs": {
+            "probability": 1,
+            "positions": [
+              {
+                "index": 5,
+              },
+            ],
+          },
+        },
+      ],
+    },
+    {
+      "width": 12,
+      "components": [
+        {
+          "type": "List",
+          "header": {
+            "title": "Personal Finance 💰",
+          },
+          "feed": {
+            "embed_reference": null,
+            "url": "https://getpocket.cdn.mozilla.net/v3/firefox/global-recs?topic_id=2&duration=2592000&end_time_offset=172800&version=3&consumer_key=$apiKey&locale_lang=en-US&feed_variant=OptimalCuratedLinksForLocaleFeed&model_id=external_time_live",
+          },
+          "properties": {
+            "items": 6,
+            "has_numbers": false,
+            "has_images": true,
+            "border": "no-border",
+          },
+        },
+      ],
+    },
+    {
+      "width": 12,
+      "components": [
+        {
+          "type": "List",
+          "header": {
+            "title": "Business 💼",
+          },
+          "feed": {
+            "embed_reference": null,
+            "url": "https://getpocket.cdn.mozilla.net/v3/firefox/global-recs?topic_id=1&duration=2592000&end_time_offset=172800&version=3&consumer_key=$apiKey&locale_lang=en-US&feed_variant=OptimalCuratedLinksForLocaleFeed&model_id=external_time_live",
+          },
+          "properties": {
+            "items": 6,
+            "has_numbers": false,
+            "has_images": true,
+            "border": "no-border",
+          },
+        },
+      ],
+    },
+    {
+      "width": 12,
+      "components": [
+        {
+          "type": "List",
+          "header": {
+            "title": "Science 🔬",
+          },
+          "feed": {
+            "embed_reference": null,
+            "url": "https://getpocket.cdn.mozilla.net/v3/firefox/global-recs?topic_id=7&duration=2592000&end_time_offset=172800&version=3&consumer_key=$apiKey&locale_lang=en-US&feed_variant=OptimalCuratedLinksForLocaleFeed&model_id=external_time_live",
+          },
+          "properties": {
+            "items": 6,
+            "has_numbers": false,
+            "has_images": true,
+            "border": "no-border",
+          },
+          "spocs": {
+            "probability": 1,
+            "positions": [
+              {
+                "index": 5,
+              },
+            ],
+          },
+        },
+      ],
+    },
+  ],
+};
+
 const EXPORTED_SYMBOLS = ["DiscoveryStreamFeed"];
deleted file mode 100644
--- a/browser/components/newtab/lib/SnippetsFeed.jsm
+++ /dev/null
@@ -1,215 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-"use strict";
-
-const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
-const {actionTypes: at, actionCreators: ac} = ChromeUtils.import("resource://activity-stream/common/Actions.jsm");
-
-ChromeUtils.defineModuleGetter(this, "AddonManager",
-  "resource://gre/modules/AddonManager.jsm");
-ChromeUtils.defineModuleGetter(this, "ShellService",
-  "resource:///modules/ShellService.jsm");
-ChromeUtils.defineModuleGetter(this, "ProfileAge",
-  "resource://gre/modules/ProfileAge.jsm");
-ChromeUtils.defineModuleGetter(this, "FxAccounts",
-  "resource://gre/modules/FxAccounts.jsm");
-ChromeUtils.defineModuleGetter(this, "NewTabUtils",
-  "resource://gre/modules/NewTabUtils.jsm");
-
-// Url to fetch snippets, in the urlFormatter service format.
-const SNIPPETS_URL_PREF = "browser.aboutHomeSnippets.updateUrl";
-const TELEMETRY_PREF = "datareporting.healthreport.uploadEnabled";
-const FXA_USERNAME_PREF = "services.sync.username";
-// Prefix for any target matching a search engine.
-const TARGET_SEARCHENGINE_PREFIX = "searchEngine-";
-
-const SEARCH_ENGINE_OBSERVER_TOPIC = "browser-search-engine-modified";
-
-// Should be bumped up if the snippets content format changes.
-const STARTPAGE_VERSION = 5;
-
-const ONE_DAY = 24 * 60 * 60 * 1000;
-const ONE_WEEK = 7 * ONE_DAY;
-
-this.SnippetsFeed = class SnippetsFeed {
-  constructor() {
-    this._refresh = this._refresh.bind(this);
-    this._totalBookmarks = null;
-    this._totalBookmarksLastUpdated = null;
-  }
-
-  get snippetsURL() {
-    const updateURL = Services
-      .prefs.getStringPref(SNIPPETS_URL_PREF)
-      .replace("%STARTPAGE_VERSION%", STARTPAGE_VERSION);
-    return Services.urlFormatter.formatURL(updateURL);
-  }
-
-  isDefaultBrowser() {
-    try {
-      return ShellService.isDefaultBrowser();
-    } catch (e) {}
-    // istanbul ignore next
-    return null;
-  }
-
-  isDevtoolsUser() {
-    return Services.prefs.getIntPref("devtools.selfxss.count") >= 5;
-  }
-
-  async getProfileInfo() {
-    const profileAge = await ProfileAge();
-    const createdDate = await profileAge.created;
-    const resetDate = await profileAge.reset;
-    return {
-      createdWeeksAgo:  Math.floor((Date.now() - createdDate) / ONE_WEEK),
-      resetWeeksAgo: resetDate ? Math.floor((Date.now() - resetDate) / ONE_WEEK) : null,
-    };
-  }
-
-  getSelectedSearchEngine() {
-    return new Promise(resolve => {
-      // Note: calling init ensures this code is only executed after Search has been initialized
-      Services.search.getVisibleEngines().then(engines => {
-        resolve({
-          searchEngineIdentifier: Services.search.defaultEngine.identifier,
-          engines: engines
-            .filter(engine => engine.identifier)
-            .map(engine => `${TARGET_SEARCHENGINE_PREFIX}${engine.identifier}`),
-        });
-      }).catch(() => resolve({engines: [], searchEngineIdentifier: ""}));
-    });
-  }
-
-  async getAddonsInfo(target) {
-    const {addons, fullData} = await AddonManager.getActiveAddons(["extension", "service"]);
-    const info = {};
-    for (const addon of addons) {
-      info[addon.id] = {
-        version: addon.version,
-        type: addon.type,
-        isSystem: addon.isSystem,
-        isWebExtension: addon.isWebExtension,
-      };
-      if (fullData) {
-        Object.assign(info[addon.id], {
-          name: addon.name,
-          userDisabled: addon.userDisabled,
-          installDate: addon.installDate,
-        });
-      }
-    }
-    const data = {addons: info, isFullData: fullData};
-    this.store.dispatch(ac.OnlyToOneContent({type: at.ADDONS_INFO_RESPONSE, data}, target));
-  }
-
-  async getTotalBookmarksCount(target) {
-    if (!this._totalBookmarks || (Date.now() - this._totalBookmarksLastUpdated > ONE_DAY)) {
-      this._totalBookmarksLastUpdated = Date.now();
-      try {
-        this._totalBookmarks = await NewTabUtils.activityStreamProvider.getTotalBookmarksCount();
-      } catch (e) {
-        Cu.reportError(e);
-      }
-    }
-    this.store.dispatch(ac.OnlyToOneContent({type: at.TOTAL_BOOKMARKS_RESPONSE, data: this._totalBookmarks}, target));
-  }
-
-  _dispatchChanges(data) {
-    this.store.dispatch(ac.BroadcastToContent({type: at.SNIPPETS_DATA, data}));
-  }
-
-  async _saveBlockedSnippet(snippetId) {
-    const blockList = await this._getBlockList() || [];
-    return this._storage.set("blockList", blockList.concat([snippetId]));
-  }
-
-  _getBlockList() {
-    return this._storage.get("blockList");
-  }
-
-  _clearBlockList() {
-    return this._storage.set("blockList", []);
-  }
-
-  async _refresh() {
-    const profileInfo = await this.getProfileInfo();
-    const data = {
-      profileCreatedWeeksAgo: profileInfo.createdWeeksAgo,
-      profileResetWeeksAgo: profileInfo.resetWeeksAgo,
-      snippetsURL: this.snippetsURL,
-      version: STARTPAGE_VERSION,
-      telemetryEnabled: Services.prefs.getBoolPref(TELEMETRY_PREF),
-      onboardingFinished: true,
-      fxaccount: Services.prefs.prefHasUserValue(FXA_USERNAME_PREF),
-      selectedSearchEngine: await this.getSelectedSearchEngine(),
-      defaultBrowser: this.isDefaultBrowser(),
-      isDevtoolsUser: this.isDevtoolsUser(),
-      blockList: await this._getBlockList() || [],
-      previousSessionEnd: this._previousSessionEnd,
-    };
-    this._dispatchChanges(data);
-  }
-
-  async observe(subject, topic, data) {
-    if (topic === SEARCH_ENGINE_OBSERVER_TOPIC) {
-      const selectedSearchEngine = await this.getSelectedSearchEngine();
-      this._dispatchChanges({selectedSearchEngine});
-    }
-  }
-
-  async init() {
-    this._storage = this.store.dbStorage.getDbTable("snippets");
-    Services.obs.addObserver(this, SEARCH_ENGINE_OBSERVER_TOPIC);
-    this._previousSessionEnd = await this._storage.get("previousSessionEnd");
-    await this._refresh();
-    Services.prefs.addObserver(SNIPPETS_URL_PREF, this._refresh);
-    Services.prefs.addObserver(TELEMETRY_PREF, this._refresh);
-    Services.prefs.addObserver(FXA_USERNAME_PREF, this._refresh);
-  }
-
-  uninit() {
-    this._storage.set("previousSessionEnd", Date.now());
-    Services.prefs.removeObserver(SNIPPETS_URL_PREF, this._refresh);
-    Services.prefs.removeObserver(TELEMETRY_PREF, this._refresh);
-    Services.prefs.removeObserver(FXA_USERNAME_PREF, this._refresh);
-    Services.obs.removeObserver(this, SEARCH_ENGINE_OBSERVER_TOPIC);
-    this.store.dispatch(ac.BroadcastToContent({type: at.SNIPPETS_RESET}));
-  }
-
-  async showFirefoxAccounts(browser) {
-    const url = await FxAccounts.config.promiseSignUpURI("snippets");
-    // We want to replace the current tab.
-    browser.loadURI(url, {triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal({})});
-  }
-
-  async onAction(action) {
-    switch (action.type) {
-      case at.INIT:
-        this.init();
-        break;
-      case at.UNINIT:
-        this.uninit();
-        break;
-      case at.SHOW_FIREFOX_ACCOUNTS:
-        this.showFirefoxAccounts(action._target.browser);
-        break;
-      case at.SNIPPETS_BLOCKLIST_UPDATED:
-        this._saveBlockedSnippet(action.data);
-        this.store.dispatch(ac.BroadcastToContent({type: at.SNIPPET_BLOCKED, data: action.data}));
-        break;
-      case at.SNIPPETS_BLOCKLIST_CLEARED:
-        this._clearBlockList();
-        break;
-      case at.TOTAL_BOOKMARKS_REQUEST:
-        this.getTotalBookmarksCount(action.meta.fromTarget);
-        break;
-      case at.ADDONS_INFO_REQUEST:
-        await this.getAddonsInfo(action.meta.fromTarget);
-        break;
-    }
-  }
-};
-
-const EXPORTED_SYMBOLS = ["SnippetsFeed"];
--- a/browser/components/newtab/locales-src/cs/strings.properties
+++ b/browser/components/newtab/locales-src/cs/strings.properties
@@ -88,33 +88,34 @@ section_disclaimer_topstories_buttontext=Ok, rozumím
 # for a "Firefox Home" section. "Firefox" should be treated as a brand and kept
 # in English, while "Home" should be localized matching the about:preferences
 # sidebar mozilla-central string for the panel that has preferences related to
 # what is shown for the homepage, new windows, and new tabs.
 prefs_home_header=Obsah domovské stránky Firefoxu
 prefs_home_description=Vyberte obsah, který chcete mít na výchozí domovské stránce Firefoxu.
 
 prefs_content_discovery_header=Domovská stránka Firefoxu
+
 prefs_content_discovery_description=Doporučování obsahu na domovské stránce obsahu vám nabídne kvalitní a relevantní články z celého internetu.
 prefs_content_discovery_button=Vypnout doporučování obsahu
 
 # LOCALIZATION NOTE (prefs_section_rows_option): This is a semi-colon list of
 # plural forms used in a drop down of multiple row options (1 row, 2 rows).
 # See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
 prefs_section_rows_option={num} řádek;{num} řádky;{num} řádků
 prefs_search_header=Vyhledávání na webu
 prefs_topsites_description=Nejnavštěvovanější stránky
 prefs_topstories_description2=Skvělý obsah z celého webu, vybraný speciálně pro vás
 prefs_topstories_options_sponsored_label=Sponzorované články
 prefs_topstories_sponsored_learn_more=Zjistit více
 prefs_highlights_description=Výběr z uložených nebo navštívených stránek
 prefs_highlights_options_visited_label=Navštívené stránky
 prefs_highlights_options_download_label=Nedávná stahování
 prefs_highlights_options_pocket_label=Stránky uložené do služby Pocket
-prefs_snippets_description=Informace od Mozilly a o Firefoxu
+prefs_snippets_description=Aktuální informace od Mozilly a Firefoxu
 settings_pane_button_label=Přizpůsobení stránky nového panelu
 settings_pane_topsites_header=Top stránky
 settings_pane_highlights_header=Vybrané
 settings_pane_highlights_options_bookmarks=Záložky
 # LOCALIZATION NOTE(settings_pane_snippets_header): For the "Snippets" feature
 # traditionally on about:home. Alternative translation options: "Small Note" or
 # something that expresses the idea of "a small message, shortened from
 # something else, and non-essential but also not entirely trivial and useless."
--- a/browser/components/newtab/locales-src/gd/strings.properties
+++ b/browser/components/newtab/locales-src/gd/strings.properties
@@ -86,16 +86,22 @@ section_disclaimer_topstories_buttontext
 
 # LOCALIZATION NOTE (prefs_*, settings_*): These are shown in about:preferences
 # for a "Firefox Home" section. "Firefox" should be treated as a brand and kept
 # in English, while "Home" should be localized matching the about:preferences
 # sidebar mozilla-central string for the panel that has preferences related to
 # what is shown for the homepage, new windows, and new tabs.
 prefs_home_header=Susbaint sgrìn mhòr Firefox
 prefs_home_description=Tagh an t-susbaint a bu mhath leat fhaicinn air sgrìn mhòr Firefox
+
+prefs_content_discovery_header=Dachaigh Firefox
+
+prefs_content_discovery_description=Bheir fidreadh susbaint ann am Firefox Home cothrom dhut sàr-artaigealan iomchaidh o fheadh an lìn a lorg.
+prefs_content_discovery_button=Cuir dheth fidreadh susbaint
+
 # LOCALIZATION NOTE (prefs_section_rows_option): This is a semi-colon list of
 # plural forms used in a drop down of multiple row options (1 row, 2 rows).
 # See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
 prefs_section_rows_option={num} ràgh;{num} ràgh;{num} ràghan;{num} ràgh
 prefs_search_header=Lorg air an lìon
 prefs_topsites_description=Na làraichean air an tadhail thu as trice
 prefs_topstories_description2=Sàr-shusbaint o fheadh an lìn, air a phearsantachadh dhut-sa
 prefs_topstories_options_sponsored_label=Sgeulachdan sponsairichte
@@ -139,17 +145,16 @@ topsites_form_image_validation=Dh’fhàillig luchdadh an deilbh. Feuch URL eile.
 
 # LOCALIZATION NOTE (pocket_read_more): This is shown at the bottom of the
 # trending stories section and precedes a list of links to popular topics.
 pocket_read_more=Cuspairean fèillmhor:
 # LOCALIZATION NOTE (pocket_read_even_more): This is shown as a link at the
 # end of the list of popular topic links.
 pocket_read_even_more=Seall barrachd sgeul
 pocket_more_reccommendations=Barrachd mholaidhean
-pocket_learn_more=Barrachd fiosrachaidh
 pocket_how_it_works=Mar a dh’obraicheas e
 pocket_cta_button=Faigh Pocket
 pocket_cta_text=Sàbhail na sgeulachdan as fhearr leat ann am Pocket is faigh toileachas inntinn san leughadh.
 
 highlights_empty_state=Tòisich air brabhsadh is seallaidh sinn dhut an-seo cuid dhe na h-artaigilean, videothan is duilleagan eile air an do thadhail thu no a chuir thu ris na comharran-lìn o chionn ghoirid.
 # LOCALIZATION NOTE (topstories_empty_state): When there are no recommendations,
 # in the space that would have shown a few stories, this is shown instead.
 # {provider} is replaced by the name of the content provider for this section.
--- a/browser/components/newtab/locales-src/pt-BR/strings.properties
+++ b/browser/components/newtab/locales-src/pt-BR/strings.properties
@@ -1,15 +1,15 @@
 newtab_page_title=Nova aba
 
 header_top_sites=Sites preferidos
 header_highlights=Destaques
 # LOCALIZATION NOTE(header_recommended_by): This is followed by the name
 # of the corresponding content provider.
-header_recommended_by=Recomendado por {provider}
+header_recommended_by=Recomendado pelo {provider}
 
 # LOCALIZATION NOTE(context_menu_button_sr): This is for screen readers when
 # the context menu button is focused/active. Title is the label or hostname of
 # the site.
 context_menu_button_sr=Abrir menu de contexto para {title}
 
 # LOCALIZATION NOTE(section_context_menu_button_sr): This is for screen readers when
 # the section edit context menu button is focused/active.
@@ -88,16 +88,17 @@ section_disclaimer_topstories_buttontext
 # for a "Firefox Home" section. "Firefox" should be treated as a brand and kept
 # in English, while "Home" should be localized matching the about:preferences
 # sidebar mozilla-central string for the panel that has preferences related to
 # what is shown for the homepage, new windows, and new tabs.
 prefs_home_header=Conteúdo inicial do Firefox
 prefs_home_description=Escolha que conteúdo você quer na sua tela inicial do Firefox.
 
 prefs_content_discovery_header=Página inicial do Firefox
+
 prefs_content_discovery_description=A descoberta de conteúdo na página inicial do Firefox permite descobrir artigos relevantes, de alta qualidade, pela web afora.
 prefs_content_discovery_button=Desativar descoberta de conteúdo
 
 # LOCALIZATION NOTE (prefs_section_rows_option): This is a semi-colon list of
 # plural forms used in a drop down of multiple row options (1 row, 2 rows).
 # See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
 prefs_section_rows_option={num} linha;{num} linhas
 prefs_search_header=Pesquisar na web
--- a/browser/components/newtab/locales-src/ta/strings.properties
+++ b/browser/components/newtab/locales-src/ta/strings.properties
@@ -88,29 +88,27 @@ section_disclaimer_topstories_buttontext=சரி, புரிந்தது
 # for a "Firefox Home" section. "Firefox" should be treated as a brand and kept
 # in English, while "Home" should be localized matching the about:preferences
 # sidebar mozilla-central string for the panel that has preferences related to
 # what is shown for the homepage, new windows, and new tabs.
 prefs_home_header=Firefox முகப்பு உள்ளடக்கம்
 prefs_home_description=உங்கள் பயர்பாக்ஸ் முகப்புத் திரையில் என்ன உள்ளடக்கம் வேண்டுமென்று தேர்ந்தெடு.
 
 prefs_content_discovery_header=பயர்பாஃசு முகப்பு
+
 prefs_content_discovery_description=பயர்பாஃசு முகப்பில் உள்ள உள்ளடக்க கண்டுபிடிப்பு, வலைத்தளங்களில் உள்ள உயர் தர, தொடர்புடைய கட்டுரைகளைக் கண்டறிய அனுமதிக்கிறது.
 prefs_content_discovery_button=உள்ளடக்க கண்டுபிடிப்பை முடக்கு
 
 # LOCALIZATION NOTE (prefs_section_rows_option): This is a semi-colon list of
 # plural forms used in a drop down of multiple row options (1 row, 2 rows).
 # See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
 prefs_section_rows_option={num} வரிசை;{num} வரிசைகள்
-prefs_search_header=வலைதள தேடல்
-prefs_topsites_description=நீங்கள் மிகவும் பார்வையிடும் தளங்கள்
 prefs_topstories_description2=இணையத்திலிருந்து சிறந்த உள்ளடக்கங்கள், உங்களுக்காக தனிப்பயனாக்கப்பட்டவை
 prefs_topstories_options_sponsored_label=விளம்பரக் கதைகள்
 prefs_topstories_sponsored_learn_more=மேலும் அறிய
-prefs_highlights_description=நீங்கள் சேமித்த அல்லது பார்வையிட்ட தளங்களின் தேர்வு
 prefs_highlights_options_visited_label=பார்வையிட்டத் தளம்
 prefs_highlights_options_download_label=அண்மைய பதிவிறக்கம்
 prefs_highlights_options_pocket_label=பக்கங்கள் பாக்கெட்டில் சேமிக்கப்பட்டது
 prefs_snippets_description=மொசில்லா மற்றும் பயர்பாக்சிலிருந்து புதுப்பிப்புகள்
 settings_pane_button_label=உங்கள் புதிய கீற்றுப் பக்கத்தை விருப்பமை
 settings_pane_topsites_header=சிறந்த தளங்கள்
 settings_pane_highlights_header=மிளிர்ப்புகள்
 settings_pane_highlights_options_bookmarks=புத்தகக்குறிகள்
--- a/browser/components/newtab/prerendered/locales/ach/activity-stream-prerendered-noscripts.html
+++ b/browser/components/newtab/prerendered/locales/ach/activity-stream-prerendered-noscripts.html
@@ -4,14 +4,14 @@
     <meta charset="utf-8">
     <meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'unsafe-inline' resource: chrome:; connect-src https:; img-src https: data: blob:; style-src 'unsafe-inline';">
     <title>Dirica matidi manyen</title>
     <link rel="icon" type="image/png" href="chrome://branding/content/icon32.png"/>
     <link rel="stylesheet" href="chrome://browser/content/contentSearchUI.css" />
     <link rel="stylesheet" href="resource://activity-stream/css/activity-stream.css" />
   </head>
   <body class="activity-stream">
-    <div id="root"><div data-reactroot=""><div class="outer-wrapper fixed-to-top"><main><div class="non-collapsible-section"><div class="search-wrapper"><div class="search-inner-wrapper"><label for="newtab-search-text" class="search-label"><span class="sr-only"><span>Yeny kakube</span></span></label><input type="search" id="newtab-search-text" maxLength="256" placeholder="Yeny kakube" title="Yeny kakube"/><button id="searchSubmit" class="search-button" title="Yeny"><span class="sr-only"><span>Yeny</span></span></button></div></div></div><div class="body-wrapper"><div class="sections-list"><section class="collapsible-section top-sites animation-enabled" data-section-id="topsites"><div class="section-top-bar"><h3 class="section-title"><span class="click-target-container"><span class="click-target"><span class="icon icon-small-spacer icon-topsites"></span><span>Kakube maloyo</span></span><span class="click-target"></span><span class="learn-more-link-wrapper"></span></span></h3><div><button class="context-menu-button icon" title="Yab jami ayera"><span class="sr-only"><span>Open the section context menu</span></span></button></div></div><div class="section-body"><ul class="top-sites-list"><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Yub kakube man"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Yub kakube man"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Yub kakube man"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Yub kakube man"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Yub kakube man"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Yub kakube man"></button></div></li><li class="top-site-outer placeholder hide-for-narrow"><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Yub kakube man"></button></div></li><li class="top-site-outer placeholder hide-for-narrow"><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Yub kakube man"></button></div></li></ul><div class="edit-topsites-wrapper"></div></div></section><section class="collapsible-section section normal-cards animation-enabled" data-section-id="topstories"><div class="section-top-bar"><h3 class="section-title"><span class="click-target-container"><span class="click-target"><span class="icon icon-small-spacer icon-pocket"></span><span>Lami tam obedo Pocket</span></span><span class="click-target"></span><span class="learn-more-link-wrapper"></span></span></h3><div><button class="context-menu-button icon" title="Yab jami ayera"><span class="sr-only"><span>Open the section context menu</span></span></button></div></div><div class="section-body"><ul class="section-list" style="padding:0"></ul><div class="top-stories-bottom-container"><div class="wrapper-more-recommendations"></div></div></div></section><section class="collapsible-section section normal-cards animation-enabled" data-section-id="highlights"><div class="section-top-bar"><h3 class="section-title"><span class="click-target-container"><span class="click-target"><span class="icon icon-small-spacer icon-highlights"></span><span>Wiye madito</span></span><span class="click-target"></span><span class="learn-more-link-wrapper"></span></span></h3><div><button class="context-menu-button icon" title="Yab jami ayera"><span class="sr-only"><span>Open the section context menu</span></span></button></div></div><div class="section-body"><ul class="section-list" style="padding:0"></ul></div></section></div><div class="prefs-button"><button class="icon icon-settings" title="Yub potbuk me dirica matidi mamegi manyen"></button></div></div></main></div></div></div>
+    <div id="root"><div><div class="outer-wrapper fixed-to-top"><main><div class="non-collapsible-section"><div class="search-wrapper"><div class="search-inner-wrapper"><label for="newtab-search-text" class="search-label"><span class="sr-only"><span>Yeny kakube</span></span></label><input type="search" id="newtab-search-text" maxLength="256" placeholder="Yeny kakube" title="Yeny kakube"/><button id="searchSubmit" class="search-button" title="Yeny"><span class="sr-only"><span>Yeny</span></span></button></div></div></div><div class="body-wrapper"><div class="sections-list"><section class="collapsible-section top-sites animation-enabled" data-section-id="topsites"><div class="section-top-bar"><h3 class="section-title"><span class="click-target-container"><span class="click-target"><span class="icon icon-small-spacer icon-topsites"></span><span>Kakube maloyo</span></span><span class="click-target"></span><span class="learn-more-link-wrapper"></span></span></h3><div><button class="context-menu-button icon" title="Yab jami ayera"><span class="sr-only"><span>Open the section context menu</span></span></button></div></div><div class="section-body"><ul class="top-sites-list"><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Yub kakube man"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Yub kakube man"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Yub kakube man"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Yub kakube man"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Yub kakube man"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Yub kakube man"></button></div></li><li class="top-site-outer placeholder hide-for-narrow"><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Yub kakube man"></button></div></li><li class="top-site-outer placeholder hide-for-narrow"><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Yub kakube man"></button></div></li></ul><div class="edit-topsites-wrapper"></div></div></section><section class="collapsible-section section normal-cards animation-enabled" data-section-id="topstories"><div class="section-top-bar"><h3 class="section-title"><span class="click-target-container"><span class="click-target"><span class="icon icon-small-spacer icon-pocket"></span><span>Lami tam obedo Pocket</span></span><span class="click-target"></span><span class="learn-more-link-wrapper"></span></span></h3><div><button class="context-menu-button icon" title="Yab jami ayera"><span class="sr-only"><span>Open the section context menu</span></span></button></div></div><div class="section-body"><ul class="section-list" style="padding:0"></ul><div class="top-stories-bottom-container"><div class="wrapper-more-recommendations"></div></div></div></section><section class="collapsible-section section normal-cards animation-enabled" data-section-id="highlights"><div class="section-top-bar"><h3 class="section-title"><span class="click-target-container"><span class="click-target"><span class="icon icon-small-spacer icon-highlights"></span><span>Wiye madito</span></span><span class="click-target"></span><span class="learn-more-link-wrapper"></span></span></h3><div><button class="context-menu-button icon" title="Yab jami ayera"><span class="sr-only"><span>Open the section context menu</span></span></button></div></div><div class="section-body"><ul class="section-list" style="padding:0"></ul></div></section></div><div class="prefs-button"><button class="icon icon-settings" title="Yub potbuk me dirica matidi mamegi manyen"></button></div></div></main></div></div></div>
     <div id="snippets-container">
       <div id="snippets"></div>
     </div>
   </body>
 </html>
--- a/browser/components/newtab/prerendered/locales/ach/activity-stream-prerendered.html
+++ b/browser/components/newtab/prerendered/locales/ach/activity-stream-prerendered.html
@@ -4,17 +4,17 @@
     <meta charset="utf-8">
     <meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'unsafe-inline' resource: chrome:; connect-src https:; img-src https: data: blob:; style-src 'unsafe-inline';">
     <title>Dirica matidi manyen</title>
     <link rel="icon" type="image/png" href="chrome://branding/content/icon32.png"/>
     <link rel="stylesheet" href="chrome://browser/content/contentSearchUI.css" />
     <link rel="stylesheet" href="resource://activity-stream/css/activity-stream.css" />
   </head>
   <body class="activity-stream">
-    <div id="root"><div data-reactroot=""><div class="outer-wrapper fixed-to-top"><main><div class="non-collapsible-section"><div class="search-wrapper"><div class="search-inner-wrapper"><label for="newtab-search-text" class="search-label"><span class="sr-only"><span>Yeny kakube</span></span></label><input type="search" id="newtab-search-text" maxLength="256" placeholder="Yeny kakube" title="Yeny kakube"/><button id="searchSubmit" class="search-button" title="Yeny"><span class="sr-only"><span>Yeny</span></span></button></div></div></div><div class="body-wrapper"><div class="sections-list"><section class="collapsible-section top-sites animation-enabled" data-section-id="topsites"><div class="section-top-bar"><h3 class="section-title"><span class="click-target-container"><span class="click-target"><span class="icon icon-small-spacer icon-topsites"></span><span>Kakube maloyo</span></span><span class="click-target"></span><span class="learn-more-link-wrapper"></span></span></h3><div><button class="context-menu-button icon" title="Yab jami ayera"><span class="sr-only"><span>Open the section context menu</span></span></button></div></div><div class="section-body"><ul class="top-sites-list"><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Yub kakube man"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Yub kakube man"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Yub kakube man"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Yub kakube man"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Yub kakube man"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Yub kakube man"></button></div></li><li class="top-site-outer placeholder hide-for-narrow"><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Yub kakube man"></button></div></li><li class="top-site-outer placeholder hide-for-narrow"><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Yub kakube man"></button></div></li></ul><div class="edit-topsites-wrapper"></div></div></section><section class="collapsible-section section normal-cards animation-enabled" data-section-id="topstories"><div class="section-top-bar"><h3 class="section-title"><span class="click-target-container"><span class="click-target"><span class="icon icon-small-spacer icon-pocket"></span><span>Lami tam obedo Pocket</span></span><span class="click-target"></span><span class="learn-more-link-wrapper"></span></span></h3><div><button class="context-menu-button icon" title="Yab jami ayera"><span class="sr-only"><span>Open the section context menu</span></span></button></div></div><div class="section-body"><ul class="section-list" style="padding:0"></ul><div class="top-stories-bottom-container"><div class="wrapper-more-recommendations"></div></div></div></section><section class="collapsible-section section normal-cards animation-enabled" data-section-id="highlights"><div class="section-top-bar"><h3 class="section-title"><span class="click-target-container"><span class="click-target"><span class="icon icon-small-spacer icon-highlights"></span><span>Wiye madito</span></span><span class="click-target"></span><span class="learn-more-link-wrapper"></span></span></h3><div><button class="context-menu-button icon" title="Yab jami ayera"><span class="sr-only"><span>Open the section context menu</span></span></button></div></div><div class="section-body"><ul class="section-list" style="padding:0"></ul></div></section></div><div class="prefs-button"><button class="icon icon-settings" title="Yub potbuk me dirica matidi mamegi manyen"></button></div></div></main></div></div></div>
+    <div id="root"><div><div class="outer-wrapper fixed-to-top"><main><div class="non-collapsible-section"><div class="search-wrapper"><div class="search-inner-wrapper"><label for="newtab-search-text" class="search-label"><span class="sr-only"><span>Yeny kakube</span></span></label><input type="search" id="newtab-search-text" maxLength="256" placeholder="Yeny kakube" title="Yeny kakube"/><button id="searchSubmit" class="search-button" title="Yeny"><span class="sr-only"><span>Yeny</span></span></button></div></div></div><div class="body-wrapper"><div class="sections-list"><section class="collapsible-section top-sites animation-enabled" data-section-id="topsites"><div class="section-top-bar"><h3 class="section-title"><span class="click-target-container"><span class="click-target"><span class="icon icon-small-spacer icon-topsites"></span><span>Kakube maloyo</span></span><span class="click-target"></span><span class="learn-more-link-wrapper"></span></span></h3><div><button class="context-menu-button icon" title="Yab jami ayera"><span class="sr-only"><span>Open the section context menu</span></span></button></div></div><div class="section-body"><ul class="top-sites-list"><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Yub kakube man"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Yub kakube man"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Yub kakube man"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Yub kakube man"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Yub kakube man"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Yub kakube man"></button></div></li><li class="top-site-outer placeholder hide-for-narrow"><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Yub kakube man"></button></div></li><li class="top-site-outer placeholder hide-for-narrow"><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Yub kakube man"></button></div></li></ul><div class="edit-topsites-wrapper"></div></div></section><section class="collapsible-section section normal-cards animation-enabled" data-section-id="topstories"><div class="section-top-bar"><h3 class="section-title"><span class="click-target-container"><span class="click-target"><span class="icon icon-small-spacer icon-pocket"></span><span>Lami tam obedo Pocket</span></span><span class="click-target"></span><span class="learn-more-link-wrapper"></span></span></h3><div><button class="context-menu-button icon" title="Yab jami ayera"><span class="sr-only"><span>Open the section context menu</span></span></button></div></div><div class="section-body"><ul class="section-list" style="padding:0"></ul><div class="top-stories-bottom-container"><div class="wrapper-more-recommendations"></div></div></div></section><section class="collapsible-section section normal-cards animation-enabled" data-section-id="highlights"><div class="section-top-bar"><h3 class="section-title"><span class="click-target-container"><span class="click-target"><span class="icon icon-small-spacer icon-highlights"></span><span>Wiye madito</span></span><span class="click-target"></span><span class="learn-more-link-wrapper"></span></span></h3><div><button class="context-menu-button icon" title="Yab jami ayera"><span class="sr-only"><span>Open the section context menu</span></span></button></div></div><div class="section-body"><ul class="section-list" style="padding:0"></ul></div></section></div><div class="prefs-button"><button class="icon icon-settings" title="Yub potbuk me dirica matidi mamegi manyen"></button></div></div></main></div></div></div>
     <div id="snippets-container">
       <div id="snippets"></div>
     </div>
     <script>
 // Don't directly load the following scripts as part of html to let the page
 // finish loading to render the content sooner.
 for (const src of [
   "resource://activity-stream/prerendered/static/activity-stream-initial-state.js",
--- a/browser/components/newtab/prerendered/locales/an/activity-stream-prerendered-noscripts.html
+++ b/browser/components/newtab/prerendered/locales/an/activity-stream-prerendered-noscripts.html
@@ -4,14 +4,14 @@
     <meta charset="utf-8">
     <meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'unsafe-inline' resource: chrome:; connect-src https:; img-src https: data: blob:; style-src 'unsafe-inline';">
     <title>Nueva Pestanya</title>
     <link rel="icon" type="image/png" href="chrome://branding/content/icon32.png"/>
     <link rel="stylesheet" href="chrome://browser/content/contentSearchUI.css" />
     <link rel="stylesheet" href="resource://activity-stream/css/activity-stream.css" />
   </head>
   <body class="activity-stream">
-    <div id="root"><div data-reactroot=""><div class="outer-wrapper fixed-to-top"><main><div class="non-collapsible-section"><div class="search-wrapper"><div class="search-inner-wrapper"><label for="newtab-search-text" class="search-label"><span class="sr-only"><span>Mirar en o Web</span></span></label><input type="search" id="newtab-search-text" maxLength="256" placeholder="Mirar en o Web" title="Mirar en o Web"/><button id="searchSubmit" class="search-button" title="Mirar"><span class="sr-only"><span>Mirar</span></span></button></div></div></div><div class="body-wrapper"><div class="sections-list"><section class="collapsible-section top-sites animation-enabled" data-section-id="topsites"><div class="section-top-bar"><h3 class="section-title"><span class="click-target-container"><span class="click-target"><span class="icon icon-small-spacer icon-topsites"></span><span>Mas freqüents</span></span><span class="click-target"></span><span class="learn-more-link-wrapper"></span></span></h3><div><button class="context-menu-button icon" title="Open menu"><span class="sr-only"><span>Ubrir lo menú contextual d&#x27;a sección</span></span></button></div></div><div class="section-body"><ul class="top-sites-list"><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Editar este puesto"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Editar este puesto"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Editar este puesto"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Editar este puesto"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Editar este puesto"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Editar este puesto"></button></div></li><li class="top-site-outer placeholder hide-for-narrow"><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Editar este puesto"></button></div></li><li class="top-site-outer placeholder hide-for-narrow"><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Editar este puesto"></button></div></li></ul><div class="edit-topsites-wrapper"></div></div></section><section class="collapsible-section section normal-cards animation-enabled" data-section-id="topstories"><div class="section-top-bar"><h3 class="section-title"><span class="click-target-container"><span class="click-target"><span class="icon icon-small-spacer icon-pocket"></span><span>Recomendau per Pocket</span></span><span class="click-target"></span><span class="learn-more-link-wrapper"></span></span></h3><div><button class="context-menu-button icon" title="Open menu"><span class="sr-only"><span>Ubrir lo menú contextual d&#x27;a sección</span></span></button></div></div><div class="section-body"><ul class="section-list" style="padding:0"></ul><div class="top-stories-bottom-container"><div class="wrapper-more-recommendations"></div></div></div></section><section class="collapsible-section section normal-cards animation-enabled" data-section-id="highlights"><div class="section-top-bar"><h3 class="section-title"><span class="click-target-container"><span class="click-target"><span class="icon icon-small-spacer icon-highlights"></span><span>Destacaus</span></span><span class="click-target"></span><span class="learn-more-link-wrapper"></span></span></h3><div><button class="context-menu-button icon" title="Open menu"><span class="sr-only"><span>Ubrir lo menú contextual d&#x27;a sección</span></span></button></div></div><div class="section-body"><ul class="section-list" style="padding:0"></ul></div></section></div><div class="prefs-button"><button class="icon icon-settings" title="Personaliza la tuya pachina de Nueva Pestanya"></button></div></div></main></div></div></div>
+    <div id="root"><div><div class="outer-wrapper fixed-to-top"><main><div class="non-collapsible-section"><div class="search-wrapper"><div class="search-inner-wrapper"><label for="newtab-search-text" class="search-label"><span class="sr-only"><span>Mirar en o Web</span></span></label><input type="search" id="newtab-search-text" maxLength="256" placeholder="Mirar en o Web" title="Mirar en o Web"/><button id="searchSubmit" class="search-button" title="Mirar"><span class="sr-only"><span>Mirar</span></span></button></div></div></div><div class="body-wrapper"><div class="sections-list"><section class="collapsible-section top-sites animation-enabled" data-section-id="topsites"><div class="section-top-bar"><h3 class="section-title"><span class="click-target-container"><span class="click-target"><span class="icon icon-small-spacer icon-topsites"></span><span>Mas freqüents</span></span><span class="click-target"></span><span class="learn-more-link-wrapper"></span></span></h3><div><button class="context-menu-button icon" title="Open menu"><span class="sr-only"><span>Ubrir lo menú contextual d&#x27;a sección</span></span></button></div></div><div class="section-body"><ul class="top-sites-list"><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Editar este puesto"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Editar este puesto"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Editar este puesto"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Editar este puesto"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Editar este puesto"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Editar este puesto"></button></div></li><li class="top-site-outer placeholder hide-for-narrow"><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Editar este puesto"></button></div></li><li class="top-site-outer placeholder hide-for-narrow"><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Editar este puesto"></button></div></li></ul><div class="edit-topsites-wrapper"></div></div></section><section class="collapsible-section section normal-cards animation-enabled" data-section-id="topstories"><div class="section-top-bar"><h3 class="section-title"><span class="click-target-container"><span class="click-target"><span class="icon icon-small-spacer icon-pocket"></span><span>Recomendau per Pocket</span></span><span class="click-target"></span><span class="learn-more-link-wrapper"></span></span></h3><div><button class="context-menu-button icon" title="Open menu"><span class="sr-only"><span>Ubrir lo menú contextual d&#x27;a sección</span></span></button></div></div><div class="section-body"><ul class="section-list" style="padding:0"></ul><div class="top-stories-bottom-container"><div class="wrapper-more-recommendations"></div></div></div></section><section class="collapsible-section section normal-cards animation-enabled" data-section-id="highlights"><div class="section-top-bar"><h3 class="section-title"><span class="click-target-container"><span class="click-target"><span class="icon icon-small-spacer icon-highlights"></span><span>Destacaus</span></span><span class="click-target"></span><span class="learn-more-link-wrapper"></span></span></h3><div><button class="context-menu-button icon" title="Open menu"><span class="sr-only"><span>Ubrir lo menú contextual d&#x27;a sección</span></span></button></div></div><div class="section-body"><ul class="section-list" style="padding:0"></ul></div></section></div><div class="prefs-button"><button class="icon icon-settings" title="Personaliza la tuya pachina de Nueva Pestanya"></button></div></div></main></div></div></div>
     <div id="snippets-container">
       <div id="snippets"></div>
     </div>
   </body>
 </html>
--- a/browser/components/newtab/prerendered/locales/an/activity-stream-prerendered.html
+++ b/browser/components/newtab/prerendered/locales/an/activity-stream-prerendered.html
@@ -4,17 +4,17 @@
     <meta charset="utf-8">
     <meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'unsafe-inline' resource: chrome:; connect-src https:; img-src https: data: blob:; style-src 'unsafe-inline';">
     <title>Nueva Pestanya</title>
     <link rel="icon" type="image/png" href="chrome://branding/content/icon32.png"/>
     <link rel="stylesheet" href="chrome://browser/content/contentSearchUI.css" />
     <link rel="stylesheet" href="resource://activity-stream/css/activity-stream.css" />
   </head>
   <body class="activity-stream">
-    <div id="root"><div data-reactroot=""><div class="outer-wrapper fixed-to-top"><main><div class="non-collapsible-section"><div class="search-wrapper"><div class="search-inner-wrapper"><label for="newtab-search-text" class="search-label"><span class="sr-only"><span>Mirar en o Web</span></span></label><input type="search" id="newtab-search-text" maxLength="256" placeholder="Mirar en o Web" title="Mirar en o Web"/><button id="searchSubmit" class="search-button" title="Mirar"><span class="sr-only"><span>Mirar</span></span></button></div></div></div><div class="body-wrapper"><div class="sections-list"><section class="collapsible-section top-sites animation-enabled" data-section-id="topsites"><div class="section-top-bar"><h3 class="section-title"><span class="click-target-container"><span class="click-target"><span class="icon icon-small-spacer icon-topsites"></span><span>Mas freqüents</span></span><span class="click-target"></span><span class="learn-more-link-wrapper"></span></span></h3><div><button class="context-menu-button icon" title="Open menu"><span class="sr-only"><span>Ubrir lo menú contextual d&#x27;a sección</span></span></button></div></div><div class="section-body"><ul class="top-sites-list"><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Editar este puesto"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Editar este puesto"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Editar este puesto"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Editar este puesto"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Editar este puesto"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Editar este puesto"></button></div></li><li class="top-site-outer placeholder hide-for-narrow"><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Editar este puesto"></button></div></li><li class="top-site-outer placeholder hide-for-narrow"><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Editar este puesto"></button></div></li></ul><div class="edit-topsites-wrapper"></div></div></section><section class="collapsible-section section normal-cards animation-enabled" data-section-id="topstories"><div class="section-top-bar"><h3 class="section-title"><span class="click-target-container"><span class="click-target"><span class="icon icon-small-spacer icon-pocket"></span><span>Recomendau per Pocket</span></span><span class="click-target"></span><span class="learn-more-link-wrapper"></span></span></h3><div><button class="context-menu-button icon" title="Open menu"><span class="sr-only"><span>Ubrir lo menú contextual d&#x27;a sección</span></span></button></div></div><div class="section-body"><ul class="section-list" style="padding:0"></ul><div class="top-stories-bottom-container"><div class="wrapper-more-recommendations"></div></div></div></section><section class="collapsible-section section normal-cards animation-enabled" data-section-id="highlights"><div class="section-top-bar"><h3 class="section-title"><span class="click-target-container"><span class="click-target"><span class="icon icon-small-spacer icon-highlights"></span><span>Destacaus</span></span><span class="click-target"></span><span class="learn-more-link-wrapper"></span></span></h3><div><button class="context-menu-button icon" title="Open menu"><span class="sr-only"><span>Ubrir lo menú contextual d&#x27;a sección</span></span></button></div></div><div class="section-body"><ul class="section-list" style="padding:0"></ul></div></section></div><div class="prefs-button"><button class="icon icon-settings" title="Personaliza la tuya pachina de Nueva Pestanya"></button></div></div></main></div></div></div>
+    <div id="root"><div><div class="outer-wrapper fixed-to-top"><main><div class="non-collapsible-section"><div class="search-wrapper"><div class="search-inner-wrapper"><label for="newtab-search-text" class="search-label"><span class="sr-only"><span>Mirar en o Web</span></span></label><input type="search" id="newtab-search-text" maxLength="256" placeholder="Mirar en o Web" title="Mirar en o Web"/><button id="searchSubmit" class="search-button" title="Mirar"><span class="sr-only"><span>Mirar</span></span></button></div></div></div><div class="body-wrapper"><div class="sections-list"><section class="collapsible-section top-sites animation-enabled" data-section-id="topsites"><div class="section-top-bar"><h3 class="section-title"><span class="click-target-container"><span class="click-target"><span class="icon icon-small-spacer icon-topsites"></span><span>Mas freqüents</span></span><span class="click-target"></span><span class="learn-more-link-wrapper"></span></span></h3><div><button class="context-menu-button icon" title="Open menu"><span class="sr-only"><span>Ubrir lo menú contextual d&#x27;a sección</span></span></button></div></div><div class="section-body"><ul class="top-sites-list"><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Editar este puesto"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Editar este puesto"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Editar este puesto"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Editar este puesto"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Editar este puesto"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Editar este puesto"></button></div></li><li class="top-site-outer placeholder hide-for-narrow"><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Editar este puesto"></button></div></li><li class="top-site-outer placeholder hide-for-narrow"><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="Editar este puesto"></button></div></li></ul><div class="edit-topsites-wrapper"></div></div></section><section class="collapsible-section section normal-cards animation-enabled" data-section-id="topstories"><div class="section-top-bar"><h3 class="section-title"><span class="click-target-container"><span class="click-target"><span class="icon icon-small-spacer icon-pocket"></span><span>Recomendau per Pocket</span></span><span class="click-target"></span><span class="learn-more-link-wrapper"></span></span></h3><div><button class="context-menu-button icon" title="Open menu"><span class="sr-only"><span>Ubrir lo menú contextual d&#x27;a sección</span></span></button></div></div><div class="section-body"><ul class="section-list" style="padding:0"></ul><div class="top-stories-bottom-container"><div class="wrapper-more-recommendations"></div></div></div></section><section class="collapsible-section section normal-cards animation-enabled" data-section-id="highlights"><div class="section-top-bar"><h3 class="section-title"><span class="click-target-container"><span class="click-target"><span class="icon icon-small-spacer icon-highlights"></span><span>Destacaus</span></span><span class="click-target"></span><span class="learn-more-link-wrapper"></span></span></h3><div><button class="context-menu-button icon" title="Open menu"><span class="sr-only"><span>Ubrir lo menú contextual d&#x27;a sección</span></span></button></div></div><div class="section-body"><ul class="section-list" style="padding:0"></ul></div></section></div><div class="prefs-button"><button class="icon icon-settings" title="Personaliza la tuya pachina de Nueva Pestanya"></button></div></div></main></div></div></div>
     <div id="snippets-container">
       <div id="snippets"></div>
     </div>
     <script>
 // Don't directly load the following scripts as part of html to let the page
 // finish loading to render the content sooner.
 for (const src of [
   "resource://activity-stream/prerendered/static/activity-stream-initial-state.js",
--- a/browser/components/newtab/prerendered/locales/ar/activity-stream-prerendered-noscripts.html
+++ b/browser/components/newtab/prerendered/locales/ar/activity-stream-prerendered-noscripts.html
@@ -4,14 +4,14 @@
     <meta charset="utf-8">
     <meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'unsafe-inline' resource: chrome:; connect-src https:; img-src https: data: blob:; style-src 'unsafe-inline';">
     <title>لسان جديد</title>
     <link rel="icon" type="image/png" href="chrome://branding/content/icon32.png"/>
     <link rel="stylesheet" href="chrome://browser/content/contentSearchUI.css" />
     <link rel="stylesheet" href="resource://activity-stream/css/activity-stream.css" />
   </head>
   <body class="activity-stream">
-    <div id="root"><div data-reactroot=""><div class="outer-wrapper fixed-to-top"><main><div class="non-collapsible-section"><div class="search-wrapper"><div class="search-inner-wrapper"><label for="newtab-search-text" class="search-label"><span class="sr-only"><span>ابحث في الوِب</span></span></label><input type="search" id="newtab-search-text" maxLength="256" placeholder="ابحث في الوِب" title="ابحث في الوِب"/><button id="searchSubmit" class="search-button" title="ابحث"><span class="sr-only"><span>ابحث</span></span></button></div></div></div><div class="body-wrapper"><div class="sections-list"><section class="collapsible-section top-sites animation-enabled" data-section-id="topsites"><div class="section-top-bar"><h3 class="section-title"><span class="click-target-container"><span class="click-target"><span class="icon icon-small-spacer icon-topsites"></span><span>المواقع الأكثر زيارة</span></span><span class="click-target"></span><span class="learn-more-link-wrapper"></span></span></h3><div><button class="context-menu-button icon" title="افتح القائمة"><span class="sr-only"><span>افتح قائمة القسم السياقية</span></span></button></div></div><div class="section-body"><ul class="top-sites-list"><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="حرّر هذا الموقع"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="حرّر هذا الموقع"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="حرّر هذا الموقع"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="حرّر هذا الموقع"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="حرّر هذا الموقع"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="حرّر هذا الموقع"></button></div></li><li class="top-site-outer placeholder hide-for-narrow"><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="حرّر هذا الموقع"></button></div></li><li class="top-site-outer placeholder hide-for-narrow"><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="حرّر هذا الموقع"></button></div></li></ul><div class="edit-topsites-wrapper"></div></div></section><section class="collapsible-section section normal-cards animation-enabled" data-section-id="topstories"><div class="section-top-bar"><h3 class="section-title"><span class="click-target-container"><span class="click-target"><span class="icon icon-small-spacer icon-pocket"></span><span>ينصح به Pocket</span></span><span class="click-target"></span><span class="learn-more-link-wrapper"></span></span></h3><div><button class="context-menu-button icon" title="افتح القائمة"><span class="sr-only"><span>افتح قائمة القسم السياقية</span></span></button></div></div><div class="section-body"><ul class="section-list" style="padding:0"></ul><div class="top-stories-bottom-container"><div class="wrapper-more-recommendations"></div></div></div></section><section class="collapsible-section section normal-cards animation-enabled" data-section-id="highlights"><div class="section-top-bar"><h3 class="section-title"><span class="click-target-container"><span class="click-target"><span class="icon icon-small-spacer icon-highlights"></span><span>أهم الأحداث</span></span><span class="click-target"></span><span class="learn-more-link-wrapper"></span></span></h3><div><button class="context-menu-button icon" title="افتح القائمة"><span class="sr-only"><span>افتح قائمة القسم السياقية</span></span></button></div></div><div class="section-body"><ul class="section-list" style="padding:0"></ul></div></section></div><div class="prefs-button"><button class="icon icon-settings" title="خصص صفحة اللسان الجديد"></button></div></div></main></div></div></div>
+    <div id="root"><div><div class="outer-wrapper fixed-to-top"><main><div class="non-collapsible-section"><div class="search-wrapper"><div class="search-inner-wrapper"><label for="newtab-search-text" class="search-label"><span class="sr-only"><span>ابحث في الوِب</span></span></label><input type="search" id="newtab-search-text" maxLength="256" placeholder="ابحث في الوِب" title="ابحث في الوِب"/><button id="searchSubmit" class="search-button" title="ابحث"><span class="sr-only"><span>ابحث</span></span></button></div></div></div><div class="body-wrapper"><div class="sections-list"><section class="collapsible-section top-sites animation-enabled" data-section-id="topsites"><div class="section-top-bar"><h3 class="section-title"><span class="click-target-container"><span class="click-target"><span class="icon icon-small-spacer icon-topsites"></span><span>المواقع الأكثر زيارة</span></span><span class="click-target"></span><span class="learn-more-link-wrapper"></span></span></h3><div><button class="context-menu-button icon" title="افتح القائمة"><span class="sr-only"><span>افتح قائمة القسم السياقية</span></span></button></div></div><div class="section-body"><ul class="top-sites-list"><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="حرّر هذا الموقع"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="حرّر هذا الموقع"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="حرّر هذا الموقع"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="حرّر هذا الموقع"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="حرّر هذا الموقع"></button></div></li><li class="top-site-outer placeholder "><div class="top-site-inner"><a tabindex="0" draggable="true"><div class="tile" aria-hidden="true"><div class="screenshot" style="background-image:none"></div></div><div class="title "><span dir="auto"></span></div></a><button class="context-menu-button edit-button icon" title="حرّر هذا الموقع"></button></div></li><li class="top-site-outer placeholder hide-for-narrow"><div class="top-site-inner"><a tabinde